新增:自动任务·快捷指令 (开发中)

This commit is contained in:
pppscn 2023-12-22 22:46:29 +08:00
parent be36ada07f
commit 28f24ef73b
74 changed files with 1350 additions and 1014 deletions

View File

@ -0,0 +1,49 @@
package com.idormy.sms.forwarder.adapter.spinner
import android.graphics.drawable.Drawable
@Suppress("unused")
class FrpcAdapterItem(
var title: CharSequence,
var icon: Drawable? = null,
var uid: String = "",
var autorun: Int? = 1
) {
fun setTitle(title: CharSequence): FrpcAdapterItem {
this.title = title
return this
}
fun setIcon(icon: Drawable?): FrpcAdapterItem {
this.icon = icon
return this
}
fun setUid(uid: String): FrpcAdapterItem {
this.uid = uid
return this
}
fun setAutorun(autorun: Int): FrpcAdapterItem {
this.autorun = autorun
return this
}
// 注意:自定义实体需要重写对象的 toString 方法
override fun toString(): String {
return title.toString()
}
companion object {
@JvmStatic
fun of(title: CharSequence): FrpcAdapterItem {
return FrpcAdapterItem(title)
}
@JvmStatic
fun arrayOf(vararg titles: CharSequence): Array<FrpcAdapterItem> {
return titles.map { FrpcAdapterItem(it) }.toTypedArray()
}
}
}

View File

@ -0,0 +1,167 @@
package com.idormy.sms.forwarder.adapter.spinner
import android.annotation.SuppressLint
import android.os.Build
import android.text.Html
import android.text.TextUtils
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.STATUS_ON
import com.xuexiang.xui.utils.CollectionUtils
import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter
import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter
import com.xuexiang.xutil.resource.ResUtils.getDrawable
@Suppress("unused", "NAME_SHADOWING", "DEPRECATION")
class FrpcSpinnerAdapter<T> : BaseEditSpinnerAdapter<T>, EditSpinnerFilter {
/**
* 选项的文字颜色
*/
private var mTextColor = 0
/**
* 选项的文字大小
*/
private var mTextSize = 0f
/**
* 背景颜色
*/
private var mBackgroundSelector = 0
/**
* 过滤关键词的选中颜色
*/
private var mFilterColor = "#F15C58"
private var mIsFilterKey = false
/**
* 构造方法
*
* @param data 选项数据
*/
constructor(data: List<T>?) : super(data)
/**
* 构造方法
*
* @param data 选项数据
*/
constructor(data: Array<T>?) : super(data)
override fun getEditSpinnerFilter(): EditSpinnerFilter {
return this
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
var convertView = convertView
val holder: ViewHolder
if (convertView == null) {
convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false)
holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector)
convertView.tag = holder
} else {
holder = convertView.tag as ViewHolder
}
val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as FrpcAdapterItem
holder.iconView.setImageDrawable(item.icon)
holder.statusView.setImageDrawable(
getDrawable(
when (item.autorun) {
STATUS_ON -> R.drawable.ic_autorun
else -> R.drawable.ic_manual
}
)
)
//holder.titleView.text = Html.fromHtml(item.toString())
holder.titleView.text = Html.fromHtml(getItem(position))
return convertView
}
override fun onFilter(keyword: String): Boolean {
mDisplayData.clear()
Log.d("FrpcSpinnerAdapter", "keyword = $keyword")
Log.d("FrpcSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}")
if (TextUtils.isEmpty(keyword)) {
initDisplayData(mDataSource)
for (i in mIndexs.indices) {
mIndexs[i] = i
}
} else {
try {
for (i in mDataSource.indices) {
if (getDataSourceString(i).contains(keyword, ignoreCase = true)) {
mIndexs[mDisplayData.size] = i
if (mIsFilterKey) {
mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "<font color=\"$mFilterColor\">$keyword</font>"))
} else {
mDisplayData.add(getDataSourceString(i))
}
}
}
} catch (e: Exception) {
e.printStackTrace()
Log.e("FrpcSpinnerAdapter", "onFilter error: ${e.message}")
}
}
Log.d("FrpcSpinnerAdapter", "mDisplayData = $mDisplayData")
notifyDataSetChanged()
return mDisplayData.size > 0
}
fun setTextColor(@ColorInt textColor: Int): FrpcSpinnerAdapter<*> {
mTextColor = textColor
return this
}
fun setTextSize(textSize: Float): FrpcSpinnerAdapter<*> {
mTextSize = textSize
return this
}
fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): FrpcSpinnerAdapter<*> {
mBackgroundSelector = backgroundSelector
return this
}
fun setFilterColor(filterColor: String): FrpcSpinnerAdapter<*> {
mFilterColor = filterColor
return this
}
fun setIsFilterKey(isFilterKey: Boolean): FrpcSpinnerAdapter<*> {
mIsFilterKey = isFilterKey
return this
}
@SuppressLint("ObsoleteSdkInt")
private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) {
val iconView: ImageView = convertView.findViewById(R.id.iv_icon)
val statusView: ImageView = convertView.findViewById(R.id.iv_status)
val titleView: TextView = convertView.findViewById(R.id.tv_title)
init {
if (textColor > 0) titleView.setTextColor(textColor)
if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
val config = convertView.resources.configuration
if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
titleView.textDirection = View.TEXT_DIRECTION_RTL
}
}
}
}
fun getItemSource(position: Int): T {
return mDataSource[mIndexs[position]]
}
}

View File

