/******************************************************************************
* *
* Copyright (C) 2021 by nekohasekai
*
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
******************************************************************************/
package io.nekohasekai.sagernet.ui
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.Toolbar
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayoutMediator
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.aidl.AppStats
import io.nekohasekai.sagernet.databinding.LayoutTrafficBinding
import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.utils.PackageCache
class TrafficFragment : ToolbarFragment(R.layout.layout_traffic),
Toolbar.OnMenuItemClickListener {
lateinit var binding: LayoutTrafficBinding
lateinit var adapter: TrafficAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
toolbar.setTitle(R.string.menu_traffic)
toolbar.inflateMenu(R.menu.traffic_menu)
toolbar.setOnMenuItemClickListener(this)
ViewCompat.setOnApplyWindowInsetsListener(view.findViewById(R.id.traffic_tab)) { v, insets ->
val bars = insets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
)
v.updatePadding(
left = bars.left,
right = bars.right,
)
insets
}
binding = LayoutTrafficBinding.bind(view)
adapter = TrafficAdapter()
binding.trafficPager.adapter = adapter
TabLayoutMediator(binding.trafficTab, binding.trafficPager) { tab, position ->
tab.text = when (position) {
0 -> getString(R.string.traffic_active)
else -> getString(R.string.traffic_stats)
}
tab.view.setOnLongClickListener { // clear toast
true
}
}.attach()
(requireActivity() as MainActivity).connection.trafficTimeout = 1500
(requireActivity() as? MainActivity)?.onBackPressedCallback?.isEnabled = true
}
override fun onMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_clear_traffic_statistics -> {
(requireActivity() as MainActivity).connection.service?.resetTrafficStats()
runOnDefaultDispatcher {
emitStats(emptyList())
}
}
}
return true
}
inner class TrafficAdapter() : FragmentStateAdapter(this) {
override fun getItemCount(): Int {
return 2
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> ActiveFragment()
else -> StatsFragment()
}
}
}
val listeners = mutableListOf<(List) -> Unit>()
fun emitStats(statsList: List) {
runOnDefaultDispatcher {
for (listener in listeners) listener(statsList)
}
}
override fun onStart() {
super.onStart()
(requireActivity() as MainActivity).connection.trafficTimeout = 1500
}
override fun onStop() {
super.onStop()
(requireActivity() as MainActivity).connection.trafficTimeout = 0
}
override fun onDestroy() {
super.onDestroy()
(requireActivity() as MainActivity).connection.trafficTimeout = 0
}
val createRule = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
(requireActivity() as MainActivity).ruleCreated()
}
}
inner class ItemMenuListener(val stats: AppStats, val packageName: String?) : PopupMenu.OnMenuItemClickListener {
override fun onMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) {
R.id.copy_label -> {
packageName?.let {
PackageCache.awaitLoadSync()
val success = SagerNet.trySetPrimaryClip(PackageCache.loadLabel(it))
snackbar(if (success) R.string.copy_success else R.string.copy_failed).show()
}
}
R.id.copy_package_name -> {
packageName?.let {
val success = SagerNet.trySetPrimaryClip(it)
snackbar(if (success) R.string.copy_success else R.string.copy_failed).show()
}
}
R.id.create_rule -> {
packageName?.let {
createRule.launch(Intent(
requireContext(), RouteSettingsActivity::class.java
).apply {
putExtra(RouteSettingsActivity.EXTRA_PACKAGE_NAME, it)
})
}
}
}
return true
}
}
}