新增:短信指令(根据短信指令开关对应功能) #I5YX3F
parent
dd798e42cc
commit
6571775a0f
@ -1,77 +1,83 @@
|
||||
package com.idormy.sms.forwarder.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.adapter.FrpcPagingAdapter.MyViewHolder
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import com.idormy.sms.forwarder.databinding.AdapterFrpcsCardViewListItemBinding
|
||||
import com.xuexiang.xutil.resource.ResUtils.getColors
|
||||
import frpclib.Frpclib
|
||||
|
||||
class FrpcPagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter<Frpc, MyViewHolder>(diffCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
|
||||
val binding = AdapterFrpcsCardViewListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return MyViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
if (item != null) {
|
||||
holder.binding.ivImage.setImageResource(R.drawable.ic_menu_frpc)
|
||||
holder.binding.ivAutorun.setImageResource(item.autorunImageId)
|
||||
holder.binding.tvName.text = item.name
|
||||
|
||||
if (item.connecting || Frpclib.isRunning(item.uid)) {
|
||||
holder.binding.ivPlay.setImageResource(R.drawable.ic_stop)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
holder.binding.ivPlay.imageTintList = getColors(R.color.colorStop)
|
||||
}
|
||||
} else {
|
||||
holder.binding.ivPlay.setImageResource(R.drawable.ic_start)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
holder.binding.ivPlay.imageTintList = getColors(R.color.colorStart)
|
||||
}
|
||||
}
|
||||
|
||||
holder.binding.ivEdit.setImageResource(R.drawable.ic_edit)
|
||||
holder.binding.ivDelete.setImageResource(R.drawable.ic_delete)
|
||||
|
||||
holder.binding.ivPlay.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
holder.binding.ivEdit.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
holder.binding.ivDelete.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyViewHolder(val binding: AdapterFrpcsCardViewListItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
interface OnItemClickListener {
|
||||
fun onItemClicked(view: View?, item: Frpc)
|
||||
fun onItemRemove(view: View?, id: Int)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var diffCallback: DiffUtil.ItemCallback<Frpc> = object : DiffUtil.ItemCallback<Frpc>() {
|
||||
override fun areItemsTheSame(oldItem: Frpc, newItem: Frpc): Boolean {
|
||||
return oldItem.uid == newItem.uid
|
||||
}
|
||||
|
||||
@SuppressLint("DiffUtilEquals")
|
||||
override fun areContentsTheSame(oldItem: Frpc, newItem: Frpc): Boolean {
|
||||
return oldItem === newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.idormy.sms.forwarder.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.adapter.FrpcPagingAdapter.MyViewHolder
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import com.idormy.sms.forwarder.databinding.AdapterFrpcsCardViewListItemBinding
|
||||
import com.xuexiang.xutil.resource.ResUtils.getColors
|
||||
import frpclib.Frpclib
|
||||
|
||||
class FrpcPagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter<Frpc, MyViewHolder>(diffCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
|
||||
val binding = AdapterFrpcsCardViewListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return MyViewHolder(binding)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
if (item != null) {
|
||||
holder.binding.ivImage.setImageResource(R.drawable.ic_menu_frpc)
|
||||
holder.binding.ivAutorun.setImageResource(item.autorunImageId)
|
||||
holder.binding.tvUid.text = "UID:${item.uid}"
|
||||
holder.binding.tvName.text = item.name
|
||||
|
||||
if (item.connecting || Frpclib.isRunning(item.uid)) {
|
||||
holder.binding.ivPlay.setImageResource(R.drawable.ic_stop)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
holder.binding.ivPlay.imageTintList = getColors(R.color.colorStop)
|
||||
}
|
||||
} else {
|
||||
holder.binding.ivPlay.setImageResource(R.drawable.ic_start)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
holder.binding.ivPlay.imageTintList = getColors(R.color.colorStart)
|
||||
}
|
||||
}
|
||||
|
||||
holder.binding.ivCopy.setImageResource(R.drawable.ic_copy)
|
||||
holder.binding.ivEdit.setImageResource(R.drawable.ic_edit)
|
||||
holder.binding.ivDelete.setImageResource(R.drawable.ic_delete)
|
||||
|
||||
holder.binding.ivCopy.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
holder.binding.ivPlay.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
holder.binding.ivEdit.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
holder.binding.ivDelete.setOnClickListener { view: View? ->
|
||||
itemClickListener.onItemClicked(view, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyViewHolder(val binding: AdapterFrpcsCardViewListItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
interface OnItemClickListener {
|
||||
fun onItemClicked(view: View?, item: Frpc)
|
||||
fun onItemRemove(view: View?, id: Int)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var diffCallback: DiffUtil.ItemCallback<Frpc> = object : DiffUtil.ItemCallback<Frpc>() {
|
||||
override fun areItemsTheSame(oldItem: Frpc, newItem: Frpc): Boolean {
|
||||
return oldItem.uid == newItem.uid
|
||||
}
|
||||
|
||||
@SuppressLint("DiffUtilEquals")
|
||||
override fun areContentsTheSame(oldItem: Frpc, newItem: Frpc): Boolean {
|
||||
return oldItem === newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +1,42 @@
|
||||
package com.idormy.sms.forwarder.database.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.*
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import io.reactivex.Single
|
||||
|
||||
@Dao
|
||||
interface FrpcDao {
|
||||
|
||||
@Insert
|
||||
fun insert(frpc: Frpc)
|
||||
|
||||
@Delete
|
||||
fun delete(frpc: Frpc)
|
||||
|
||||
@Query("DELETE FROM Frpc where uid=:uid")
|
||||
fun delete(uid: String)
|
||||
|
||||
@Update
|
||||
fun update(frpc: Frpc)
|
||||
|
||||
@Query("SELECT * FROM Frpc where uid=:uid")
|
||||
fun get(uid: String): Single<Frpc>
|
||||
|
||||
//TODO:允许主线程访问,后面再优化
|
||||
@Query("SELECT * FROM Frpc where autorun=1")
|
||||
fun getAutorun(): List<Frpc>
|
||||
|
||||
@Query("SELECT * FROM Frpc ORDER BY time DESC")
|
||||
fun pagingSource(): PagingSource<Int, Frpc>
|
||||
|
||||
//TODO:允许主线程访问,后面再优化
|
||||
@Query("SELECT * FROM Frpc ORDER BY time ASC")
|
||||
fun getAll(): List<Frpc>
|
||||
|
||||
@Query("DELETE FROM Frpc")
|
||||
fun deleteAll()
|
||||
package com.idormy.sms.forwarder.database.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.*
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import io.reactivex.Single
|
||||
|
||||
@Dao
|
||||
interface FrpcDao {
|
||||
|
||||
@Insert
|
||||
fun insert(frpc: Frpc)
|
||||
|
||||
@Delete
|
||||
fun delete(frpc: Frpc)
|
||||
|
||||
@Query("DELETE FROM Frpc where uid=:uid")
|
||||
fun delete(uid: String)
|
||||
|
||||
@Update
|
||||
fun update(frpc: Frpc)
|
||||
|
||||
@Query("SELECT * FROM Frpc where uid=:uid")
|
||||
fun get(uid: String): Single<Frpc>
|
||||
|
||||
//TODO:允许主线程访问,后面再优化
|
||||
@Query("SELECT * FROM Frpc where uid=:uid")
|
||||
fun getOne(uid: String): Frpc
|
||||
|
||||
@Query("SELECT * FROM Frpc where autorun=1")
|
||||
fun getAutorun(): List<Frpc>
|
||||
|
||||
@Query("SELECT * FROM Frpc ORDER BY time DESC")
|
||||
fun pagingSource(): PagingSource<Int, Frpc>
|
||||
|
||||
//TODO:允许主线程访问,后面再优化
|
||||
@Query("SELECT * FROM Frpc ORDER BY time ASC")
|
||||
fun getAll(): List<Frpc>
|
||||
|
||||
@Query("DELETE FROM Frpc")
|
||||
fun deleteAll()
|
||||
}
|
@ -1,202 +1,203 @@
|
||||
package com.idormy.sms.forwarder.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
|
||||
import com.alibaba.android.vlayout.VirtualLayoutManager
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.adapter.FrpcPagingAdapter
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
|
||||
import com.idormy.sms.forwarder.database.viewmodel.FrpcViewModel
|
||||
import com.idormy.sms.forwarder.databinding.FragmentFrpcsBinding
|
||||
import com.idormy.sms.forwarder.service.ForegroundService
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||
import com.scwang.smartrefresh.layout.api.RefreshLayout
|
||||
import com.xuexiang.xaop.annotation.SingleClick
|
||||
import com.xuexiang.xpage.annotation.Page
|
||||
import com.xuexiang.xpage.base.XPageActivity
|
||||
import com.xuexiang.xpage.core.PageOption
|
||||
import com.xuexiang.xui.utils.ThemeUtils
|
||||
import com.xuexiang.xui.utils.WidgetUtils
|
||||
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
import com.xuexiang.xui.widget.dialog.LoadingDialog
|
||||
import frpclib.Frpclib
|
||||
import io.reactivex.CompletableObserver
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Page(name = "Frp内网穿透")
|
||||
class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.OnItemClickListener {
|
||||
|
||||
var titleBar: TitleBar? = null
|
||||
private var adapter = FrpcPagingAdapter(this)
|
||||
private val viewModel by viewModels<FrpcViewModel> { BaseViewModelFactory(context) }
|
||||
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentFrpcsBinding {
|
||||
return FragmentFrpcsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false)
|
||||
titleBar!!.setTitle(R.string.menu_frpc)
|
||||
titleBar!!.setActionTextColor(ThemeUtils.resolveColor(context, R.attr.colorAccent))
|
||||
titleBar!!.addAction(object : TitleBar.ImageAction(R.drawable.ic_add) {
|
||||
@SingleClick
|
||||
override fun performAction(view: View) {
|
||||
FrpcUtils.getStringFromRaw(context!!, R.raw.frpc)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<String?> {
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onNext(content: String) {
|
||||
LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(Frpc(content))
|
||||
PageOption.to(FrpcEditFragment::class.java).setNewActivity(true).open((context as XPageActivity?)!!)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
e.message?.let { XToastUtils.error(it) }
|
||||
}
|
||||
|
||||
override fun onComplete() {}
|
||||
})
|
||||
}
|
||||
})
|
||||
return titleBar
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化控件
|
||||
*/
|
||||
override fun initViews() {
|
||||
val virtualLayoutManager = VirtualLayoutManager(requireContext())
|
||||
binding!!.recyclerView.layoutManager = virtualLayoutManager
|
||||
val viewPool = RecycledViewPool()
|
||||
binding!!.recyclerView.setRecycledViewPool(viewPool)
|
||||
viewPool.setMaxRecycledViews(0, 10)
|
||||
|
||||
binding!!.recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
override fun initListeners() {
|
||||
//下拉刷新
|
||||
binding!!.refreshLayout.setOnRefreshListener { refreshLayout: RefreshLayout ->
|
||||
//adapter.refresh()
|
||||
lifecycleScope.launch {
|
||||
viewModel.allFrpc.collectLatest { adapter.submitData(it) }
|
||||
}
|
||||
refreshLayout.finishRefresh()
|
||||
}
|
||||
binding!!.refreshLayout.autoRefresh()
|
||||
|
||||
//更新时间
|
||||
LiveEventBus.get(EVENT_FRPC_UPDATE_CONFIG, Frpc::class.java).observe(this) {
|
||||
adapter.refresh()
|
||||
}
|
||||
|
||||
//删除事件
|
||||
LiveEventBus.get(EVENT_FRPC_DELETE_CONFIG, Frpc::class.java).observe(this) {
|
||||
adapter.refresh()
|
||||
}
|
||||
|
||||
//运行出错时间
|
||||
LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).observe(this) {
|
||||
XToastUtils.error(getString(R.string.frpc_failed_to_run))
|
||||
//FrpcUtils.checkAndStopService(requireContext())
|
||||
adapter.refresh()
|
||||
}
|
||||
|
||||
//运行成功
|
||||
LiveEventBus.get(EVENT_FRPC_RUNNING_SUCCESS, String::class.java).observe(this) {
|
||||
adapter.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClicked(view: View?, item: Frpc) {
|
||||
val id = view?.id
|
||||
if (id == R.id.iv_play) {
|
||||
//if (!FrpcUtils.isServiceRunning(ForegroundService::class.java.name, requireContext())) {
|
||||
if (!ForegroundService.isRunning) {
|
||||
val intent = Intent(requireContext(), ForegroundService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
requireContext().startForegroundService(intent)
|
||||
} else {
|
||||
requireContext().startService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
if (Frpclib.isRunning(item.uid)) {
|
||||
Frpclib.close(item.uid)
|
||||
item.setConnecting(false)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
|
||||
//FrpcUtils.checkAndStopService(requireContext())
|
||||
return
|
||||
}
|
||||
|
||||
FrpcUtils.waitService(ForegroundService::class.java.name, requireContext())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : CompletableObserver {
|
||||
var mLoadingDialog: LoadingDialog = WidgetUtils.getLoadingDialog(context!!).setIconScale(0.4f).setLoadingSpeed(8)
|
||||
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
mLoadingDialog.setLoadingIcon(R.drawable.ic_menu_frpc)
|
||||
mLoadingDialog.updateMessage(R.string.tipWaitService)
|
||||
mLoadingDialog.show()
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
mLoadingDialog.dismiss()
|
||||
mLoadingDialog.recycle()
|
||||
LiveEventBus.get<String>(INTENT_FRPC_APPLY_FILE).postAcrossProcess(item.uid)
|
||||
item.setConnecting(true)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
mLoadingDialog.dismiss()
|
||||
mLoadingDialog.recycle()
|
||||
e.message?.let { XToastUtils.error(it) }
|
||||
item.setConnecting(false)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
//编辑或删除需要先停止客户端
|
||||
if (Frpclib.isRunning(item.uid)) {
|
||||
XToastUtils.warning(R.string.tipServiceRunning)
|
||||
return
|
||||
}
|
||||
if (id == R.id.iv_edit) {
|
||||
LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(item)
|
||||
openNewPage(FrpcEditFragment::class.java)
|
||||
} else if (id == R.id.iv_delete) {
|
||||
try {
|
||||
viewModel.delete(item)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_DELETE_CONFIG).post(item)
|
||||
XToastUtils.success(getString(R.string.successfully_deleted))
|
||||
} catch (e: Exception) {
|
||||
e.message?.let { XToastUtils.error(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemRemove(view: View?, id: Int) {}
|
||||
package com.idormy.sms.forwarder.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
|
||||
import com.alibaba.android.vlayout.VirtualLayoutManager
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.adapter.FrpcPagingAdapter
|
||||
import com.idormy.sms.forwarder.core.BaseFragment
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
|
||||
import com.idormy.sms.forwarder.database.viewmodel.FrpcViewModel
|
||||
import com.idormy.sms.forwarder.databinding.FragmentFrpcsBinding
|
||||
import com.idormy.sms.forwarder.service.ForegroundService
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||
import com.scwang.smartrefresh.layout.api.RefreshLayout
|
||||
import com.xuexiang.xaop.annotation.SingleClick
|
||||
import com.xuexiang.xpage.annotation.Page
|
||||
import com.xuexiang.xpage.base.XPageActivity
|
||||
import com.xuexiang.xpage.core.PageOption
|
||||
import com.xuexiang.xui.utils.ThemeUtils
|
||||
import com.xuexiang.xui.utils.WidgetUtils
|
||||
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||
import com.xuexiang.xui.widget.dialog.LoadingDialog
|
||||
import com.xuexiang.xutil.system.ClipboardUtils
|
||||
import frpclib.Frpclib
|
||||
import io.reactivex.CompletableObserver
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Page(name = "Frp内网穿透")
|
||||
class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.OnItemClickListener {
|
||||
|
||||
var titleBar: TitleBar? = null
|
||||
private var adapter = FrpcPagingAdapter(this)
|
||||
private val viewModel by viewModels<FrpcViewModel> { BaseViewModelFactory(context) }
|
||||
|
||||
override fun viewBindingInflate(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
): FragmentFrpcsBinding {
|
||||
return FragmentFrpcsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun initTitle(): TitleBar? {
|
||||
titleBar = super.initTitle()!!.setImmersive(false)
|
||||
titleBar!!.setTitle(R.string.menu_frpc)
|
||||
titleBar!!.setActionTextColor(ThemeUtils.resolveColor(context, R.attr.colorAccent))
|
||||
titleBar!!.addAction(object : TitleBar.ImageAction(R.drawable.ic_add) {
|
||||
@SingleClick
|
||||
override fun performAction(view: View) {
|
||||
FrpcUtils.getStringFromRaw(context!!, R.raw.frpc).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer<String?> {
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
override fun onNext(content: String) {
|
||||
LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(Frpc(content))
|
||||
PageOption.to(FrpcEditFragment::class.java).setNewActivity(true).open((context as XPageActivity?)!!)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
e.message?.let { XToastUtils.error(it) }
|
||||
}
|
||||
|
||||
override fun onComplete() {}
|
||||
})
|
||||
}
|
||||
})
|
||||
return titleBar
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化控件
|
||||
*/
|
||||
override fun initViews() {
|
||||
val virtualLayoutManager = VirtualLayoutManager(requireContext())
|
||||
binding!!.recyclerView.layoutManager = virtualLayoutManager
|
||||
val viewPool = RecycledViewPool()
|
||||
binding!!.recyclerView.setRecycledViewPool(viewPool)
|
||||
viewPool.setMaxRecycledViews(0, 10)
|
||||
|
||||
binding!!.recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
override fun initListeners() {
|
||||
//下拉刷新
|
||||
binding!!.refreshLayout.setOnRefreshListener { refreshLayout: RefreshLayout ->
|
||||
//adapter.refresh()
|
||||
lifecycleScope.launch {
|
||||
viewModel.allFrpc.collectLatest { adapter.submitData(it) }
|
||||
}
|
||||
refreshLayout.finishRefresh()
|
||||
}
|
||||
binding!!.refreshLayout.autoRefresh()
|
||||
|
||||
//更新时间
|
||||
LiveEventBus.get(EVENT_FRPC_UPDATE_CONFIG, Frpc::class.java).observe(this) {
|
||||
adapter.refresh()
|
||||
}
|
||||
|
||||
//删除事件
|
||||
LiveEventBus.get(EVENT_FRPC_DELETE_CONFIG, Frpc::class.java).observe(this) {
|
||||
adapter.refresh()
|
||||
}
|
||||
|
||||
//运行出错时间
|
||||
LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).observe(this) {
|
||||
XToastUtils.error(getString(R.string.frpc_failed_to_run))
|
||||
adapter.refresh()
|
||||
}
|
||||
|
||||
//运行成功
|
||||
LiveEventBus.get(EVENT_FRPC_RUNNING_SUCCESS, String::class.java).observe(this) {
|
||||
adapter.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClicked(view: View?, item: Frpc) {
|
||||
when (val id = view?.id) {
|
||||
R.id.iv_copy -> {
|
||||
ClipboardUtils.copyText(item.uid)
|
||||
XToastUtils.info(String.format(getString(R.string.copied_to_clipboard), item.uid))
|
||||
}
|
||||
R.id.iv_play -> {
|
||||
if (!ForegroundService.isRunning) {
|
||||
val intent = Intent(requireContext(), ForegroundService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
requireContext().startForegroundService(intent)
|
||||
} else {
|
||||
requireContext().startService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
if (Frpclib.isRunning(item.uid)) {
|
||||
Frpclib.close(item.uid)
|
||||
item.setConnecting(false)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
|
||||
return
|
||||
}
|
||||
|
||||
FrpcUtils.waitService(ForegroundService::class.java.name, requireContext()).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : CompletableObserver {
|
||||
var mLoadingDialog: LoadingDialog = WidgetUtils.getLoadingDialog(context!!).setIconScale(0.4f).setLoadingSpeed(8)
|
||||
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
mLoadingDialog.setLoadingIcon(R.drawable.ic_menu_frpc)
|
||||
mLoadingDialog.updateMessage(R.string.tipWaitService)
|
||||
mLoadingDialog.show()
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
mLoadingDialog.dismiss()
|
||||
mLoadingDialog.recycle()
|
||||
LiveEventBus.get<String>(INTENT_FRPC_APPLY_FILE).postAcrossProcess(item.uid)
|
||||
item.setConnecting(true)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
mLoadingDialog.dismiss()
|
||||
mLoadingDialog.recycle()
|
||||
e.message?.let { XToastUtils.error(it) }
|
||||
item.setConnecting(false)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
else -> {
|
||||
//编辑或删除需要先停止客户端
|
||||
if (Frpclib.isRunning(item.uid)) {
|
||||
XToastUtils.warning(R.string.tipServiceRunning)
|
||||
return
|
||||
}
|
||||
when (id) {
|
||||
R.id.iv_edit -> {
|
||||
LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(item)
|
||||
openNewPage(FrpcEditFragment::class.java)
|
||||
}
|
||||
R.id.iv_delete -> {
|
||||
try {
|
||||
viewModel.delete(item)
|
||||
LiveEventBus.get<Frpc>(EVENT_FRPC_DELETE_CONFIG).post(item)
|
||||
XToastUtils.success(getString(R.string.successfully_deleted))
|
||||
} catch (e: Exception) {
|
||||
e.message?.let { XToastUtils.error(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemRemove(view: View?, id: Int) {}
|
||||
}
|
@ -1,80 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.xuexiang.xui.widget.layout.XUIFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/card_view"
|
||||
style="@style/XUILayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/config_margin_5dp"
|
||||
android:layout_marginTop="@dimen/config_margin_5dp"
|
||||
android:layout_marginEnd="@dimen/config_margin_5dp"
|
||||
android:paddingStart="@dimen/config_padding_5dp"
|
||||
android:paddingTop="@dimen/config_padding_5dp"
|
||||
android:paddingEnd="@dimen/config_padding_5dp"
|
||||
android:paddingBottom="@dimen/config_padding_5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_image"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_autorun"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="-16dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_play"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
android:padding="@dimen/card_view_image_padding"
|
||||
app:tint="@color/colorStart"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_edit"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
android:padding="@dimen/card_view_image_padding"
|
||||
app:tint="@color/toast_info_color"
|
||||
tools:ignore="ContentDescription,PrivateResource" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_delete"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
android:padding="@dimen/card_view_image_padding"
|
||||
app:tint="@color/toast_error_color"
|
||||
tools:ignore="ContentDescription,PrivateResource" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.xuexiang.xui.widget.layout.XUIFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/card_view"
|
||||
style="@style/XUILayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/config_margin_5dp"
|
||||
android:layout_marginTop="@dimen/config_margin_5dp"
|
||||
android:layout_marginEnd="@dimen/config_margin_5dp"
|
||||
android:paddingStart="@dimen/config_padding_5dp"
|
||||
android:paddingTop="@dimen/config_padding_5dp"
|
||||
android:paddingEnd="@dimen/config_padding_5dp"
|
||||
android:paddingBottom="@dimen/config_padding_5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_image"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_autorun"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="-16dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:paddingEnd="15dp"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_play"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
android:padding="@dimen/card_view_image_padding"
|
||||
app:tint="@color/colorStart"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_edit"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
android:padding="@dimen/card_view_image_padding"
|
||||
app:tint="@color/toast_info_color"
|
||||
tools:ignore="ContentDescription,PrivateResource" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_delete"
|
||||
android:layout_width="@dimen/card_view_image_size"
|
||||
android:layout_height="@dimen/card_view_image_size"
|
||||
android:padding="@dimen/card_view_image_padding"
|
||||
app:tint="@color/toast_error_color"
|
||||
tools:ignore="ContentDescription,PrivateResource" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_copy"
|
||||
android:layout_width="@dimen/config_padding_18dp"
|
||||
android:layout_height="@dimen/config_padding_18dp"
|
||||
app:tint="@color/colorStart"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_uid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:lines="1"
|
||||
android:textSize="11sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.xuexiang.xui.widget.layout.XUIFrameLayout>
|
Loading…
Reference in New Issue