@ -36,10 +36,12 @@ class RuleAdapterItem(
}
companion object {
@JvmStatic
fun of(title: CharSequence): RuleAdapterItem {
return RuleAdapterItem(title)
}
@JvmStatic
fun arrayOf(vararg titles: CharSequence): Array<RuleAdapterItem> {
return titles.map { RuleAdapterItem(it) }.toTypedArray()
}

View File

@ -24,6 +24,9 @@ interface FrpcDao {
@Query("DELETE FROM Frpc where uid=:uid")
fun delete(uid: String)
@Query("DELETE FROM Frpc")
fun deleteAll()
@Update
fun update(frpc: Frpc)
@ -43,10 +46,11 @@ interface FrpcDao {
@Query("SELECT * FROM Frpc ORDER BY time DESC")
fun pagingSource(): PagingSource<Int, Frpc>
@Query("SELECT * FROM Frpc ORDER BY time DESC")
fun getAll(): Single<List<Frpc>>
@Transaction
@RawQuery(observedEntities = [Frpc::class])
fun getAllRaw(query: SupportSQLiteQuery): List<Frpc>
@Query("DELETE FROM Frpc")
fun deleteAll()
}

View File

@ -34,6 +34,16 @@ interface LogsDao {
@Update
fun update(logs: Logs): Completable
@Query(
"UPDATE Logs SET forward_status=:status" +
",forward_response=CASE WHEN (trim(forward_response) = '' or trim(forward_response) = 'ok')" +
" THEN :response" +
" ELSE forward_response || '\n--------------------\n' || :response" +
" END" +
" where id=:id"
)
fun updateStatus(id: Long, status: Int, response: String): Int
@Query("SELECT * FROM Logs where id=:id")
fun get(id: Long): Single<Logs>
@ -48,13 +58,4 @@ interface LogsDao {
@Query("SELECT * FROM Logs WHERE type = :type ORDER BY id DESC")
fun pagingSource(type: String): PagingSource<Int, LogsAndRuleAndSender>
@Query(
"UPDATE Logs SET forward_status=:status" +
",forward_response=CASE WHEN (trim(forward_response) = '' or trim(forward_response) = 'ok')" +
" THEN :response" +
" ELSE forward_response || '\n--------------------\n' || :response" +
" END" +
" where id=:id"
)
fun updateStatus(id: Long, status: Int, response: String): Int
}

View File

@ -31,6 +31,9 @@ interface RuleDao {
@Update
fun update(rule: Rule)
@Query("UPDATE Rule SET status=:status WHERE id IN (:ids)")
fun updateStatusByIds(ids: List<Long>, status: Int)
@Query("SELECT * FROM Rule where id=:id")
fun get(id: Long): Single<Rule>
@ -54,4 +57,5 @@ interface RuleDao {
@Query("SELECT * FROM Rule ORDER BY id DESC")
fun getAll(): Single<List<Rule>>
}

View File

@ -26,9 +26,15 @@ interface SenderDao {
@Query("DELETE FROM Sender where id=:id")
fun delete(id: Long)
@Query("DELETE FROM Sender")
fun deleteAll()
@Update
fun update(sender: Sender)
@Query("UPDATE Sender SET status=:status WHERE id IN (:ids)")
fun updateStatusByIds(ids: List<Long>, status: Int)
@Query("SELECT * FROM Sender where id=:id")
fun get(id: Long): Single<Sender>
@ -54,6 +60,4 @@ interface SenderDao {
@Query("SELECT COUNT(id) FROM Sender WHERE status = 1")
fun getOnCount(): Flow<Long>
@Query("DELETE FROM Sender")
fun deleteAll()
}

View File

@ -3,6 +3,7 @@ package com.idormy.sms.forwarder.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Transaction
@ -15,6 +16,24 @@ import java.util.Date
@Dao
interface TaskDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(task: Task): Long
@Query("DELETE FROM Task WHERE id = :taskId")
fun delete(taskId: Long)
@Query("DELETE FROM Task")
fun deleteAll()
@Update
fun update(task: Task)
@Query("UPDATE Task SET last_exec_time = :lastExecTime, next_exec_time = :nextExecTime, status = :status WHERE id = :taskId")
fun updateExecTime(taskId: Long, lastExecTime: Date, nextExecTime: Date, status: Int)
@Query("UPDATE Task SET status = :status WHERE id = :id")
fun updateStatus(id: Long, status: Int)
@Query("SELECT * FROM Task where id=:id")
fun get(id: Long): Single<Task>
@ -34,22 +53,4 @@ interface TaskDao {
@Query("SELECT * FROM Task WHERE status = 1 AND type = :taskType")
fun getByType(taskType: Int): List<Task>
@Insert
fun insert(task: Task)
@Update
fun update(task: Task)
@Query("UPDATE Task SET last_exec_time = :lastExecTime, next_exec_time = :nextExecTime, status = :status WHERE id = :taskId")
fun updateExecTime(taskId: Long, lastExecTime: Date, nextExecTime: Date, status: Int)
@Query("DELETE FROM Task WHERE id = :taskId")
fun delete(taskId: Long)
@Query("DELETE FROM Task")
fun deleteAll()
@Query("UPDATE Task SET status = :status WHERE id = :id")
fun updateStatus(id: Long, status: Int)
}

View File

@ -22,6 +22,9 @@ data class Frpc(
@Ignore var connecting: Boolean = false,
) : Parcelable {
val imageId: Int
get() = R.drawable.ic_menu_frpc
val autorunImageId: Int
get() = when (autorun) {
STATUS_ON -> R.drawable.ic_autorun

View File

@ -4,34 +4,33 @@ import androidx.annotation.WorkerThread
import androidx.sqlite.db.SimpleSQLiteQuery
import com.idormy.sms.forwarder.database.dao.FrpcDao
import com.idormy.sms.forwarder.database.entity.Frpc
import io.reactivex.Single
class FrpcRepository(
private val frpcDao: FrpcDao,
) {
class FrpcRepository(private val frpcDao: FrpcDao) {
@WorkerThread
fun insert(frpc: Frpc) {
frpcDao.insert(frpc)
}
fun insert(frpc: Frpc) = frpcDao.insert(frpc)
@WorkerThread
fun delete(uid: String) {
frpcDao.delete(uid)
}
fun delete(uid: String) = frpcDao.delete(uid)
@WorkerThread
fun get(uid: String) = frpcDao.get(uid)
fun deleteAll() = frpcDao.deleteAll()
@WorkerThread
fun update(frpc: Frpc) = frpcDao.update(frpc)
@WorkerThread
fun get(uid: String) = frpcDao.get(uid)
fun getAllNonCache(): List<Frpc> {
val query = SimpleSQLiteQuery("SELECT * FROM Frpc ORDER BY time DESC")
return frpcDao.getAllRaw(query)
}
fun deleteAll() {
frpcDao.deleteAll()
}
fun getAll(): Single<List<Frpc>> = frpcDao.getAll()
fun getAutorun(): List<Frpc> = frpcDao.getAutorun()
fun getByUids(uids: List<String>): List<Frpc> = frpcDao.getByUids(uids)
}

View File

@ -6,26 +6,17 @@ import com.idormy.sms.forwarder.database.entity.Logs
class LogsRepository(private val logsDao: LogsDao) {
@WorkerThread
fun delete(id: Long) {
logsDao.delete(id)
}
//@WorkerThread
//fun deleteTimeAgo(time: Long) {
// logsDao.deleteTimeAgo(time)
//}
@WorkerThread
suspend fun insert(logs: Logs): Long = logsDao.insert(logs)
@WorkerThread
fun updateStatus(id: Long, status: Int, response: String): Int =
logsDao.updateStatus(id, status, response)
fun delete(id: Long) = logsDao.delete(id)
fun deleteAll() = logsDao.deleteAll()
@WorkerThread
fun updateStatus(id: Long, status: Int, response: String): Int = logsDao.updateStatus(id, status, response)
fun getOne(id: Long) = logsDao.getOne(id)
fun deleteAll() {
logsDao.deleteAll()
}
}

View File

@ -6,21 +6,17 @@ import com.idormy.sms.forwarder.database.entity.Msg
class MsgRepository(private val msgDao: MsgDao) {
@WorkerThread
fun delete(id: Long) {
msgDao.delete(id)
}
@WorkerThread
fun deleteTimeAgo(time: Long) {
msgDao.deleteTimeAgo(time)
}
@WorkerThread
suspend fun insert(msg: Msg): Long = msgDao.insert(msg)
fun deleteAll() {
msgDao.deleteAll()
}
@WorkerThread
fun delete(id: Long) = msgDao.delete(id)
fun deleteAll() = msgDao.deleteAll()
fun deleteAll(type: String) = msgDao.deleteAll(type)
@WorkerThread
fun deleteTimeAgo(time: Long) = msgDao.deleteTimeAgo(time)
}

View File

@ -4,17 +4,14 @@ import androidx.annotation.WorkerThread
import androidx.sqlite.db.SimpleSQLiteQuery
import com.idormy.sms.forwarder.database.dao.RuleDao
import com.idormy.sms.forwarder.database.entity.Rule
import io.reactivex.Single
class RuleRepository(
private val ruleDao: RuleDao,
) {
class RuleRepository(private val ruleDao: RuleDao) {
private var listener: Listener? = null
@WorkerThread
fun insert(rule: Rule) {
ruleDao.insert(rule)
}
fun insert(rule: Rule) = ruleDao.insert(rule)
@WorkerThread
fun delete(id: Long) {
@ -22,23 +19,26 @@ class RuleRepository(
ruleDao.delete(id)
}
fun deleteAll() = ruleDao.deleteAll()
@WorkerThread
fun update(rule: Rule) = ruleDao.update(rule)
fun updateStatusByIds(ids: List<Long>, status: Int) = ruleDao.updateStatusByIds(ids, status)
@WorkerThread
fun get(id: Long) = ruleDao.get(id)
@WorkerThread
fun getOne(id: Long) = ruleDao.getOne(id)
fun getRuleList(type: String, status: Int, simSlot: String) = ruleDao.getRuleList(type, status, simSlot)
@WorkerThread
fun update(rule: Rule) = ruleDao.update(rule)
fun getAll(): Single<List<Rule>> = ruleDao.getAll()
fun getAllNonCache(): List<Rule> {
val query = SimpleSQLiteQuery("SELECT * FROM Rule ORDER BY id ASC")
return ruleDao.getAllRaw(query)
}
fun deleteAll() {
ruleDao.deleteAll()
}
fun getRuleList(type: String, status: Int, simSlot: String) = ruleDao.getRuleList(type, status, simSlot)
}

View File

@ -4,6 +4,7 @@ import androidx.annotation.WorkerThread
import androidx.sqlite.db.SimpleSQLiteQuery
import com.idormy.sms.forwarder.database.dao.SenderDao
import com.idormy.sms.forwarder.database.entity.Sender
import io.reactivex.Single
import kotlinx.coroutines.flow.Flow
class SenderRepository(private val senderDao: SenderDao) {
@ -19,22 +20,25 @@ class SenderRepository(private val senderDao: SenderDao) {
senderDao.delete(id)
}
fun deleteAll() = senderDao.deleteAll()
fun update(sender: Sender) = senderDao.update(sender)
fun updateStatusByIds(ids: List<Long>, status: Int) = senderDao.updateStatusByIds(ids, status)
fun get(id: Long) = senderDao.get(id)
fun getOne(id: Long) = senderDao.getOne(id)
fun getByIds(ids: List<Long>) = senderDao.getByIds(ids)
fun update(sender: Sender) = senderDao.update(sender)
fun getAllNonCache(): List<Sender> {
val query = SimpleSQLiteQuery("SELECT * FROM Sender ORDER BY id ASC")
return senderDao.getAllRaw(query)
}
fun getAll(): Single<List<Sender>> = senderDao.getAll()
val count: Flow<Long> = senderDao.getOnCount()
fun deleteAll() {
senderDao.deleteAll()
}
}

View File

@ -4,27 +4,31 @@ import androidx.annotation.WorkerThread
import androidx.sqlite.db.SimpleSQLiteQuery
import com.idormy.sms.forwarder.database.dao.TaskDao
import com.idormy.sms.forwarder.database.entity.Task
import java.util.Date
class TaskRepository(private val taskDao: TaskDao) {
@WorkerThread
fun insert(task: Task) = taskDao.insert(task)
fun insert(task: Task): Long = taskDao.insert(task)
suspend fun getOne(id: Long) = taskDao.getOne(id)
@WorkerThread
fun delete(id: Long) = taskDao.delete(id)
fun deleteAll() = taskDao.deleteAll()
fun update(task: Task) = taskDao.update(task)
fun updateExecTime(taskId: Long, lastExecTime: Date, nextExecTime: Date, status: Int) = taskDao.updateExecTime(taskId, lastExecTime, nextExecTime, status)
fun get(id: Long) = taskDao.get(id)
suspend fun getOne(id: Long) = taskDao.getOne(id)
fun getAllNonCache(): List<Task> {
val query = SimpleSQLiteQuery("SELECT * FROM Task ORDER BY id ASC")
return taskDao.getAllRaw(query)
}
@WorkerThread
fun delete(id: Long) {
taskDao.delete(id)
}
fun getByType(type: Int): List<Task> = taskDao.getByType(type)
fun deleteAll() {
taskDao.deleteAll()
}
}

View File

@ -26,7 +26,7 @@ class TaskViewModel(private val dao: TaskDao) : ViewModel() {
initialLoadSize = 10
)
) {
//TODO:根据条件查询,不使用
//TODO:根据条件查询,不使用
//dao.pagingSource(type)
if (type == "mine") dao.pagingSourceMine() else dao.pagingSourceFixed()
}.flow.cachedIn(viewModelScope)

View File

@ -5,6 +5,6 @@ import java.io.Serializable
data class RuleSetting(
var description: String = "", //描述
var status: String = "enable", //状态: enable=启用disable=禁
var status: Int = 1, //状态0-禁用1-启
var ruleList: List<Rule>, //转发规则列表
) : Serializable

View File

@ -5,6 +5,6 @@ import java.io.Serializable
data class SenderSetting(
var description: String = "", //描述
var status: String = "enable", //状态: enable=启用disable=禁
var status: Int = 1, //状态0-禁用1-启
var senderList: List<Sender>, //发送通道列表
) : Serializable

View File

@ -13,7 +13,7 @@ import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.activity.MainActivity
import com.idormy.sms.forwarder.adapter.MsgPagingAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.LogsDetail
import com.idormy.sms.forwarder.database.entity.MsgAndLogs
import com.idormy.sms.forwarder.database.entity.Rule
@ -78,9 +78,7 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
AppDatabase.getInstance(requireContext())
.msgDao()
.deleteAll(currentType)
Core.msg.deleteAll(currentType)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CompletableObserver {

View File

@ -16,7 +16,7 @@ import com.idormy.sms.forwarder.adapter.spinner.AppListSpinnerAdapter
import com.idormy.sms.forwarder.adapter.spinner.SenderAdapterItem
import com.idormy.sms.forwarder.adapter.spinner.SenderSpinnerAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Rule
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
@ -405,7 +405,7 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
//免打扰(禁用转发)时间段
binding!!.tvSilentPeriod.text = mTimeOption[silentPeriodStart] + " ~ " + mTimeOption[silentPeriodEnd]
AppDatabase.getInstance(requireContext()).senderDao().getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Sender>> {
Core.sender.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Sender>> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
@ -568,7 +568,7 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
//初始化表单
private fun initForm() {
AppDatabase.getInstance(requireContext()).ruleDao().get(ruleId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Rule> {
Core.rule.get(ruleId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Rule> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {

View File

@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -18,10 +17,8 @@ import com.idormy.sms.forwarder.adapter.ItemMoveCallback
import com.idormy.sms.forwarder.adapter.TaskSettingAdapter
import com.idormy.sms.forwarder.adapter.WidgetItemAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Task
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.TaskViewModel
import com.idormy.sms.forwarder.databinding.FragmentTasksEditBinding
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.condition.CronSetting
@ -59,7 +56,6 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
private val TAG: String = TasksEditFragment::class.java.simpleName
private val that = this
private var titleBar: TitleBar? = null
private val viewModel by viewModels<TaskViewModel> { BaseViewModelFactory(context) }
private val dialog: BottomSheetDialog by lazy { BottomSheetDialog(requireContext()) }
@JvmField
@ -345,10 +341,14 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
val taskNew = checkForm()
if (isClone) taskNew.id = 0
Log.d(TAG, taskNew.toString())
//保存任务
if (taskNew.id > 0) {
Core.task.update(taskNew)
} else {
taskNew.id = Core.task.insert(taskNew)
}
//应用任务
applyTask(taskNew)
//保存任务
viewModel.insertOrUpdate(taskNew)
XToastUtils.success(R.string.tipSaveSuccess)
popToBack()
return
@ -363,7 +363,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
//初始化表单
private fun initForm() {
AppDatabase.getInstance(requireContext()).taskDao().get(taskId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Task> {
Core.task.get(taskId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Task> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
@ -464,6 +464,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
when (task.type) {
//定时任务
TASK_CONDITION_CRON -> {
if (task.id <= 0) return
//取消旧任务的定时器 & 设置新的定时器
CronJobScheduler.cancelTask(task.id)
CronJobScheduler.scheduleTask(task)
@ -490,7 +491,7 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
//必须开启定位服务,才能使用进入地点 或 离开地点 类型条件
if ((typeCondition == TASK_CONDITION_TO_ADDRESS || typeCondition == TASK_CONDITION_LEAVE_ADDRESS) && !App.LocationClient.isStarted()) {
MaterialDialog.Builder(requireContext())
.iconRes(R.drawable.icon_location)
.iconRes(R.drawable.auto_task_icon_location)
.title(R.string.enable_location)
.content(R.string.enable_location_dialog)
.cancelable(false)

View File

@ -5,9 +5,17 @@ import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.spinner.FrpcAdapterItem
import com.idormy.sms.forwarder.adapter.spinner.FrpcSpinnerAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Frpc
import com.idormy.sms.forwarder.databinding.FragmentTasksActionFrpcBinding
import com.idormy.sms.forwarder.entity.action.FrpcSetting
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
@ -15,6 +23,7 @@ import com.idormy.sms.forwarder.utils.KEY_BACK_DESCRIPTION_ACTION
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_TEST_ACTION
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.STATUS_ON
import com.idormy.sms.forwarder.utils.TASK_ACTION_FRPC
import com.idormy.sms.forwarder.utils.XToastUtils
import com.jeremyliao.liveeventbus.LiveEventBus
@ -24,6 +33,11 @@ import com.xuexiang.xrouter.annotation.AutoWired
import com.xuexiang.xrouter.launcher.XRouter
import com.xuexiang.xui.utils.CountDownButtonHelper
import com.xuexiang.xui.widget.actionbar.TitleBar
import com.xuexiang.xutil.resource.ResUtils.getDrawable
import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
@Page(name = "Frpc")
@Suppress("PrivatePropertyName")
@ -33,6 +47,16 @@ class FrpcFragment : BaseFragment<FragmentTasksActionFrpcBinding?>(), View.OnCli
private var titleBar: TitleBar? = null
private var mCountDownHelper: CountDownButtonHelper? = null
//当前发送通道
private var frpcUid = ""
private var frpcListSelected: MutableList<Frpc> = mutableListOf()
private var frpcItemMap = HashMap<String, LinearLayout>(2)
//发送通道列表
private var frpcListAll: MutableList<Frpc> = mutableListOf()
private val frpcSpinnerList = ArrayList<FrpcAdapterItem>()
private lateinit var frpcSpinnerAdapter: FrpcSpinnerAdapter<*>
@JvmField
@AutoWired(name = KEY_EVENT_DATA_ACTION)
var eventData: String? = null
@ -69,28 +93,15 @@ class FrpcFragment : BaseFragment<FragmentTasksActionFrpcBinding?>(), View.OnCli
}
})
binding!!.rgFrpcState.setOnCheckedChangeListener { _, checkedId ->
when (checkedId) {
R.id.rb_start_server -> {
binding!!.layoutStartServer.visibility = View.VISIBLE
binding!!.layoutStopServer.visibility = View.GONE
}
R.id.rb_stop_server -> {
binding!!.layoutStartServer.visibility = View.GONE
binding!!.layoutStopServer.visibility = View.VISIBLE
}
}
}
Log.d(TAG, "initViews eventData:$eventData")
if (eventData != null) {
val settingVo = Gson().fromJson(eventData, FrpcSetting::class.java)
binding!!.etStartUid.setText(settingVo.uids)
binding!!.etStopUid.setText(settingVo.uids)
binding!!.rgFrpcState.check(if (settingVo.action == "start") R.id.rb_start_server else R.id.rb_stop_server)
Log.d(TAG, "initViews settingVo:$settingVo")
}
//初始化发送通道下拉框
initFrpcSpinner()
}
@SuppressLint("SetTextI18n")
@ -151,23 +162,131 @@ class FrpcFragment : BaseFragment<FragmentTasksActionFrpcBinding?>(), View.OnCli
}
}
//初始化发送通道下拉框
@SuppressLint("SetTextI18n")
private fun initFrpcSpinner() {
Core.frpc.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Frpc>> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "initFrpcSpinner error: ${e.message}")
}
override fun onSuccess(frpcList: List<Frpc>) {
if (frpcList.isEmpty()) {
XToastUtils.error(R.string.add_frpc_first)
return
}
frpcListAll = frpcList as MutableList<Frpc>
for (frpc in frpcList) {
val name = if (frpc.name.length > 20) frpc.name.substring(0, 19) else frpc.name
frpcSpinnerList.add(FrpcAdapterItem(name, getDrawable(R.drawable.auto_task_icon_frpc), frpc.uid, frpc.autorun))
}
frpcSpinnerAdapter = FrpcSpinnerAdapter(frpcSpinnerList)
.setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
binding!!.spFrpc.setAdapter(frpcSpinnerAdapter)
if (frpcListSelected.isNotEmpty()) {
for (frpc in frpcListSelected) {
for (frpcItem in frpcSpinnerList) {
if (frpc.uid == frpcItem.uid) {
addFrpcItemLinearLayout(frpcItemMap, binding!!.layoutFrpcs, frpcItem)
}
}
}
}
}
})
binding!!.spFrpc.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long ->
try {
val frpc = frpcSpinnerAdapter.getItemSource(position) as FrpcAdapterItem
frpcUid = frpc.uid
if (frpcUid.isNotEmpty()) {
frpcListSelected.forEach {
if (frpcUid == it.uid) {
XToastUtils.warning(getString(R.string.frpc_contains_tips))
return@setOnItemClickListener
}
}
frpcListAll.forEach {
if (frpcUid == it.uid) {
frpcListSelected.add(it)
addFrpcItemLinearLayout(frpcItemMap, binding!!.layoutFrpcs, frpc)
}
}
/*if (STATUS_OFF == frpc.status) {
XToastUtils.warning(getString(R.string.frpc_disabled_tips))
}*/
}
} catch (e: Exception) {
XToastUtils.error(e.message.toString())
}
}
}
/**
* 动态增删Frpc
*
* @param frpcItemMap 管理item的map用于删除指定header
* @param layoutFrpcs 需要挂载item的LinearLayout
* @param frpc FrpcAdapterItem
*/
@SuppressLint("SetTextI18n")
private fun addFrpcItemLinearLayout(
frpcItemMap: MutableMap<String, LinearLayout>, layoutFrpcs: LinearLayout, frpc: FrpcAdapterItem
) {
val layoutFrpcItem = View.inflate(requireContext(), R.layout.item_add_frpc, null) as LinearLayout
val ivRemoveFrpc = layoutFrpcItem.findViewById<ImageView>(R.id.iv_remove_frpc)
val ivFrpcImage = layoutFrpcItem.findViewById<ImageView>(R.id.iv_frpc_image)
val ivFrpcStatus = layoutFrpcItem.findViewById<ImageView>(R.id.iv_frpc_status)
val tvFrpcName = layoutFrpcItem.findViewById<TextView>(R.id.tv_frpc_name)
ivFrpcImage.setImageDrawable(frpc.icon)
ivFrpcStatus.setImageDrawable(getDrawable(if (STATUS_ON == frpc.autorun) R.drawable.ic_autorun else R.drawable.ic_manual))
val frpcItemId = frpc.uid
tvFrpcName.text = frpc.title
ivRemoveFrpc.tag = frpcItemId
ivRemoveFrpc.setOnClickListener { view2: View ->
val tagId = view2.tag
layoutFrpcs.removeView(frpcItemMap[tagId])
frpcItemMap.remove(tagId)
//frpcListSelected.removeIf { it.uid == tagId }
for (it in frpcListSelected) {
if (it.uid == tagId) {
frpcListSelected -= it
break
}
}
Log.d(TAG, frpcListSelected.count().toString())
Log.d(TAG, frpcListSelected.toString())
if (frpcListSelected.isEmpty()) frpcUid = ""
}
layoutFrpcs.addView(layoutFrpcItem)
frpcItemMap[frpcItemId] = layoutFrpcItem
}
//检查设置
@SuppressLint("SetTextI18n")
private fun checkSetting(): FrpcSetting {
val startUid = binding!!.etStartUid.text.toString().trim()
val stopUid = binding!!.etStopUid.text.toString().trim()
val description: String
val action: String
val uids: String
if (binding!!.rgFrpcState.checkedRadioButtonId == R.id.rb_start_server) {
description = if (startUid == "") "启动全部自启动的Frpc" else "启动UID为${startUid}的Frpc"
action = "start"
uids = startUid
val description = StringBuilder()
val action = if (binding!!.rgFrpcState.checkedRadioButtonId == R.id.rb_start_server) {
description.append(getString(R.string.enable))
"start"
} else {
description = if (stopUid == "") "停止全部自启动的Frpc" else "停止UID为${stopUid}的Frpc"
action = "stop"
uids = stopUid
description.append(getString(R.string.disable))
"stop"
}
return FrpcSetting(description, action, uids)
if (frpcListSelected.isEmpty()) {
description.append(getString(R.string.all_auto_started_frpc))
} else {
description.append(getString(R.string.specified_frpc)).append(": ")
description.append(frpcListSelected.joinToString(",") { it.name })
}
return FrpcSetting(description.toString(), action, frpcListSelected)
}
}

View File

@ -215,10 +215,10 @@ class HttpServerFragment : BaseFragment<FragmentTasksActionHttpServerBinding?>()
val action = if (binding!!.rgHttpServerState.checkedRadioButtonId == R.id.rb_start_server) {
description.append(getString(R.string.start_server))
if (enableList.isNotEmpty()) {
description.append(", ").append(getString(R.string.enable_function)).append(": ").append(enableList.joinToString("/"))
description.append(", ").append(getString(R.string.enable_function)).append(": ").append(enableList.joinToString(","))
}
if (disableList.isNotEmpty()) {
description.append(", ").append(getString(R.string.disable_function)).append(": ").append(disableList.joinToString("/"))
description.append(", ").append(getString(R.string.disable_function)).append(": ").append(disableList.joinToString(","))
}
"start"
} else {

View File

@ -11,7 +11,7 @@ import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.spinner.SenderAdapterItem
import com.idormy.sms.forwarder.adapter.spinner.SenderSpinnerAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Rule
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.databinding.FragmentTasksActionNotificationBinding
@ -268,7 +268,7 @@ class NotificationFragment : BaseFragment<FragmentTasksActionNotificationBinding
R.id.btn_save -> {
val settingVo = checkSetting()
var description = getString(R.string.select_sender) + ": "
var description = getString(R.string.task_notification) + ": "
description += settingVo.senderList.joinToString(",") { it.name }
if (settingVo.senderList.size > 1) {
description += "; " + getString(R.string.sender_logic) + ": " + when (settingVo.senderLogic) {
@ -298,7 +298,7 @@ class NotificationFragment : BaseFragment<FragmentTasksActionNotificationBinding
//免打扰(禁用转发)时间段
binding!!.tvSilentPeriod.text = mTimeOption[silentPeriodStart] + " ~ " + mTimeOption[silentPeriodEnd]
AppDatabase.getInstance(requireContext()).senderDao().getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Sender>> {
Core.sender.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Sender>> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {

View File

@ -14,7 +14,7 @@ import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.spinner.RuleAdapterItem
import com.idormy.sms.forwarder.adapter.spinner.RuleSpinnerAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Rule
import com.idormy.sms.forwarder.databinding.FragmentTasksActionRuleBinding
import com.idormy.sms.forwarder.entity.action.RuleSetting
@ -24,7 +24,7 @@ import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_TEST_ACTION
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.STATUS_OFF
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDER
import com.idormy.sms.forwarder.utils.TASK_ACTION_RULE
import com.idormy.sms.forwarder.utils.XToastUtils
import com.jeremyliao.liveeventbus.LiveEventBus
import com.xuexiang.xaop.annotation.SingleClick
@ -52,7 +52,7 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
private var ruleListSelected: MutableList<Rule> = mutableListOf()
private var ruleItemMap = HashMap<Long, LinearLayout>(2)
//发送通道列表
//转发规则列表
private var ruleListAll: MutableList<Rule> = mutableListOf()
private val ruleSpinnerList = ArrayList<RuleAdapterItem>()
private lateinit var ruleSpinnerAdapter: RuleSpinnerAdapter<*>
@ -96,7 +96,7 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
Log.d(TAG, "initViews eventData:$eventData")
if (eventData != null) {
val settingVo = Gson().fromJson(eventData, RuleSetting::class.java)
binding!!.rgStatus.check(if (settingVo.status == "enable") R.id.rb_status_enable else R.id.rb_status_disable)
binding!!.rgStatus.check(if (settingVo.status == 1) R.id.rb_status_enable else R.id.rb_status_disable)
Log.d(TAG, settingVo.ruleList.toString())
settingVo.ruleList.forEach {
ruleId = it.id
@ -105,7 +105,7 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
Log.d(TAG, "initViews settingVo:$settingVo")
}
//初始化发送通道下拉框
//初始化转发规则下拉框
initRuleSpinner()
}
@ -155,7 +155,7 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
val intent = Intent()
intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, settingVo.description)
intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo))
setFragmentResult(TASK_ACTION_SENDER, intent)
setFragmentResult(TASK_ACTION_RULE, intent)
popToBack()
return
}
@ -167,10 +167,10 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
}
}
//初始化发送通道下拉框
//初始化转发规则下拉框
@SuppressLint("SetTextI18n")
private fun initRuleSpinner() {
AppDatabase.getInstance(requireContext()).ruleDao().getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Rule>> {
Core.rule.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Rule>> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
@ -187,7 +187,13 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
ruleListAll = ruleList as MutableList<Rule>
for (rule in ruleList) {
val name = if (rule.name.length > 20) rule.name.substring(0, 19) else rule.name
ruleSpinnerList.add(RuleAdapterItem(name, getDrawable(rule.imageId), rule.id, rule.status))
val icon = when (rule.type) {
"sms" -> R.drawable.auto_task_icon_sms
"call" -> R.drawable.auto_task_icon_incall
"app" -> R.drawable.auto_task_icon_start_activity
else -> R.drawable.auto_task_icon_sms
}
ruleSpinnerList.add(RuleAdapterItem(name, getDrawable(icon), rule.id, rule.status))
}
ruleSpinnerAdapter = RuleSpinnerAdapter(ruleSpinnerList)
.setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
@ -222,9 +228,9 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
}
}
if (STATUS_OFF == rule.status) {
/*if (STATUS_OFF == rule.status) {
XToastUtils.warning(getString(R.string.rule_disabled_tips))
}
}*/
}
} catch (e: Exception) {
XToastUtils.error(e.message.toString())
@ -277,21 +283,21 @@ class RuleFragment : BaseFragment<FragmentTasksActionRuleBinding?>(), View.OnCli
//检查设置
@SuppressLint("SetTextI18n")
private fun checkSetting(): RuleSetting {
if (ruleListSelected.isEmpty() || ruleId == 0L) {
throw Exception(getString(R.string.new_sender_first))
}
val description = StringBuilder()
val status: String
val status: Int
if (binding!!.rgStatus.checkedRadioButtonId == R.id.rb_status_enable) {
status = "enable"
status = 1
description.append(getString(R.string.enable))
} else {
status = "disable"
status = 0
description.append(getString(R.string.disable))
}
description.append(getString(R.string.menu_rules))
if (ruleListSelected.isNotEmpty()) {
description.append(", ").append(getString(R.string.specified_rule)).append(": ")
description.append(ruleListSelected.joinToString("/") { it.id.toString() })
}
description.append(getString(R.string.menu_rules)).append(", ").append(getString(R.string.specified_rule)).append(": ")
description.append(ruleListSelected.joinToString(",") { it.id.toString() })
return RuleSetting(description.toString(), status, ruleListSelected)
}

View File

@ -14,7 +14,7 @@ import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.adapter.spinner.SenderAdapterItem
import com.idormy.sms.forwarder.adapter.spinner.SenderSpinnerAdapter
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSenderBinding
import com.idormy.sms.forwarder.entity.action.SenderSetting
@ -96,7 +96,7 @@ class SenderFragment : BaseFragment<FragmentTasksActionSenderBinding?>(), View.O
Log.d(TAG, "initViews eventData:$eventData")
if (eventData != null) {
val settingVo = Gson().fromJson(eventData, SenderSetting::class.java)
binding!!.rgStatus.check(if (settingVo.status == "enable") R.id.rb_status_enable else R.id.rb_status_disable)
binding!!.rgStatus.check(if (settingVo.status == 1) R.id.rb_status_enable else R.id.rb_status_disable)
Log.d(TAG, settingVo.senderList.toString())
settingVo.senderList.forEach {
senderId = it.id
@ -170,7 +170,7 @@ class SenderFragment : BaseFragment<FragmentTasksActionSenderBinding?>(), View.O
//初始化发送通道下拉框
@SuppressLint("SetTextI18n")
private fun initSenderSpinner() {
AppDatabase.getInstance(requireContext()).senderDao().getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Sender>> {
Core.sender.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<List<Sender>> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
@ -222,9 +222,9 @@ class SenderFragment : BaseFragment<FragmentTasksActionSenderBinding?>(), View.O
}
}
if (STATUS_OFF == sender.status) {
/*if (STATUS_OFF == sender.status) {
XToastUtils.warning(getString(R.string.sender_disabled_tips))
}
}*/
}
} catch (e: Exception) {
XToastUtils.error(e.message.toString())
@ -277,21 +277,21 @@ class SenderFragment : BaseFragment<FragmentTasksActionSenderBinding?>(), View.O
//检查设置
@SuppressLint("SetTextI18n")
private fun checkSetting(): SenderSetting {
if (senderListSelected.isEmpty() || senderId == 0L) {
throw Exception(getString(R.string.new_sender_first))
}
val description = StringBuilder()
val status: String
val status: Int
if (binding!!.rgStatus.checkedRadioButtonId == R.id.rb_status_enable) {
status = "enable"
status = 1
description.append(getString(R.string.enable))
} else {
status = "disable"
status = 0
description.append(getString(R.string.disable))
}
description.append(getString(R.string.menu_senders))
if (senderListSelected.isNotEmpty()) {
description.append(", ").append(getString(R.string.specified_sender)).append(": ")
description.append(senderListSelected.joinToString("/") { it.name })
}
description.append(getString(R.string.menu_senders)).append(", ").append(getString(R.string.specified_sender)).append(": ")
description.append(senderListSelected.joinToString(",") { it.name })
return SenderSetting(description.toString(), status, senderListSelected)
}

View File

@ -476,10 +476,10 @@ class SettingsFragment : BaseFragment<FragmentTasksActionSettingsBinding?>(), Vi
val description = StringBuilder()
if (enableList.isNotEmpty()) {
description.append(" ").append(getString(R.string.enable_function)).append(": ").append(enableList.joinToString("/"))
description.append(" ").append(getString(R.string.enable_function)).append(": ").append(enableList.joinToString(","))
}
if (disableList.isNotEmpty()) {
description.append(" ").append(getString(R.string.disable_function)).append(": ").append(disableList.joinToString("/"))
description.append(" ").append(getString(R.string.disable_function)).append(": ").append(disableList.joinToString(","))
}
return SettingsSetting(description.toString().trim(), enableSms, enablePhone, enableCallType1, enableCallType2, enableCallType3, enableCallType4, enableCallType5, enableCallType6, enableAppNotify, enableCancelAppNotify, enableNotUserPresent, enableLocation, locationAccuracy, locationPowerRequirement, locationMinInterval, locationMinDistance, enableSmsCommand, smsCommandSafePhone, enableLoadAppList, enableLoadUserAppList, enableLoadSystemAppList, cancelExtraAppNotify, duplicateMessagesLimits)

View File

@ -172,7 +172,7 @@ class LeaveAddressFragment : BaseFragment<FragmentTasksConditionLeaveAddressBind
when (v.id) {
R.id.btn_current_coordinates -> {
if (!App.LocationClient.isStarted()) {
MaterialDialog.Builder(requireContext()).iconRes(R.drawable.icon_location).title(R.string.enable_location).content(R.string.enable_location_dialog).cancelable(false).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
MaterialDialog.Builder(requireContext()).iconRes(R.drawable.auto_task_icon_location).title(R.string.enable_location).content(R.string.enable_location_dialog).cancelable(false).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
SettingUtils.enableLocation = true
val serviceIntent = Intent(requireContext(), LocationService::class.java)
serviceIntent.action = "START"

View File

@ -172,7 +172,7 @@ class ToAddressFragment : BaseFragment<FragmentTasksConditionToAddressBinding?>(
when (v.id) {
R.id.btn_current_coordinates -> {
if (!App.LocationClient.isStarted()) {
MaterialDialog.Builder(requireContext()).iconRes(R.drawable.icon_location).title(R.string.enable_location).content(R.string.enable_location_dialog).cancelable(false).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
MaterialDialog.Builder(requireContext()).iconRes(R.drawable.auto_task_icon_location).title(R.string.enable_location).content(R.string.enable_location_dialog).cancelable(false).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
SettingUtils.enableLocation = true
val serviceIntent = Intent(requireContext(), LocationService::class.java)
serviceIntent.action = "START"

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -145,7 +145,7 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext()).senderDao().get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {

View File

@ -11,7 +11,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -105,41 +105,36 @@ class DingtalkGroupRobotFragment : BaseFragment<FragmentSendersDingtalkGroupRobo
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkGroupRobotSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etToken.setText(settingVo.token)
binding!!.etSecret.setText(settingVo.secret)
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etAtMobiles.setText(settingVo.atMobiles)
binding!!.etAtDingtalkIds.setText(settingVo.atDingtalkIds)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkGroupRobotSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etToken.setText(settingVo.token)
binding!!.etSecret.setText(settingVo.secret)
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etAtMobiles.setText(settingVo.atMobiles)
binding!!.etAtDingtalkIds.setText(settingVo.atDingtalkIds)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
}
}
})
}
override fun initListeners() {
@ -220,17 +215,11 @@ class DingtalkGroupRobotFragment : BaseFragment<FragmentSendersDingtalkGroupRobo
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -12,7 +12,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -99,46 +99,41 @@ class DingtalkInnerRobotFragment : BaseFragment<FragmentSendersDingtalkInnerRobo
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkInnerRobotSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etAgentID.setText(settingVo.agentID)
binding!!.etAppKey.setText(settingVo.appKey)
binding!!.etAppSecret.setText(settingVo.appSecret)
binding!!.etUserIds.setText(settingVo.userIds)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, DingtalkInnerRobotSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etAgentID.setText(settingVo.agentID)
binding!!.etAppKey.setText(settingVo.appKey)
binding!!.etAppSecret.setText(settingVo.appSecret)
binding!!.etUserIds.setText(settingVo.userIds)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
}
}
})
}
override fun initListeners() {
@ -228,17 +223,11 @@ class DingtalkInnerRobotFragment : BaseFragment<FragmentSendersDingtalkInnerRobo
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -121,50 +121,45 @@ class EmailFragment : BaseFragment<FragmentSendersEmailBinding?>(), View.OnClick
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, EmailSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
if (!TextUtils.isEmpty(settingVo.mailType)) {
mailType = settingVo.mailType.toString()
binding!!.spMailType.setSelectedItem(mailType)
if (mailType != getString(R.string.other_mail_type)) {
binding!!.layoutServiceSetting.visibility = View.GONE
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, EmailSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
if (!TextUtils.isEmpty(settingVo.mailType)) {
mailType = settingVo.mailType.toString()
binding!!.spMailType.setSelectedItem(mailType)
if (mailType != getString(R.string.other_mail_type)) {
binding!!.layoutServiceSetting.visibility = View.GONE
}
binding!!.etFromEmail.setText(settingVo.fromEmail)
binding!!.etPwd.setText(settingVo.pwd)
binding!!.etNickname.setText(settingVo.nickname)
binding!!.etHost.setText(settingVo.host)
binding!!.etPort.setText(settingVo.port)
binding!!.sbSsl.isChecked = settingVo.ssl == true
binding!!.sbStartTls.isChecked = settingVo.startTls == true
binding!!.etToEmail.setText(settingVo.toEmail)
binding!!.etTitleTemplate.setText(settingVo.title)
}
binding!!.etFromEmail.setText(settingVo.fromEmail)
binding!!.etPwd.setText(settingVo.pwd)
binding!!.etNickname.setText(settingVo.nickname)
binding!!.etHost.setText(settingVo.host)
binding!!.etPort.setText(settingVo.port)
binding!!.sbSsl.isChecked = settingVo.ssl == true
binding!!.sbStartTls.isChecked = settingVo.startTls == true
binding!!.etToEmail.setText(settingVo.toEmail)
binding!!.etTitleTemplate.setText(settingVo.title)
}
})
}
})
}
override fun initListeners() {
@ -253,17 +248,11 @@ class EmailFragment : BaseFragment<FragmentSendersEmailBinding?>(), View.OnClick
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -103,9 +103,7 @@ class FeishuAppFragment : BaseFragment<FragmentSendersFeishuAppBinding?>(), View
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
Core.sender.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -103,38 +103,33 @@ class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnCli
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, FeishuSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etWebhook.setText(settingVo.webhook)
binding!!.etSecret.setText(settingVo.secret)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, FeishuSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etWebhook.setText(settingVo.webhook)
binding!!.etSecret.setText(settingVo.secret)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
}
}
})
}
override fun initListeners() {
@ -198,17 +193,11 @@ class FeishuFragment : BaseFragment<FragmentSendersFeishuBinding?>(), View.OnCli
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -103,37 +103,32 @@ class GotifyFragment : BaseFragment<FragmentSendersGotifyBinding?>(), View.OnCli
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError $e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError $e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, GotifySetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etWebServer.setText(settingVo.webServer)
binding!!.etTitleTemplate.setText(settingVo.title)
binding!!.etPriority.setText(settingVo.priority)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, GotifySetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etWebServer.setText(settingVo.webServer)
binding!!.etTitleTemplate.setText(settingVo.title)
binding!!.etPriority.setText(settingVo.priority)
}
}
})
}
override fun initListeners() {
@ -197,17 +192,11 @@ class GotifyFragment : BaseFragment<FragmentSendersGotifyBinding?>(), View.OnCli
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -10,7 +10,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -104,47 +104,42 @@ class PushplusFragment : BaseFragment<FragmentSendersPushplusBinding?>(), View.O
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, PushplusSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
if (TextUtils.isEmpty(settingVo.website) || settingVo.website == getString(R.string.pushplus_plus)) {
binding!!.rgWebsite.check(R.id.rb_website_plus)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, PushplusSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
if (TextUtils.isEmpty(settingVo.website) || settingVo.website == getString(R.string.pushplus_plus)) {
binding!!.rgWebsite.check(R.id.rb_website_plus)
} else {
binding!!.rgWebsite.check(R.id.rb_website_hxtrip)
}
binding!!.etToken.setText(settingVo.token)
binding!!.etTopic.setText(settingVo.topic)
binding!!.etTemplate.setText(settingVo.template)
binding!!.etChannel.setText(settingVo.channel)
binding!!.etWebhook.setText(settingVo.webhook)
binding!!.etCallbackUrl.setText(settingVo.callbackUrl)
binding!!.etValidTime.setText(settingVo.validTime)
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
binding!!.rgWebsite.check(R.id.rb_website_hxtrip)
}
binding!!.etToken.setText(settingVo.token)
binding!!.etTopic.setText(settingVo.topic)
binding!!.etTemplate.setText(settingVo.template)
binding!!.etChannel.setText(settingVo.channel)
binding!!.etWebhook.setText(settingVo.webhook)
binding!!.etCallbackUrl.setText(settingVo.callbackUrl)
binding!!.etValidTime.setText(settingVo.validTime)
binding!!.etTitleTemplate.setText(settingVo.titleTemplate)
}
})
}
})
}
override fun initListeners() {
@ -217,17 +212,11 @@ class PushplusFragment : BaseFragment<FragmentSendersPushplusBinding?>(), View.O
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -8,7 +8,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -101,37 +101,32 @@ class ServerchanFragment : BaseFragment<FragmentSendersServerchanBinding?>(), Vi
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, ServerchanSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etSendKey.setText(settingVo.sendKey)
binding!!.etChannel.setText(settingVo.channel)
binding!!.etOpenid.setText(settingVo.openid)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, ServerchanSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etSendKey.setText(settingVo.sendKey)
binding!!.etChannel.setText(settingVo.channel)
binding!!.etOpenid.setText(settingVo.openid)
}
}
})
}
override fun initListeners() {
@ -170,17 +165,11 @@ class ServerchanFragment : BaseFragment<FragmentSendersServerchanBinding?>(), Vi
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -11,7 +11,7 @@ import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -86,27 +86,25 @@ class SmsFragment : BaseFragment<FragmentSendersSmsBinding?>(), View.OnClickList
*/
override fun initViews() {
//检查发短信权限
XXPermissions.with(this)
.permission(Permission.SEND_SMS)
.request(object : OnPermissionCallback {
override fun onGranted(permissions: List<String>, all: Boolean) {
if (!all) {
XToastUtils.error(R.string.toast_granted_part)
HttpServerUtils.enableApiSmsSend = false
}
}
override fun onDenied(permissions: List<String>, never: Boolean) {
XXPermissions.with(this).permission(Permission.SEND_SMS).request(object : OnPermissionCallback {
override fun onGranted(permissions: List<String>, all: Boolean) {
if (!all) {
XToastUtils.error(R.string.toast_granted_part)
HttpServerUtils.enableApiSmsSend = false
if (never) {
XToastUtils.error(R.string.toast_denied_never)
// 如果是被永久拒绝就跳转到应用权限系统设置页面
XXPermissions.startPermissionActivity(requireContext(), permissions)
} else {
XToastUtils.error(R.string.toast_denied)
}
}
})
}
override fun onDenied(permissions: List<String>, never: Boolean) {
HttpServerUtils.enableApiSmsSend = false
if (never) {
XToastUtils.error(R.string.toast_denied_never)
// 如果是被永久拒绝就跳转到应用权限系统设置页面
XXPermissions.startPermissionActivity(requireContext(), permissions)
} else {
XToastUtils.error(R.string.toast_denied)
}
}
})
//测试按钮增加倒计时,避免重复点击
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout)
@ -129,37 +127,32 @@ class SmsFragment : BaseFragment<FragmentSendersSmsBinding?>(), View.OnClickList
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, SmsSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.rgSimSlot.check(settingVo.getSmsSimSlotCheckId())
binding!!.etMobiles.setText(settingVo.mobiles)
binding!!.sbOnlyNoNetwork.isChecked = settingVo.onlyNoNetwork == true
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, SmsSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.rgSimSlot.check(settingVo.getSmsSimSlotCheckId())
binding!!.etMobiles.setText(settingVo.mobiles)
binding!!.sbOnlyNoNetwork.isChecked = settingVo.onlyNoNetwork == true
}
}
})
}
override fun initListeners() {
@ -204,17 +197,11 @@ class SmsFragment : BaseFragment<FragmentSendersSmsBinding?>(), View.OnClickList
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -103,7 +103,7 @@ class SocketFragment : BaseFragment<FragmentSendersSocketBinding?>(), View.OnCli
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext()).senderDao().get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {

View File

@ -10,7 +10,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -104,43 +104,38 @@ class TelegramFragment : BaseFragment<FragmentSendersTelegramBinding?>(), View.O
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, TelegramSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.rgMethod.check(settingVo.getMethodCheckId())
binding!!.etApiToken.setText(settingVo.apiToken)
binding!!.etChatId.setText(settingVo.chatId)
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, TelegramSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.rgMethod.check(settingVo.getMethodCheckId())
binding!!.etApiToken.setText(settingVo.apiToken)
binding!!.etChatId.setText(settingVo.chatId)
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
}
}
})
}
override fun initListeners() {
@ -196,17 +191,11 @@ class TelegramFragment : BaseFragment<FragmentSendersTelegramBinding?>(), View.O
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -12,7 +12,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -106,35 +106,30 @@ class UrlSchemeFragment : BaseFragment<FragmentSendersUrlSchemeBinding?>(), View
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, UrlSchemeSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etUrlScheme.setText(settingVo.urlScheme)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, UrlSchemeSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etUrlScheme.setText(settingVo.urlScheme)
}
}
})
}
override fun initListeners() {
@ -173,17 +168,11 @@ class UrlSchemeFragment : BaseFragment<FragmentSendersUrlSchemeBinding?>(), View
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -11,7 +11,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -87,8 +87,7 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
override fun initViews() {
//测试按钮增加倒计时,避免重复点击
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout)
mCountDownHelper!!.setOnCountDownListener(object :
CountDownButtonHelper.OnCountDownListener {
mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener {
override fun onCountDown(time: Int) {
binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time)
}
@ -107,50 +106,42 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WebhookSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.rgMethod.check(settingVo.getMethodCheckId())
binding!!.etWebServer.setText(settingVo.webServer)
binding!!.etSecret.setText(settingVo.secret)
binding!!.etResponse.setText(settingVo.response)
binding!!.etWebParams.setText(settingVo.webParams)
//set header
if (settingVo.headers != null) {
for ((key, value) in settingVo.headers) {
addHeaderItemLinearLayout(
headerItemMap,
binding!!.layoutHeaders,
key,
value
)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WebhookSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.rgMethod.check(settingVo.getMethodCheckId())
binding!!.etWebServer.setText(settingVo.webServer)
binding!!.etSecret.setText(settingVo.secret)
binding!!.etResponse.setText(settingVo.response)
binding!!.etWebParams.setText(settingVo.webParams)
//set header
if (settingVo.headers != null) {
for ((key, value) in settingVo.headers) {
addHeaderItemLinearLayout(
headerItemMap, binding!!.layoutHeaders, key, value
)
}
}
}
})
}
})
}
override fun initListeners() {
@ -192,17 +183,11 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}
@ -215,8 +200,7 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
val status = if (binding!!.sbEnable.isChecked) 1 else 0
val settingVo = checkSetting()
if (isClone) senderId = 0
val senderNew =
Sender(senderId, senderType, name, Gson().toJson(settingVo), status)
val senderNew = Sender(senderId, senderType, name, Gson().toJson(settingVo), status)
Log.d(TAG, senderNew.toString())
viewModel.insertOrUpdate(senderNew)
@ -265,20 +249,13 @@ class WebhookFragment : BaseFragment<FragmentSendersWebhookBinding?>(), View.OnC
* @param value header的value为空则不设置
*/
private fun addHeaderItemLinearLayout(
headerItemMap: MutableMap<Int, LinearLayout>,
linearLayoutWebNotifyHeaders: LinearLayout,
key: String?,
value: String?
headerItemMap: MutableMap<Int, LinearLayout>, linearLayoutWebNotifyHeaders: LinearLayout, key: String?, value: String?
) {
val linearLayoutItemAddHeader =
View.inflate(requireContext(), R.layout.item_add_header, null) as LinearLayout
val imageViewRemoveHeader =
linearLayoutItemAddHeader.findViewById<ImageView>(R.id.imageViewRemoveHeader)
val linearLayoutItemAddHeader = View.inflate(requireContext(), R.layout.item_add_header, null) as LinearLayout
val imageViewRemoveHeader = linearLayoutItemAddHeader.findViewById<ImageView>(R.id.imageViewRemoveHeader)
if (key != null && value != null) {
val editTextHeaderKey =
linearLayoutItemAddHeader.findViewById<EditText>(R.id.editTextHeaderKey)
val editTextHeaderValue =
linearLayoutItemAddHeader.findViewById<EditText>(R.id.editTextHeaderValue)
val editTextHeaderKey = linearLayoutItemAddHeader.findViewById<EditText>(R.id.editTextHeaderKey)
val editTextHeaderValue = linearLayoutItemAddHeader.findViewById<EditText>(R.id.editTextHeaderValue)
editTextHeaderKey.setText(key)
editTextHeaderValue.setText(value)
}

View File

@ -11,7 +11,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -98,51 +98,46 @@ class WeworkAgentFragment : BaseFragment<FragmentSendersWeworkAgentBinding?>(),
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WeworkAgentSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etCorpID.setText(settingVo.corpID)
binding!!.etAgentID.setText(settingVo.agentID)
binding!!.etSecret.setText(settingVo.secret)
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etToUser.setText(settingVo.toUser)
binding!!.etToParty.setText(settingVo.toParty)
binding!!.etToTag.setText(settingVo.toTag)
binding!!.layoutToUser.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToParty.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToTag.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
binding!!.etCustomizeAPI.setText(settingVo.customizeAPI)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WeworkAgentSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etCorpID.setText(settingVo.corpID)
binding!!.etAgentID.setText(settingVo.agentID)
binding!!.etSecret.setText(settingVo.secret)
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etToUser.setText(settingVo.toUser)
binding!!.etToParty.setText(settingVo.toParty)
binding!!.etToTag.setText(settingVo.toTag)
binding!!.layoutToUser.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToParty.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.layoutToTag.visibility = if (settingVo.atAll == true) View.GONE else View.VISIBLE
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
binding!!.etCustomizeAPI.setText(settingVo.customizeAPI)
}
}
})
}
override fun initListeners() {
@ -223,17 +218,11 @@ class WeworkAgentFragment : BaseFragment<FragmentSendersWeworkAgentBinding?>(),
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -10,7 +10,7 @@ import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.Sender
import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory
import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel
@ -104,40 +104,35 @@ class WeworkRobotFragment : BaseFragment<FragmentSendersWeworkRobotBinding?>(),
//编辑
binding!!.btnDel.setText(R.string.del)
AppDatabase.getInstance(requireContext())
.senderDao()
.get(senderId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
Core.sender.get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
override fun onSubscribe(d: Disposable) {}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onError(e: Throwable) {
e.printStackTrace()
Log.e(TAG, "onError:$e")
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WeworkRobotSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etWebHook.setText(settingVo.webHook)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.layoutAt.visibility = if (settingVo.getMsgTypeCheckId() == R.id.rb_msg_type_text) View.VISIBLE else View.GONE
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etAtMobiles.setText(settingVo.atMobiles)
binding!!.etAtUserIds.setText(settingVo.atUserIds)
}
override fun onSuccess(sender: Sender) {
if (isClone) {
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
binding!!.btnDel.setText(R.string.discard)
} else {
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
}
})
binding!!.etName.setText(sender.name)
binding!!.sbEnable.isChecked = sender.status == 1
val settingVo = Gson().fromJson(sender.jsonSetting, WeworkRobotSetting::class.java)
Log.d(TAG, settingVo.toString())
if (settingVo != null) {
binding!!.etWebHook.setText(settingVo.webHook)
binding!!.rgMsgType.check(settingVo.getMsgTypeCheckId())
binding!!.layoutAt.visibility = if (settingVo.getMsgTypeCheckId() == R.id.rb_msg_type_text) View.VISIBLE else View.GONE
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etAtMobiles.setText(settingVo.atMobiles)
binding!!.etAtUserIds.setText(settingVo.atUserIds)
}
}
})
}
override fun initListeners() {
@ -193,17 +188,11 @@ class WeworkRobotFragment : BaseFragment<FragmentSendersWeworkRobotBinding?>(),
return
}
MaterialDialog.Builder(requireContext())
.title(R.string.delete_sender_title)
.content(R.string.delete_sender_tips)
.positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}
.show()
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(senderId)
XToastUtils.success(R.string.delete_sender_toast)
popToBack()
}.show()
return
}

