Commit 3b05935f authored by Max Lv's avatar Max Lv

Refine importing subscription

parent a080085d
...@@ -54,6 +54,27 @@ object ProfileManager { ...@@ -54,6 +54,27 @@ object ProfileManager {
return profile return profile
} }
fun createProfilesFromSubscription(jsons: Sequence<InputStream>, replace: Boolean,
oldProfiles: List<Profile>?) {
val profiles = oldProfiles?.associateBy { it.formattedAddress }
val feature = profiles?.values?.singleOrNull { it.id == DataStore.profileId }
val lazyClear = lazy { clear() }
jsons.asIterable().forEachTry { json ->
Profile.parseJson(JsonStreamParser(json.bufferedReader()).asSequence().single(), feature) {
if (replace) {
lazyClear.value
}
// if two profiles has the same address, treat them as the same profile and copy stats over
profiles?.get(it.formattedAddress)?.apply {
it.tx = tx
it.rx = rx
}
createProfile(it)
}
}
}
fun createProfilesFromJson(jsons: Sequence<InputStream>, replace: Boolean = false) { fun createProfilesFromJson(jsons: Sequence<InputStream>, replace: Boolean = false) {
val profiles = if (replace) getAllProfiles()?.associateBy { it.formattedAddress } else null val profiles = if (replace) getAllProfiles()?.associateBy { it.formattedAddress } else null
val feature = if (replace) { val feature = if (replace) {
...@@ -74,6 +95,7 @@ object ProfileManager { ...@@ -74,6 +95,7 @@ object ProfileManager {
} }
} }
} }
fun serializeToJson(profiles: List<Profile>? = getAllProfiles()): JSONArray? { fun serializeToJson(profiles: List<Profile>? = getAllProfiles()): JSONArray? {
if (profiles == null) return null if (profiles == null) return null
val lookup = LongSparseArray<Profile>(profiles.size).apply { profiles.forEach { put(it.id, it) } } val lookup = LongSparseArray<Profile>(profiles.size).apply { profiles.forEach { put(it.id, it) } }
......
...@@ -58,14 +58,11 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar ...@@ -58,14 +58,11 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
import java.util.*
class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
companion object { companion object {
private const val REQUEST_CODE_ADD = 1 private const val REQUEST_CODE_ADD = 1
private const val REQUEST_CODE_EDIT = 2 private const val REQUEST_CODE_EDIT = 2
private const val SELECTED_URLS = "com.github.shadowsocks.acl.subscription.SELECTED_URLS"
} }
@Parcelize @Parcelize
...@@ -135,34 +132,25 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener ...@@ -135,34 +132,25 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
} }
private inner class SubViewHolder(view: View) : RecyclerView.ViewHolder(view), private inner class SubViewHolder(view: View) : RecyclerView.ViewHolder(view),
View.OnClickListener, View.OnLongClickListener { View.OnClickListener {
lateinit var item: URL lateinit var item: URL
private val text = view.findViewById<TextView>(android.R.id.text1) private val text = view.findViewById<TextView>(android.R.id.text1)
init { init {
view.isFocusable = true view.isFocusable = true
view.setOnClickListener(this) view.setOnClickListener(this)
view.setOnLongClickListener(this)
view.setBackgroundResource(R.drawable.background_selectable) view.setBackgroundResource(R.drawable.background_selectable)
} }
fun bind(url: URL) { fun bind(url: URL) {
item = url item = url
text.text = url.toString() text.text = url.toString()
itemView.isSelected = selectedItems.contains(url)
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
if (selectedItems.isNotEmpty()) onLongClick(v) SubDialogFragment().withArg(SubItem(item.toString()))
else SubDialogFragment().withArg(SubItem(item.toString()))
.show(this@SubscriptionFragment, REQUEST_CODE_EDIT) .show(this@SubscriptionFragment, REQUEST_CODE_EDIT)
} }
override fun onLongClick(v: View?): Boolean {
if (!selectedItems.add(item)) selectedItems.remove(item) // toggle
itemView.isSelected = !itemView.isSelected
return true
}
} }
private inner class SubscriptionAdapter : RecyclerView.Adapter<SubViewHolder>() { private inner class SubscriptionAdapter : RecyclerView.Adapter<SubViewHolder>() {
...@@ -227,7 +215,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener ...@@ -227,7 +215,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
private val isEnabled get() = (activity as MainActivity).state == BaseService.State.Stopped private val isEnabled get() = (activity as MainActivity).state == BaseService.State.Stopped
private val selectedItems = HashSet<Any>()
private val adapter by lazy { SubscriptionAdapter() } private val adapter by lazy { SubscriptionAdapter() }
private lateinit var list: RecyclerView private lateinit var list: RecyclerView
private lateinit var progress: MaterialProgressBar private lateinit var progress: MaterialProgressBar
...@@ -242,15 +229,19 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener ...@@ -242,15 +229,19 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
fetchJob = GlobalScope.launch { fetchJob = GlobalScope.launch {
val subscription = Subscription.instance val subscription = Subscription.instance
val oldProfiles = ProfileManager.getAllProfiles()
var replace = true
for (url in subscription.urls.asIterable()) { for (url in subscription.urls.asIterable()) {
try { try {
val connection = url.openConnection() as HttpURLConnection val connection = url.openConnection() as HttpURLConnection
ProfileManager.createProfilesFromJson(sequenceOf(connection.inputStream), replace = true) ProfileManager.createProfilesFromSubscription(sequenceOf(connection.inputStream),
replace, oldProfiles)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
activity.snackbar(e.readableMessage).show() activity.snackbar(e.readableMessage).show()
} finally {
replace = false
} }
} }
...@@ -267,10 +258,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener ...@@ -267,10 +258,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
view.setOnApplyWindowInsetsListener(ListHolderListener) view.setOnApplyWindowInsetsListener(ListHolderListener)
if (savedInstanceState != null) {
selectedItems.addAll(savedInstanceState.getStringArray(SELECTED_URLS)?.map { URL(it) }
?: listOf())
}
toolbar.setTitle(R.string.subscriptions) toolbar.setTitle(R.string.subscriptions)
toolbar.inflateMenu(R.menu.subscription_menu) toolbar.inflateMenu(R.menu.subscription_menu)
toolbar.setOnMenuItemClickListener(this) toolbar.setOnMenuItemClickListener(this)
...@@ -285,7 +272,7 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener ...@@ -285,7 +272,7 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
undoManager = UndoSnackbarManager(activity, adapter::undo) undoManager = UndoSnackbarManager(activity, adapter::undo)
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.START or ItemTouchHelper.END) { ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.START or ItemTouchHelper.END) {
override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int = override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int =
if (isEnabled && selectedItems.isEmpty()) super.getSwipeDirs(recyclerView, viewHolder) else 0 if (isEnabled) super.getSwipeDirs(recyclerView, viewHolder) else 0
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) =
adapter.remove(viewHolder.adapterPosition) adapter.remove(viewHolder.adapterPosition)
...@@ -303,11 +290,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener ...@@ -303,11 +290,6 @@ class SubscriptionFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener
} else super.onBackPressed() } else super.onBackPressed()
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putStringArray(SELECTED_URLS, selectedItems.filterIsInstance<URL>().map(URL::toString).toTypedArray())
}
override fun onMenuItemClick(item: MenuItem): Boolean = when (item.itemId) { override fun onMenuItemClick(item: MenuItem): Boolean = when (item.itemId) {
R.id.action_manual_settings -> { R.id.action_manual_settings -> {
SubDialogFragment().withArg(SubItem()).show(this, REQUEST_CODE_ADD) SubDialogFragment().withArg(SubItem()).show(this, REQUEST_CODE_ADD)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment