Improve dashboard
This commit is contained in:
@@ -14,12 +14,17 @@ import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.setupActionBarWithNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.nekohasekai.libbox.Libbox
|
||||
import io.nekohasekai.libbox.ProfileContent
|
||||
@@ -38,6 +43,7 @@ import io.nekohasekai.sfa.databinding.ActivityMainBinding
|
||||
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
||||
import io.nekohasekai.sfa.ktx.hasPermission
|
||||
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
||||
import io.nekohasekai.sfa.ui.settings.CoreFragment
|
||||
import io.nekohasekai.sfa.ui.shared.AbstractActivity
|
||||
import io.nekohasekai.sfa.vendor.Vendor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -47,13 +53,15 @@ import java.io.File
|
||||
import java.util.Date
|
||||
import java.util.LinkedList
|
||||
|
||||
class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||
class MainActivity : AbstractActivity(),
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
|
||||
ServiceConnection.Callback {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MainActivity"
|
||||
}
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
internal lateinit var binding: ActivityMainBinding
|
||||
private val connection = ServiceConnection(this, this)
|
||||
|
||||
val logList = LinkedList<String>()
|
||||
@@ -65,9 +73,12 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setSupportActionBar(binding.toolbar)
|
||||
|
||||
val navController = findNavController(R.id.nav_host_fragment_activity_my)
|
||||
navController.setGraph(R.navigation.mobile_navigation)
|
||||
navController.navigate(R.id.navigation_dashboard)
|
||||
navController.addOnDestinationChangedListener(::onDestinationChanged)
|
||||
val appBarConfiguration =
|
||||
AppBarConfiguration(
|
||||
setOf(
|
||||
@@ -86,6 +97,31 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||
onNewIntent(intent)
|
||||
}
|
||||
|
||||
|
||||
private fun onDestinationChanged(
|
||||
navController: NavController,
|
||||
navDestination: NavDestination,
|
||||
bundle: Bundle?
|
||||
) {
|
||||
val destinationId = navDestination.id
|
||||
binding.dashboardTabContainer.isVisible = destinationId == R.id.navigation_dashboard
|
||||
}
|
||||
|
||||
override fun onPreferenceStartFragment(
|
||||
caller: PreferenceFragmentCompat,
|
||||
pref: Preference
|
||||
): Boolean {
|
||||
val navController = findNavController(R.id.nav_host_fragment_activity_my)
|
||||
when (pref.fragment) {
|
||||
CoreFragment::class.java.name -> {
|
||||
navController.navigate(R.id.navigation_settings_core)
|
||||
return true
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
val uri = intent.data ?: return
|
||||
@@ -445,4 +481,5 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
@@ -133,6 +132,8 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
|
||||
lateinit var group: OutboundGroup
|
||||
lateinit var items: MutableList<OutboundGroupItem>
|
||||
lateinit var adapter: ItemAdapter
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun bind(group: OutboundGroup) {
|
||||
this.group = group
|
||||
binding.groupName.text = group.tag
|
||||
@@ -153,10 +154,23 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
|
||||
while (itemIterator.hasNext()) {
|
||||
items.add(itemIterator.next())
|
||||
}
|
||||
adapter = ItemAdapter(this, group, items)
|
||||
binding.itemList.adapter = adapter
|
||||
(binding.itemList.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||
binding.itemList.layoutManager = GridLayoutManager(binding.root.context, 2)
|
||||
if (!::adapter.isInitialized) {
|
||||
adapter = ItemAdapter(this, group, items)
|
||||
binding.itemList.adapter = adapter
|
||||
/* val divider =
|
||||
MaterialDividerItemDecoration(
|
||||
binding.root.context,
|
||||
LinearLayoutManager.VERTICAL
|
||||
)
|
||||
divider.isLastItemDecorated = false
|
||||
binding.itemList.addItemDecoration(divider)*/
|
||||
(binding.itemList.itemAnimator as SimpleItemAnimator).supportsChangeAnimations =
|
||||
false
|
||||
binding.itemList.layoutManager = LinearLayoutManager(binding.root.context)
|
||||
} else {
|
||||
adapter.items = items
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
updateExpand()
|
||||
}
|
||||
|
||||
@@ -220,7 +234,7 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
|
||||
private class ItemAdapter(
|
||||
val groupView: GroupView,
|
||||
val group: OutboundGroup,
|
||||
val items: List<OutboundGroupItem>
|
||||
var items: List<OutboundGroupItem> = emptyList()
|
||||
) :
|
||||
RecyclerView.Adapter<ItemGroupView>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemGroupView {
|
||||
|
||||
@@ -70,42 +70,20 @@ class OverviewFragment : Fragment() {
|
||||
Status.Stopped -> {
|
||||
binding.clashModeCard.isVisible = false
|
||||
binding.systemProxyCard.isVisible = false
|
||||
binding.fab.setImageResource(R.drawable.ic_play_arrow_24)
|
||||
binding.fab.show()
|
||||
}
|
||||
|
||||
Status.Starting -> {
|
||||
binding.fab.hide()
|
||||
}
|
||||
|
||||
Status.Started -> {
|
||||
statusClient.connect()
|
||||
clashModeClient.connect()
|
||||
reloadSystemProxyStatus()
|
||||
binding.fab.setImageResource(R.drawable.ic_stop_24)
|
||||
binding.fab.show()
|
||||
}
|
||||
|
||||
Status.Stopping -> {
|
||||
binding.fab.hide()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
binding.fab.setOnClickListener {
|
||||
when (activity.serviceStatus.value) {
|
||||
Status.Stopped -> {
|
||||
activity.startService()
|
||||
}
|
||||
|
||||
Status.Started -> {
|
||||
BoxService.stop()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
ProfileManager.registerCallback(this::updateProfiles)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.bg.BoxService
|
||||
import io.nekohasekai.sfa.constant.Status
|
||||
import io.nekohasekai.sfa.databinding.FragmentDashboardBinding
|
||||
import io.nekohasekai.sfa.ui.MainActivity
|
||||
@@ -20,6 +21,7 @@ class DashboardFragment : Fragment(R.layout.fragment_dashboard) {
|
||||
|
||||
private val activity: MainActivity? get() = super.getActivity() as MainActivity?
|
||||
private var binding: FragmentDashboardBinding? = null
|
||||
private var mediator: TabLayoutMediator? = null
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
@@ -34,21 +36,46 @@ class DashboardFragment : Fragment(R.layout.fragment_dashboard) {
|
||||
val binding = binding ?: return
|
||||
binding.dashboardPager.adapter = Adapter(this)
|
||||
binding.dashboardPager.offscreenPageLimit = Page.values().size
|
||||
TabLayoutMediator(binding.dashboardTabLayout, binding.dashboardPager) { tab, position ->
|
||||
mediator = TabLayoutMediator(
|
||||
activity.binding.dashboardTabLayout,
|
||||
binding.dashboardPager
|
||||
) { tab, position ->
|
||||
tab.setText(Page.values()[position].titleRes)
|
||||
}.attach()
|
||||
}.apply { attach() }
|
||||
activity.serviceStatus.observe(viewLifecycleOwner) {
|
||||
when (it) {
|
||||
Status.Stopped -> {
|
||||
disablePager()
|
||||
binding.fab.setImageResource(R.drawable.ic_play_arrow_24)
|
||||
binding.fab.show()
|
||||
}
|
||||
|
||||
Status.Starting -> {
|
||||
binding.fab.hide()
|
||||
}
|
||||
|
||||
Status.Started -> {
|
||||
enablePager()
|
||||
binding.fab.setImageResource(R.drawable.ic_stop_24)
|
||||
binding.fab.show()
|
||||
}
|
||||
|
||||
Status.Stopping -> {
|
||||
disablePager()
|
||||
binding.fab.hide()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
binding.fab.setOnClickListener {
|
||||
when (activity.serviceStatus.value) {
|
||||
Status.Stopped -> {
|
||||
activity.startService()
|
||||
}
|
||||
|
||||
Status.Started -> {
|
||||
BoxService.stop()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
@@ -58,18 +85,21 @@ class DashboardFragment : Fragment(R.layout.fragment_dashboard) {
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
mediator?.detach()
|
||||
binding = null
|
||||
}
|
||||
|
||||
private fun enablePager() {
|
||||
val activity = activity ?: return
|
||||
val binding = binding ?: return
|
||||
binding.dashboardTabLayout.isVisible = true
|
||||
activity.binding.dashboardTabLayout.isVisible = true
|
||||
binding.dashboardPager.isUserInputEnabled = true
|
||||
}
|
||||
|
||||
private fun disablePager() {
|
||||
val activity = activity ?: return
|
||||
val binding = binding ?: return
|
||||
binding.dashboardTabLayout.isVisible = false
|
||||
activity.binding.dashboardTabLayout.isVisible = false
|
||||
binding.dashboardPager.isUserInputEnabled = false
|
||||
binding.dashboardPager.setCurrentItem(0, false)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.nekohasekai.sfa.ui.main
|
||||
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.ui.settings.AbstractSettingsFragment
|
||||
|
||||
class SettingsFragment0 : AbstractSettingsFragment(R.xml.preferences_settings) {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.nekohasekai.sfa.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.XmlRes
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.nekohasekai.sfa.R
|
||||
|
||||
open class AbstractSettingsFragment(@XmlRes val resId: Int) : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(resId, rootKey)
|
||||
}
|
||||
|
||||
override fun onCreateRecyclerView(
|
||||
inflater: LayoutInflater,
|
||||
parent: ViewGroup,
|
||||
savedInstanceState: Bundle?
|
||||
): RecyclerView {
|
||||
val recyclerView = inflater
|
||||
.inflate(R.layout.view_prefenence_screen, parent, false) as RecyclerView
|
||||
recyclerView.layoutManager = onCreateLayoutManager()
|
||||
return recyclerView
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.nekohasekai.sfa.ui.settings
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
class CoreFragment : Fragment() {
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package io.nekohasekai.sfa.ui.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import androidx.preference.Preference
|
||||
import io.nekohasekai.sfa.ktx.getAttrColor
|
||||
|
||||
class Preference : Preference {
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||
icon?.setTint(context.getAttrColor(com.google.android.material.R.attr.colorOnSurface))
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : this(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr,
|
||||
0
|
||||
)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(
|
||||
context, attrs, getAttr(
|
||||
context, androidx.preference.R.attr.preferenceStyle,
|
||||
android.R.attr.preferenceStyle
|
||||
)
|
||||
)
|
||||
|
||||
companion object {
|
||||
private fun getAttr(context: Context, attr: Int, fallbackAttr: Int): Int {
|
||||
val value = TypedValue()
|
||||
context.theme.resolveAttribute(attr, value, true)
|
||||
if (value.resourceId != 0) {
|
||||
return attr
|
||||
}
|
||||
return fallbackAttr
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.google.android.material.elevation.SurfaceColors
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.ktx.getAttrColor
|
||||
|
||||
@@ -16,9 +15,10 @@ abstract class AbstractActivity : AppCompatActivity() {
|
||||
|
||||
DynamicColors.applyToActivityIfAvailable(this)
|
||||
|
||||
val color = SurfaceColors.SURFACE_2.getColor(this)
|
||||
window.statusBarColor = color
|
||||
window.navigationBarColor = color
|
||||
val colorSurfaceContainer =
|
||||
getAttrColor(com.google.android.material.R.attr.colorSurfaceContainer)
|
||||
window.statusBarColor = colorSurfaceContainer
|
||||
window.navigationBarColor = colorSurfaceContainer
|
||||
|
||||
supportActionBar?.setHomeAsUpIndicator(AppCompatResources.getDrawable(
|
||||
this@AbstractActivity,
|
||||
|
||||
Reference in New Issue
Block a user