View File

@ -16,11 +16,13 @@ import androidx.annotation.RequiresApi
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.workDataOf
import com.idormy.sms.forwarder.utils.DELAY_TIME_AFTER_SIM_READY
import com.idormy.sms.forwarder.utils.Log
import com.idormy.sms.forwarder.utils.TASK_CONDITION_NETWORK
import com.idormy.sms.forwarder.utils.TaskWorker
import com.idormy.sms.forwarder.utils.task.TaskUtils
import com.idormy.sms.forwarder.workers.NetworkWorker
import java.util.concurrent.TimeUnit
@Suppress("PrivatePropertyName", "DEPRECATION", "UNUSED_PARAMETER")
class NetworkChangeReceiver : BroadcastReceiver() {
@ -84,12 +86,14 @@ class NetworkChangeReceiver : BroadcastReceiver() {
return
}
//获取公网IP地址后执行任务
val request = OneTimeWorkRequestBuilder<NetworkWorker>().setInputData(
workDataOf(
TaskWorker.conditionType to TASK_CONDITION_NETWORK,
)
).build()
//【注意】延迟5秒给够搜索信号时间才执行任务
val request = OneTimeWorkRequestBuilder<NetworkWorker>()
.setInitialDelay(DELAY_TIME_AFTER_SIM_READY, TimeUnit.MILLISECONDS)
.setInputData(
workDataOf(
TaskWorker.conditionType to TASK_CONDITION_NETWORK,
)
).build()
WorkManager.getInstance(context).enqueue(request)
}

View File

@ -12,10 +12,9 @@ import androidx.core.app.NotificationCompat
import androidx.lifecycle.Observer
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.activity.MainActivity
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.utils.*
import com.idormy.sms.forwarder.utils.task.CronJobScheduler
import com.idormy.sms.forwarder.workers.LoadAppListWorker
@ -45,7 +44,7 @@ class ForegroundService : Service() {
if (Frpclib.isRunning(uid)) {
return@Observer
}
AppDatabase.getInstance(App.context).frpcDao().get(uid).flatMap { (uid1, _, config) ->
Core.frpc.get(uid).flatMap { (uid1, _, config) ->
val error = Frpclib.runContent(uid1, config)
Single.just(error)
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<String> {
@ -130,7 +129,7 @@ class ForegroundService : Service() {
//启动定时任务
GlobalScope.async(Dispatchers.IO) {
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(TASK_CONDITION_CRON)
val taskList = Core.task.getByType(TASK_CONDITION_CRON)
taskList.forEach { task ->
Log.d(TAG, "task = $task")
CronJobScheduler.cancelTask(task.id)
@ -150,7 +149,7 @@ class ForegroundService : Service() {
LiveEventBus.get(INTENT_FRPC_APPLY_FILE, String::class.java).observeStickyForever(frpcObserver)
//自启动的Frpc
GlobalScope.async(Dispatchers.IO) {
val frpcList = AppDatabase.getInstance(App.context).frpcDao().getAutorun()
val frpcList = Core.frpc.getAutorun()
if (frpcList.isEmpty()) {
Log.d(TAG, "没有自启动的Frpc")

View File

@ -237,8 +237,8 @@ const val TASK_ACTION_SENDSMS = 2000
const val TASK_ACTION_NOTIFICATION = 2001
const val TASK_ACTION_CLEANER = 2002
const val TASK_ACTION_SETTINGS = 2003
const val TASK_ACTION_HTTPSERVER = 2004
const val TASK_ACTION_FRPC = 2005
const val TASK_ACTION_FRPC = 2004
const val TASK_ACTION_HTTPSERVER = 2005
const val TASK_ACTION_RULE = 2006
const val TASK_ACTION_SENDER = 2007

View File

@ -8,7 +8,7 @@ import android.net.wifi.WifiManager
import androidx.core.app.ActivityCompat
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.server.model.SmsSendData
import com.idormy.sms.forwarder.service.HttpServerService
import com.xuexiang.xrouter.utils.TextUtils
@ -50,10 +50,10 @@ class SmsCommandUtils {
GlobalScope.async(Dispatchers.IO) {
val frpcList = if (param.isEmpty()) {
AppDatabase.getInstance(App.context).frpcDao().getAutorun()
Core.frpc.getAutorun()
} else {
val uids = param.split(",")
AppDatabase.getInstance(App.context).frpcDao().getByUids(uids)
Core.frpc.getByUids(uids)
}
if (frpcList.isEmpty()) {

View File

@ -43,9 +43,9 @@ class ConditionUtils private constructor() {
return true
}
//注意:触发条件 = SIM卡已准备就绪延迟5秒给够搜索信号时间才执行任务
//注意:触发条件 = SIM卡已准备就绪/网络状态改变延迟5秒给够搜索信号时间才执行任务
val firstCondition = conditionList.firstOrNull()
val needDelay = firstCondition?.type == TASK_CONDITION_SIM && TaskUtils.simState == 5
val needDelay = (firstCondition?.type == TASK_CONDITION_SIM && TaskUtils.simState == 5) || (firstCondition?.type == TASK_CONDITION_NETWORK && TaskUtils.networkState != 0)
for (i in startIndex until conditionList.size) {
val condition = conditionList[i]

View File

@ -57,8 +57,8 @@ class TaskUtils private constructor() {
TASK_ACTION_NOTIFICATION -> R.drawable.auto_task_icon_notification
TASK_ACTION_CLEANER -> R.drawable.auto_task_icon_cleaner
TASK_ACTION_SETTINGS -> R.drawable.auto_task_icon_settings
TASK_ACTION_HTTPSERVER -> R.drawable.auto_task_icon_http_server
TASK_ACTION_FRPC -> R.drawable.auto_task_icon_frpc
TASK_ACTION_HTTPSERVER -> R.drawable.auto_task_icon_http_server
TASK_ACTION_RULE -> R.drawable.auto_task_icon_rule
TASK_ACTION_SENDER -> R.drawable.auto_task_icon_sender
else -> R.drawable.auto_task_icon_custom_time
@ -80,8 +80,8 @@ class TaskUtils private constructor() {
TASK_ACTION_NOTIFICATION -> R.drawable.auto_task_icon_notification_grey
TASK_ACTION_CLEANER -> R.drawable.auto_task_icon_cleaner_grey
TASK_ACTION_SETTINGS -> R.drawable.auto_task_icon_settings_grey
TASK_ACTION_HTTPSERVER -> R.drawable.auto_task_icon_http_server_grey
TASK_ACTION_FRPC -> R.drawable.auto_task_icon_frpc_grey
TASK_ACTION_HTTPSERVER -> R.drawable.auto_task_icon_http_server_grey
TASK_ACTION_RULE -> R.drawable.auto_task_icon_rule_grey
TASK_ACTION_SENDER -> R.drawable.auto_task_icon_sender_grey
else -> R.drawable.auto_task_icon_custom_time_grey

View File

@ -13,13 +13,14 @@ import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.database.entity.Rule
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.action.CleanerSetting
import com.idormy.sms.forwarder.entity.action.FrpcSetting
import com.idormy.sms.forwarder.entity.action.HttpServerSetting
import com.idormy.sms.forwarder.entity.action.RuleSetting
import com.idormy.sms.forwarder.entity.action.SenderSetting
import com.idormy.sms.forwarder.entity.action.SettingsSetting
import com.idormy.sms.forwarder.entity.action.SmsSetting
import com.idormy.sms.forwarder.service.HttpServerService
@ -39,6 +40,8 @@ import com.idormy.sms.forwarder.utils.TASK_ACTION_CLEANER
import com.idormy.sms.forwarder.utils.TASK_ACTION_FRPC
import com.idormy.sms.forwarder.utils.TASK_ACTION_HTTPSERVER
import com.idormy.sms.forwarder.utils.TASK_ACTION_NOTIFICATION
import com.idormy.sms.forwarder.utils.TASK_ACTION_RULE
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDER
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDSMS
import com.idormy.sms.forwarder.utils.TASK_ACTION_SETTINGS
import com.idormy.sms.forwarder.utils.TaskWorker
@ -197,11 +200,8 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
continue
}
val frpcList = if (frpcSetting.uids.isEmpty()) {
AppDatabase.getInstance(App.context).frpcDao().getAutorun()
} else {
val uids = frpcSetting.uids.split(",")
AppDatabase.getInstance(App.context).frpcDao().getByUids(uids)
val frpcList = frpcSetting.frpcList.ifEmpty {
Core.frpc.getAutorun()
}
if (frpcList.isEmpty()) {
@ -256,6 +256,38 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
writeLog("httpServer success", "SUCCESS")
}
TASK_ACTION_RULE -> {
val ruleSetting = Gson().fromJson(action.setting, RuleSetting::class.java)
if (ruleSetting == null) {
writeLog("httpServerSetting is null")
continue
}
val ids = ruleSetting.ruleList.map { it.id }
if (ids.isNotEmpty()) {
Core.rule.updateStatusByIds(ids, ruleSetting.status)
}
successNum++
writeLog("update rule success", "SUCCESS")
}
TASK_ACTION_SENDER -> {
val senderSetting = Gson().fromJson(action.setting, SenderSetting::class.java)
if (senderSetting == null) {
writeLog("senderSetting is null")
continue
}
val ids = senderSetting.senderList.map { it.id }
if (ids.isNotEmpty()) {
Core.sender.updateStatusByIds(ids, senderSetting.status)
}
successNum++
writeLog("update sender success", "SUCCESS")
}
else -> {
writeLog("action.type is ${action.type}")
}

View File

@ -7,8 +7,7 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.condition.BatterySetting
@ -40,7 +39,7 @@ class BatteryWorker(context: Context, params: WorkerParameters) : CoroutineWorke
return Result.failure()
}
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")
@ -95,7 +94,7 @@ class BatteryWorker(context: Context, params: WorkerParameters) : CoroutineWorke
return Result.failure()
}
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")

View File

@ -7,8 +7,7 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.condition.CronSetting
@ -32,7 +31,7 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
return Result.failure()
}
val task = AppDatabase.getInstance(App.context).taskDao().getOne(taskId)
val task = Core.task.getOne(taskId)
if (task == null || task.status == 0) {
Log.d(TAG, "TASK-$taskIdtask is disabled")
return Result.success()
@ -77,7 +76,7 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
}
// 更新任务信息
AppDatabase.getInstance(App.context).taskDao().updateExecTime(task.id, task.lastExecTime, task.nextExecTime, task.status)
Core.task.updateExecTime(task.id, task.lastExecTime, task.nextExecTime, task.status)
if (task.status == 0) {
Log.d(TAG, "TASK-${task.id}task is disabled")

View File

@ -7,9 +7,8 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.LocationInfo
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
@ -51,7 +50,7 @@ class LocationWorker(context: Context, params: WorkerParameters) : CoroutineWork
//到达地点
TASK_CONDITION_TO_ADDRESS -> {
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")
@ -114,7 +113,7 @@ class LocationWorker(context: Context, params: WorkerParameters) : CoroutineWork
//离开地点
TASK_CONDITION_LEAVE_ADDRESS -> {
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")

View File

@ -8,8 +8,7 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.condition.LockScreenSetting
@ -29,7 +28,7 @@ class LockScreenWorker(context: Context, params: WorkerParameters) : CoroutineWo
val conditionType = inputData.getInt(TaskWorker.conditionType, -1)
val action = inputData.getString(TaskWorker.action)
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")

View File

@ -9,7 +9,7 @@ import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.condition.NetworkSetting
@ -34,7 +34,7 @@ class NetworkWorker(context: Context, params: WorkerParameters) : CoroutineWorke
override suspend fun doWork(): Result {
try {
val conditionType = inputData.getInt(TaskWorker.conditionType, -1)
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")
@ -61,7 +61,7 @@ class NetworkWorker(context: Context, params: WorkerParameters) : CoroutineWorke
continue
}
//TODO判断其他条件是否满足
//TODO判断其他条件是否满足注意延迟5秒给够搜索信号时间才执行任务
if (!ConditionUtils.checkCondition(task.id, conditionList)) {
Log.d(TAG, "TASK-${task.id}other condition is not satisfied")
continue
@ -92,7 +92,6 @@ class NetworkWorker(context: Context, params: WorkerParameters) : CoroutineWorke
}
}
Thread.sleep(1000) //延迟2秒等待获取IP地址
ipv4 = getPublicIP(false)
ipv6 = getPublicIP(true)
}
@ -106,7 +105,6 @@ class NetworkWorker(context: Context, params: WorkerParameters) : CoroutineWorke
msg.append(getString(R.string.net_wifi)).append("\n")
msg.append(getString(R.string.wifi_ssid)).append(": ").append(TaskUtils.wifiSsid).append("\n")
Thread.sleep(2000) //延迟2秒等待获取IP地址
ipv4 = getPublicIP(false)
ipv6 = getPublicIP(true)
}
@ -154,6 +152,8 @@ class NetworkWorker(context: Context, params: WorkerParameters) : CoroutineWorke
//获取公网IP地址
private fun getPublicIP(ipv6: Boolean = false): String {
if (TaskUtils.networkState == 0) return ""
return try {
val url = if (ipv6) URL("https://api6.ipify.org/") else URL("https://api.ipify.org/")
val urlConnection = url.openConnection() as HttpURLConnection

View File

@ -10,7 +10,7 @@ import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.condition.SimSetting
@ -31,7 +31,7 @@ class SimWorker(context: Context, params: WorkerParameters) : CoroutineWorker(co
try {
val conditionType = inputData.getInt(TaskWorker.conditionType, -1)
val simStateStr = inputData.getString(TaskWorker.msg)
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
val taskList = Core.task.getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="25.0dip" android:width="25.0dip" android:autoMirrored="true" android:viewportWidth="25.0" android:viewportHeight="25.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/color_green_primary_default" android:pathData="M6.66,0.66L18.66,0.66A6,6 0,0 1,24.66 6.66L24.66,18.66A6,6 0,0 1,18.66 24.66L6.66,24.66A6,6 0,0 1,0.66 18.66L0.66,6.66A6,6 0,0 1,6.66 0.66z" />
<path android:fillColor="#ffffffff" android:pathData="M9.372,6.643C9.337,6.583 9.292,6.531 9.238,6.488C9.078,6.322 8.846,6.252 8.622,6.298L8.486,6.314C8.453,6.313 8.427,6.318 8.412,6.321C8.375,6.328 8.344,6.34 8.326,6.348C8.285,6.365 8.24,6.388 8.197,6.412C8.107,6.462 7.991,6.534 7.864,6.615C7.609,6.779 7.295,6.995 7.034,7.186L7.029,7.19L7.025,7.193C6.433,7.657 6.249,8.29 6.29,8.968C6.327,9.585 6.549,10.26 6.823,10.93L6.81,10.951L6.872,11.093C7.346,12.181 8.27,13.582 9.741,15.108L9.738,15.112L9.926,15.3L9.993,15.366L10.009,15.381L10.02,15.392L10.113,15.299L10.114,15.3L10.021,15.394C11.622,16.972 13.094,17.953 14.226,18.447L14.368,18.509L14.389,18.496C15.058,18.77 15.734,18.992 16.351,19.029C17.028,19.07 17.662,18.886 18.126,18.294L18.129,18.29L18.132,18.285C18.323,18.024 18.539,17.71 18.703,17.455C18.785,17.328 18.857,17.212 18.906,17.122C18.931,17.079 18.954,17.034 18.971,16.993C18.979,16.975 18.991,16.944 18.998,16.907C19.001,16.892 19.006,16.866 19.005,16.833L19.02,16.697C19.066,16.473 18.996,16.241 18.831,16.081C18.788,16.028 18.736,15.982 18.676,15.948L18.64,15.92L15.363,14.127L13.785,15.497C13.005,15.085 12.239,14.414 11.574,13.762C10.916,13.093 10.237,12.321 9.822,11.533L11.192,9.955L9.399,6.679L9.372,6.643ZM10.039,15.186L10.039,15.185L10.048,15.176L10.049,15.177C10.059,15.207 10.073,15.237 10.091,15.267L10.09,15.268C10.071,15.244 10.053,15.217 10.039,15.186ZM10.005,14.98L10.02,14.991C10.021,14.98 10.022,14.971 10.024,14.965C10.023,14.965 10.023,14.964 10.022,14.963C10.017,14.968 10.011,14.974 10.005,14.98ZM10.091,15.269L10.092,15.268L10.101,15.281L10.091,15.269ZM10.116,15.298L10.115,15.297L10.234,15.178L10.116,15.298ZM10.431,15.407L10.441,15.398L10.44,15.4L10.431,15.407ZM10.425,15.413L10.428,15.41L10.427,15.411L10.425,15.413ZM10.394,15.435L10.391,15.436L10.403,15.429L10.394,15.435ZM10.408,15.426L10.407,15.427L10.41,15.424L10.408,15.426Z" android:fillType="evenOdd" />
</vector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="25.0dip" android:width="25.0dip" android:autoMirrored="true" android:viewportWidth="25.0" android:viewportHeight="25.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/auto_task_icon_light_blue" android:pathData="M6.66,0.66L18.66,0.66A6,6 0,0 1,24.66 6.66L24.66,18.66A6,6 0,0 1,18.66 24.66L6.66,24.66A6,6 0,0 1,0.66 18.66L0.66,6.66A6,6 0,0 1,6.66 0.66z" />
<path android:fillColor="#ffffffff" android:pathData="M7.984,5.837C8.418,5.586 8.974,5.735 9.224,6.169L9.779,7.13C10.518,6.712 11.372,6.473 12.282,6.473C13.199,6.473 14.06,6.715 14.803,7.14L15.342,6.207C15.592,5.772 16.148,5.623 16.582,5.874C17.017,6.125 17.165,6.68 16.915,7.115L16.212,8.331C16.862,9.121 17.278,10.11 17.355,11.194H7.21C7.287,10.103 7.708,9.107 8.366,8.314L7.651,7.077C7.401,6.643 7.55,6.087 7.984,5.837ZM17.368,12.647H7.198V17.732C7.198,18.535 7.848,19.185 8.651,19.185H15.915C16.718,19.185 17.368,18.535 17.368,17.732V12.647Z" android:fillType="evenOdd" />
</vector>

View File

@ -58,6 +58,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView

View File

@ -150,12 +150,12 @@
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
@ -190,12 +190,12 @@
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
@ -230,12 +230,12 @@
style="@style/BarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView

View File

@ -66,6 +66,7 @@
android:text="@string/forward_sms_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
@ -928,7 +929,7 @@
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="TouchTargetSizeCheck" />
tools:ignore="TouchTargetSizeCheck,DuplicateSpeakableTextCheck" />
</LinearLayout>
@ -1119,6 +1120,7 @@
android:text="@string/retry_interval_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<LinearLayout
@ -1257,6 +1259,7 @@
android:text="@string/custom_settings_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<LinearLayout
@ -1276,7 +1279,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1" />
android:layout_weight="1"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/btn_extra_device_mark"
@ -1292,7 +1296,7 @@
app:sb_ripple_color="@color/white"
app:sb_ripple_duration="500"
app:sb_shape_type="rectangle"
tools:ignore="SmallSp" />
tools:ignore="SmallSp,DuplicateSpeakableTextCheck,TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
@ -1320,6 +1324,7 @@
android:text="@string/carrier_mobile"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
@ -1337,7 +1342,8 @@
app:met_autoValidate="true"
app:met_errorMessage="@string/tip_number_only_error_message"
app:met_regexp="@string/regexp_number_only"
app:met_validateOnFocusLost="true" />
app:met_validateOnFocusLost="true"
tools:ignore="DuplicateSpeakableTextCheck,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_extra_sim1"
@ -1347,7 +1353,8 @@
android:layout_weight="3"
android:hint="@string/custom_settings_tips"
android:singleLine="true"
app:met_clearButton="true" />
app:met_clearButton="true"
tools:ignore="DuplicateSpeakableTextCheck,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/btn_extra_sim1"
@ -1363,7 +1370,7 @@
app:sb_ripple_color="@color/white"
app:sb_ripple_duration="500"
app:sb_shape_type="rectangle"
tools:ignore="SmallSp" />
tools:ignore="SmallSp,TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
@ -1391,6 +1398,7 @@
android:text="@string/carrier_mobile"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
@ -1408,7 +1416,8 @@
app:met_autoValidate="true"
app:met_errorMessage="@string/tip_number_only_error_message"
app:met_regexp="@string/regexp_number_only"
app:met_validateOnFocusLost="true" />
app:met_validateOnFocusLost="true"
tools:ignore="TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_extra_sim2"
@ -1418,7 +1427,8 @@
android:layout_weight="3"
android:hint="@string/custom_settings_tips"
android:singleLine="true"
app:met_clearButton="true" />
app:met_clearButton="true"
tools:ignore="TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/btn_extra_sim2"
@ -1434,7 +1444,7 @@
app:sb_ripple_color="@color/white"
app:sb_ripple_duration="500"
app:sb_shape_type="rectangle"
tools:ignore="SmallSp" />
tools:ignore="SmallSp,TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
@ -1457,7 +1467,8 @@
android:layout_marginStart="5dp"
android:layout_weight="1"
android:inputType="textMultiLine"
android:minLines="1" />
android:minLines="1"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
</LinearLayout>
@ -1485,13 +1496,15 @@
android:text="@string/enable_custom_templates_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_sms_template"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
tools:ignore="TouchTargetSizeCheck" />
</LinearLayout>
@ -1533,7 +1546,7 @@
android:inputType="textMultiLine"
android:minLines="1"
android:text=""
tools:ignore="RtlHardcoded" />
tools:ignore="RtlHardcoded,SpeakableTextPresentCheck" />
<LinearLayout
android:layout_width="match_parent"
@ -1597,6 +1610,7 @@
android:text="@string/pure_client_mode_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
@ -1631,6 +1645,7 @@
android:text="@string/pure_task_mode_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
@ -1652,12 +1667,36 @@
android:layout_weight="1"
android:orientation="vertical">
<TextView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/debug_mode"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/debug_mode"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/btn_export_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:gravity="center"
android:padding="3dp"
android:text="@string/export"
android:textColor="@color/white"
android:textSize="@dimen/text_size_mini"
app:sb_color_unpressed="@color/colorPrimary"
app:sb_ripple_color="@color/white"
app:sb_ripple_duration="500"
app:sb_shape_type="rectangle"
tools:ignore="PrivateResource,SmallSp" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
@ -1665,22 +1704,8 @@
android:text="@string/debug_mode_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.shadowbutton.RippleShadowShadowButton
android:id="@+id/btn_export_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="@string/export"
android:textColor="@color/white"
android:textSize="@dimen/text_size_small"
app:sb_color_unpressed="@color/colorPrimary"
app:sb_ripple_color="@color/white"
app:sb_ripple_duration="500"
app:sb_shape_type="rectangle"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_debug_mode"

View File

@ -59,81 +59,54 @@
<RadioGroup
android:id="@+id/rg_frpc_state"
style="@style/rg_style"
android:orientation="vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/config_padding_5dp">
<RadioButton
android:id="@+id/rb_start_server"
style="@style/rg_rb_style_match"
style="@style/rg_rb_style"
android:checked="true"
android:text="@string/start_server"
tools:ignore="TouchTargetSizeCheck" />
<LinearLayout
android:id="@+id/layout_start_server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/config_margin_10dp"
android:layout_marginEnd="@dimen/config_margin_10dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/specified_uid"
android:textStyle="bold" />
<EditText
android:id="@+id/et_start_uid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:hint="@string/specified_uid_hint"
android:importantForAutofill="no"
tools:ignore="TextContrastCheck,TextFields,TouchTargetSizeCheck" />
</LinearLayout>
<RadioButton
android:id="@+id/rb_stop_server"
style="@style/rg_rb_style_match"
style="@style/rg_rb_style"
android:text="@string/stop_server"
tools:ignore="TouchTargetSizeCheck" />
<LinearLayout
android:id="@+id/layout_stop_server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/config_margin_10dp"
android:layout_marginEnd="@dimen/config_margin_10dp"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/specified_uid"
android:textStyle="bold" />
<EditText
android:id="@+id/et_stop_uid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:hint="@string/specified_uid_hint"
android:importantForAutofill="no"
tools:ignore="TextContrastCheck,TextFields,TouchTargetSizeCheck" />
</LinearLayout>
</RadioGroup>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/specified_uid"
android:textStyle="bold" />
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner
android:id="@+id/sp_frpc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
app:es_hint="@string/choose_frpc"
app:es_maxLength="20"
app:es_maxLine="1" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_frpcs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</LinearLayout>

View File

@ -60,7 +60,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/layout_Senders"
android:id="@+id/layout_senders"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />

View File

@ -54,7 +54,7 @@
</LinearLayout>
<LinearLayout
style="@style/BarStyle"
style="@style/BarStyle.Switch"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -69,7 +69,7 @@
android:layout_height="wrap_content"
android:text="@string/forward_sms"
android:textStyle="bold"
tools:ignore="RelativeOverlap,TextContrastCheck" />
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="wrap_content"
@ -77,6 +77,7 @@
android:text="@string/forward_sms_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
@ -89,7 +90,7 @@
</LinearLayout>
<LinearLayout
style="@style/BarStyle"
style="@style/BarStyle.Switch"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -260,7 +261,7 @@
</LinearLayout>
<LinearLayout
style="@style/BarStyle"
style="@style/BarStyle.Switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
@ -290,7 +291,8 @@
android:layout_width="match_parent"
android:layout_height="25dp"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="horizontal"
tools:ignore="TextSizeCheck">
<TextView
android:layout_width="wrap_content"
@ -304,7 +306,8 @@
android:id="@+id/scb_cancel_app_notify"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary" />
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="wrap_content"
@ -318,7 +321,8 @@
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary" />
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="wrap_content"
@ -344,7 +348,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
@ -366,7 +370,7 @@
</LinearLayout>
<LinearLayout
style="@style/BarStyle"
style="@style/BarStyle.Switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
@ -413,7 +417,7 @@
android:id="@+id/layout_location_setting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical">
<View
@ -589,7 +593,7 @@
</LinearLayout>
<LinearLayout
style="@style/BarStyle"
style="@style/BarStyle.Switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
@ -618,7 +622,8 @@
android:id="@+id/et_safe_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/safe_phone_tips" />
android:hint="@string/safe_phone_tips"
tools:ignore="TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
@ -632,7 +637,7 @@
</LinearLayout>
<LinearLayout
style="@style/BarStyle"
style="@style/BarStyle.Switch"
android:layout_width="match_parent"
android:layout_height="wrap_content">

View File

@ -66,49 +66,56 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/second" />
android:text="@string/second"
android:textSize="@dimen/text_size_mini" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/minute" />
android:text="@string/minute"
android:textSize="@dimen/text_size_mini" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/hour" />
android:text="@string/hour"
android:textSize="@dimen/text_size_mini" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/day" />
android:text="@string/day"
android:textSize="@dimen/text_size_mini" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/month" />
android:text="@string/month"
android:textSize="@dimen/text_size_mini" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/week" />
android:text="@string/week"
android:textSize="@dimen/text_size_mini" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/year" />
android:text="@string/year"
android:textSize="@dimen/text_size_mini" />
</LinearLayout>
<View

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/xui_config_color_white"
android:orientation="vertical"
tools:ignore="UseCompoundDrawables">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/xui_config_color_separator_light" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="24dp"
android:layout_height="24dp"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_frpc_image"
android:layout_width="24dp"
android:layout_height="24dp"
tools:ignore="ContentDescription,UseAppTint" />
<ImageView
android:id="@+id/iv_frpc_status"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginStart="14dp"
android:layout_marginTop="-10dp"
tools:ignore="ContentDescription" />
</LinearLayout>
<TextView
android:id="@+id/tv_frpc_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:ellipsize="marquee"
android:minHeight="?attr/ms_item_height_size"
android:paddingStart="?attr/ms_padding_left_size"
android:paddingTop="?attr/ms_padding_top_size"
android:paddingEnd="?attr/ms_padding_left_size"
android:paddingBottom="?attr/ms_padding_top_size"
android:singleLine="true"
tools:ignore="PrivateResource" />
<ImageView
android:id="@+id/iv_remove_frpc"
android:layout_width="18dp"
android:layout_height="18dp"
android:contentDescription="@string/frpc_del"
android:src="@drawable/ic_delete"
app:tint="#F15C58" />
</LinearLayout>
</LinearLayout>

View File

@ -28,7 +28,7 @@
android:id="@+id/iv_rule_image"
android:layout_width="24dp"
android:layout_height="24dp"
tools:ignore="ContentDescription" />
tools:ignore="ContentDescription,UseAppTint" />
<ImageView
android:id="@+id/iv_rule_status"

View File

@ -21,9 +21,6 @@
<string name="app_browser_name">Universal Browser</string>
<string name="description_navigation_main">navigation</string>
<string name="guide_key_sliding_root_navigation">guide_key_sliding_root_navigation</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="menu_logs">Logs</string>
<string name="menu_senders">Senders</string>
@ -234,8 +231,11 @@
<string name="delete_rule_tips">Are you sure to delete this rule?</string>
<string name="delete_rule_toast">The rule has deleted.</string>
<string name="new_sender_first">Please add a new sender and then choose it.</string>
<string name="new_rule_first">Please add a new rule and then choose it.</string>
<string name="new_frpc_first">Please add a new frpc and then choose it.</string>
<string name="add_sender_first">Please add a sender first.</string>
<string name="add_rule_first">Please add a rule first.</string>
<string name="add_frpc_first">Please add a frpc first.</string>
<string name="select_sender">Select Sender</string>
<string name="rule_tester">Rule tester:</string>
<string name="test_sim_slot">Test SIM Slot</string>
@ -336,7 +336,7 @@
<string name="Customize_API">Customize API</string>
<string name="Corp_ID">Corp ID</string>
<string name="Agent_ID">Agent ID</string>
<string name="App_Secret">App Secret</string>
<string name="App_Secret">Secret</string>
<string name="is_at_all">Is At All</string>
<string name="specified_member">Specified Member</string>
<string name="at_all">\@all</string>
@ -826,6 +826,7 @@
<string name="pushplus_token_hint">Please go to the corresponding official website to obtain</string>
<string name="choose_rule">Drop-down selection, keyword fuzzy match</string>
<string name="choose_sender">Drop-down selection, keyword fuzzy match</string>
<string name="choose_frpc">Drop-down selection, keyword fuzzy match</string>
<string name="choose_app">Installed Apps</string>
<string name="extra_app">Extra Apps</string>
<string name="extra_app_hint">One package name per line\nEnable async loading of the App list for selection.</string>
@ -976,6 +977,7 @@
<string name="rule_disabled_tips">[Note] The rule has been disabled, will not be sent even if they match!</string>
<string name="sender_contains_tips">[Note] The sending channel is already in the list, no need to add it again!</string>
<string name="rule_contains_tips">[Note] The rule is already in the list, no need to add it again!</string>
<string name="frpc_contains_tips">[Note] The frpc is already in the list, no need to add it again!</string>
<string name="local_call">Local Call:</string>
<string name="remote_sms">Remote SMS</string>
<string name="clear">Clear</string>
@ -1087,6 +1089,7 @@
<string name="rule_del">Del Rule</string>
<string name="sender_del">Del Sender</string>
<string name="frpc_del">Del Frpc</string>
<string name="sender_disabled">Sender is disabled</string>
<string name="unknown_sender">Unknown sender</string>
<string name="network_type">Network Type</string>
@ -1176,10 +1179,10 @@
<string name="task_lock_screen">Screen Off/On</string>
<string name="task_lock_screen_tips">Trigger upon screen lock/unlock instantly or after a set time.</string>
<string name="task_sendsms">Send Sms</string>
<string name="task_notification">Notification</string>
<string name="task_frpc">Frpc Setting</string>
<string name="task_notification">Notify</string>
<string name="task_frpc">Frpc On/Off</string>
<string name="task_frpc_tips">Control the start/stop of FRPC.</string>
<string name="task_http_server">Server Setting</string>
<string name="task_http_server">Server On/Off</string>
<string name="task_http_server_tips">Manage HttpServer start/stop and enable/disable functions</string>
<string name="task_cleaner">Cleaner</string>
<string name="task_cleaner_tips">Delete FW. logs older than N days, delete cache, etc.</string>
@ -1314,4 +1317,6 @@
<string name="english">English</string>
<string name="log_export_failed">Log Export Failed!</string>
<string name="log_export_success">Log exported successfully! Path:</string>
<string name="all_auto_started_frpc">All auto-started Frpc</string>
<string name="specified_frpc">Specified Frpc</string>
</resources>

View File

@ -21,9 +21,6 @@
<string name="app_browser_name">通用浏览器</string>
<string name="description_navigation_main">导航条</string>
<string name="guide_key_sliding_root_navigation">guide_key_sliding_root_navigation</string>
<string name="navigation_drawer_open">打开导航抽屉</string>
<string name="navigation_drawer_close">关闭导航抽屉</string>
<string name="menu_logs">转发日志</string>
<string name="menu_senders">发送通道</string>
@ -235,8 +232,11 @@
<string name="delete_rule_tips">删除转发规则后会级联删除其相关的转发日志的所有记录!\n\n确定删除该条规则?</string>
<string name="delete_rule_toast">该条规则已经删除!</string>
<string name="new_sender_first">请选择发送通道(若无,请先添加)</string>
<string name="new_rule_first">请选择发送通道(若无,请先添加)</string>
<string name="new_frpc_first">请选择发送通道(若无,请先添加)</string>
<string name="add_sender_first">请先去设置发送通道页面添加</string>
<string name="add_rule_first">请先去设置转发规则页面添加</string>
<string name="add_frpc_first">请先去设置FRPC页面添加</string>
<string name="select_sender">发送通道</string>
<string name="rule_tester">转发规则测试</string>
<string name="test_sim_slot">测试模拟的接收卡槽</string>
@ -345,9 +345,9 @@
<string name="touser">指定成员</string>
<string name="toparty">指定部门</string>
<string name="totag">指定标签</string>
<string name="touser_tips">Tip接收消息的成员ID列表多个接收者用‘|分隔最多支持1000个</string>
<string name="toparty_tips">Tip接收消息的部门ID列表多个接收者用‘|分隔最多支持1000个</string>
<string name="totag_tips">Tip接收消息的标签ID列表多个接收者用‘|分隔最多支持1000个</string>
<string name="touser_tips">Tip接收消息的成员ID列表多个用|分隔最多支持1000个</string>
<string name="toparty_tips">Tip接收消息的部门ID列表多个用|分隔最多支持1000个</string>
<string name="totag_tips">Tip接收消息的标签ID列表多个用|分隔最多支持1000个</string>
<string name="customize_api_tips">Tip通过反向代理(proxy_pass)绕过IP白名单限制</string>
<string name="specified_member_tips2">Tip接收用户的userid每次最多传20个|’分隔)</string>
<string name="server_chan_send_key">SendKey</string>
@ -827,6 +827,7 @@
<string name="pushplus_token_hint">请前往对应的官网地址获取</string>
<string name="choose_rule">下拉选择,关键字模糊匹配</string>
<string name="choose_sender">下拉选择,关键字模糊匹配</string>
<string name="choose_frpc">下拉选择,关键字模糊匹配</string>
<string name="choose_app">已装APP列表</string>
<string name="extra_app">额外消除应用通知</string>
<string name="extra_app_hint">一行一个包名\n开启异步加载App列表以便选择</string>
@ -977,6 +978,7 @@
<string name="rule_disabled_tips">【注意】该转发规则已经禁用,即便匹配上也不会发送!</string>
<string name="sender_contains_tips">【注意】该发送通道已经在列表中,无需重复添加!</string>
<string name="rule_contains_tips">【注意】该转发规则已经在列表中,无需重复添加!</string>
<string name="frpc_contains_tips">【注意】该Frpc已经在列表中无需重复添加</string>
<string name="local_call">本地呼叫:</string>
<string name="remote_sms">远程发短信:</string>
<string name="clear">清除</string>
@ -1088,6 +1090,7 @@
<string name="rule_del">删除转发规则</string>
<string name="sender_del">删除发送通道</string>
<string name="frpc_del">删除Frpc</string>
<string name="sender_disabled">发送通道已禁用</string>
<string name="unknown_sender">未知发送通道</string>
<string name="network_type">网络类型</string>
@ -1178,9 +1181,9 @@
<string name="task_lock_screen_tips">在屏幕锁定或解锁后立即或指定时间触发</string>
<string name="task_sendsms">发送短信</string>
<string name="task_notification">推送通知</string>
<string name="task_frpc">Frpc设置</string>
<string name="task_frpc">启停Frpc</string>
<string name="task_frpc_tips">控制内网穿透·FRPC的启动/停止</string>
<string name="task_http_server">HttpServer设置</string>
<string name="task_http_server">启停HttpServer</string>
<string name="task_http_server_tips">控制HttpServer的启动/停止,并支持启用/禁用功能</string>
<string name="task_cleaner">清理日志</string>
<string name="task_cleaner_tips">批量删除N天前的转发记录、删除缓存等</string>
@ -1315,4 +1318,6 @@
<string name="english">English</string>
<string name="log_export_failed">导出日志失败!</string>
<string name="log_export_success">导出日志成功!存放路径:</string>
<string name="all_auto_started_frpc">所有自启动的Frpc</string>
<string name="specified_frpc">指定的Frpc</string>
</resources>

View File

@ -21,9 +21,6 @@
<string name="app_browser_name">通用瀏覽器</string>
<string name="description_navigation_main">導航列</string>
<string name="guide_key_sliding_root_navigation">guide_key_sliding_root_navigation</string>
<string name="navigation_drawer_open">打開導航抽屜</string>
<string name="navigation_drawer_close">關閉導航抽屜</string>
<string name="menu_logs">轉發日誌</string>
<string name="menu_senders">發送通道</string>
@ -235,8 +232,11 @@
<string name="delete_rule_tips">刪除轉發規則後會級聯刪除其相關的轉發日誌的所有記錄!\n\n確定刪除該條規則?</string>
<string name="delete_rule_toast">該條規則已刪除!</string>
<string name="new_sender_first">請選擇發送通道(若無,請先添加)</string>
<string name="new_rule_first">請選擇轉發規則(若無,請先添加)</string>
<string name="new_frpc_first">請選擇FRPC若無請先添加</string>
<string name="add_sender_first">請先去設置發送通道頁面添加</string>
<string name="add_rule_first">請先去設置轉發規則頁面添加</string>
<string name="add_frpc_first">請先去設置FRPC頁面添加</string>
<string name="select_sender">發送通道</string>
<string name="rule_tester">轉發規則測試</string>
<string name="test_sim_slot">測試模擬的接收卡槽</string>
@ -345,9 +345,9 @@
<string name="touser">指定成員</string>
<string name="toparty">指定部門</string>
<string name="totag">指定標籤</string>
<string name="touser_tips">Tip接收消息的成員ID列表多個接收者用‘|分隔最多支持1000個</string>
<string name="toparty_tips">Tip接收消息的部門ID列表多個接收者用‘|分隔最多支持1000個</string>
<string name="totag_tips">Tip接收消息的標籤ID列表多個接收者用‘|分隔最多支持1000個</string>
<string name="touser_tips">Tip接收消息的成員ID列表多個用|分隔最多支持1000個</string>
<string name="toparty_tips">Tip接收消息的部門ID列表多個用|分隔最多支持1000個</string>
<string name="totag_tips">Tip接收消息的標籤ID列表多個用|分隔最多支持1000個</string>
<string name="customize_api_tips">Tip通過反向代理(proxy_pass)繞過IP白名單限制</string>
<string name="specified_member_tips2">Tip接收用戶的userid每次最多傳20個|’分隔)</string>
<string name="server_chan_send_key">SendKey</string>
@ -827,6 +827,7 @@
<string name="pushplus_token_hint">請前往對應的官網地址獲取</string>
<string name="choose_rule">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_sender">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_frpc">下拉選擇,關鍵字模糊匹配</string>
<string name="choose_app">已裝APP列表</string>
<string name="extra_app">額外消除應用通知</string>
<string name="extra_app_hint">一行一個包名\n開啟異步加載App列表以便選擇</string>
@ -977,6 +978,7 @@
<string name="rule_disabled_tips">【注意】該轉發規則已經禁用,即便匹配上也不會發送!</string>
<string name="sender_contains_tips">【注意】該發送通道已經在列表中,無需重複添加!</string>
<string name="rule_contains_tips">【注意】該轉發規則已經在列表中,無需重複添加!</string>
<string name="frpc_contains_tips">【注意】該Frpc已經在列表中無需重複添加</string>
<string name="local_call">本地呼叫:</string>
<string name="remote_sms">遠程發簡訊:</string>
<string name="clear">清除</string>
@ -1088,6 +1090,7 @@
<string name="rule_del">刪除轉發規則</string>
<string name="sender_del">刪除發送通道</string>
<string name="frpc_del">刪除Frpc</string>
<string name="sender_disabled">發送通道已停用</string>
<string name="unknown_sender">未知的發送通道</string>
<string name="network_type">網絡類型</string>
@ -1178,9 +1181,9 @@
<string name="task_lock_screen_tips">在屏幕鎖定或解鎖後立即或指定時間觸發</string>
<string name="task_sendsms">發送簡訊</string>
<string name="task_notification">推送通知</string>
<string name="task_frpc">Frpc設置</string>
<string name="task_frpc">啟停Frpc</string>
<string name="task_frpc_tips">控制內網穿透·FRPC的啟動/停止</string>
<string name="task_http_server">HttpServer設置</string>
<string name="task_http_server">啟停HttpServer</string>
<string name="task_http_server_tips">控制HttpServer的啟動/停止,並支持啟用/禁用功能</string>
<string name="task_cleaner">清理日誌</string>
<string name="task_cleaner_tips">批量刪除N天前的轉發記錄、刪除快取等</string>
@ -1316,4 +1319,6 @@
<string name="english">English</string>
<string name="log_export_failed">日誌匯出失敗!</string>
<string name="log_export_success">日誌匯出成功!儲存路徑:</string>
<string name="all_auto_started_frpc">所有自動啟動的Frpc</string>
<string name="specified_frpc">特定的Frpc</string>
</resources>

View File

@ -21,9 +21,6 @@
<string name="app_browser_name">通用浏览器</string>
<string name="description_navigation_main">导航条</string>
<string name="guide_key_sliding_root_navigation">guide_key_sliding_root_navigation</string>
<string name="navigation_drawer_open">打开导航抽屉</string>
<string name="navigation_drawer_close">关闭导航抽屉</string>
<string name="menu_logs">转发日志</string>
<string name="menu_senders">发送通道</string>
@ -235,8 +232,11 @@
<string name="delete_rule_tips">删除转发规则后会级联删除其相关的转发日志的所有记录!\n\n确定删除该条规则?</string>
<string name="delete_rule_toast">该条规则已经删除!</string>
<string name="new_sender_first">请选择发送通道(若无,请先添加)</string>
<string name="new_rule_first">请选择转发规则(若无,请先添加)</string>
<string name="new_frpc_first">请选择Frpc若无请先添加</string>
<string name="add_sender_first">请先去设置发送通道页面添加</string>
<string name="add_rule_first">请先去设置转发规则页面添加</string>
<string name="add_frpc_first">请先去设置Frpc页面添加</string>
<string name="select_sender">发送通道</string>
<string name="rule_tester">转发规则测试</string>
<string name="test_sim_slot">测试模拟的接收卡槽</string>
@ -345,9 +345,9 @@
<string name="touser">指定成员</string>
<string name="toparty">指定部门</string>
<string name="totag">指定标签</string>
<string name="touser_tips">Tip接收消息的成员ID列表多个接收者用‘|分隔最多支持1000个</string>
<string name="toparty_tips">Tip接收消息的部门ID列表多个接收者用‘|分隔最多支持1000个</string>
<string name="totag_tips">Tip接收消息的标签ID列表多个接收者用‘|分隔最多支持1000个</string>
<string name="touser_tips">Tip接收消息的成员ID列表多个用|分隔最多支持1000个</string>
<string name="toparty_tips">Tip接收消息的部门ID列表多个用|分隔最多支持1000个</string>
<string name="totag_tips">Tip接收消息的标签ID列表多个用|分隔最多支持1000个</string>
<string name="customize_api_tips">Tip通过反向代理(proxy_pass)绕过IP白名单限制</string>
<string name="specified_member_tips2">Tip接收用户的userid每次最多传20个|’分隔)</string>
<string name="server_chan_send_key">SendKey</string>
@ -827,6 +827,7 @@
<string name="pushplus_token_hint">请前往对应的官网地址获取</string>
<string name="choose_rule">下拉选择,关键字模糊匹配</string>
<string name="choose_sender">下拉选择,关键字模糊匹配</string>
<string name="choose_frpc">下拉选择,关键字模糊匹配</string>
<string name="choose_app">已装APP列表</string>
<string name="extra_app">额外消除应用通知</string>
<string name="extra_app_hint">一行一个包名\n开启异步加载App列表以便选择</string>
@ -977,6 +978,7 @@
<string name="rule_disabled_tips">【注意】该转发规则已经禁用,即便匹配上也不会发送!</string>
<string name="sender_contains_tips">【注意】该发送通道已经在列表中,无需重复添加!</string>
<string name="rule_contains_tips">【注意】该转发规则已经在列表中,无需重复添加!</string>
<string name="frpc_contains_tips">【注意】该Frpc已经在列表中无需重复添加</string>
<string name="local_call">本地呼叫:</string>
<string name="remote_sms">远程发短信:</string>
<string name="clear">清除</string>
@ -1088,6 +1090,7 @@
<string name="rule_del">删除转发规则</string>
<string name="sender_del">删除发送通道</string>
<string name="frpc_del">删除Frpc</string>
<string name="sender_disabled">发送通道已禁用</string>
<string name="unknown_sender">未知发送通道</string>
<string name="network_type">网络类型</string>
@ -1178,9 +1181,9 @@
<string name="task_lock_screen_tips">在屏幕锁定或解锁后立即或指定时间触发</string>
<string name="task_sendsms">发送短信</string>
<string name="task_notification">推送通知</string>
<string name="task_frpc">Frpc设置</string>
<string name="task_frpc">启停Frpc</string>
<string name="task_frpc_tips">控制内网穿透·FRPC的启动/停止</string>
<string name="task_http_server">HttpServer设置</string>
<string name="task_http_server">启停HttpServer</string>
<string name="task_http_server_tips">控制HttpServer的启动/停止,并支持启用/禁用功能</string>
<string name="task_cleaner">清理日志</string>
<string name="task_cleaner_tips">批量删除N天前的转发记录、删除缓存等</string>
@ -1315,4 +1318,6 @@
<string name="english">English</string>
<string name="log_export_failed">导出日志失败!</string>
<string name="log_export_success">导出日志成功!存放路径:</string>
<string name="all_auto_started_frpc">所有自启动的Frpc</string>
<string name="specified_frpc">指定的Frpc</string>
</resources>