新增:转发日志增加筛选器方便搜索/批量删除 #433

This commit is contained in:
pppscn 2024-04-05 00:24:29 +08:00
parent 75b0e48815
commit 5e0537e1e2
10 changed files with 715 additions and 139 deletions

View File

@ -1,7 +1,15 @@
package com.idormy.sms.forwarder.database.dao package com.idormy.sms.forwarder.database.dao
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.room.* import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Transaction
import androidx.room.Update
import androidx.sqlite.db.SupportSQLiteQuery
import com.idormy.sms.forwarder.database.entity.Msg import com.idormy.sms.forwarder.database.entity.Msg
import com.idormy.sms.forwarder.database.entity.MsgAndLogs import com.idormy.sms.forwarder.database.entity.MsgAndLogs
import io.reactivex.Completable import io.reactivex.Completable
@ -22,6 +30,9 @@ interface MsgDao {
@Query("DELETE FROM Msg where type=:type") @Query("DELETE FROM Msg where type=:type")
fun deleteAll(type: String): Completable fun deleteAll(type: String): Completable
@RawQuery
fun deleteAll(sql: SupportSQLiteQuery): Int
@Query("DELETE FROM Msg") @Query("DELETE FROM Msg")
fun deleteAll() fun deleteAll()
@ -41,4 +52,8 @@ interface MsgDao {
@Query("SELECT * FROM Msg WHERE type = :type ORDER BY id DESC") @Query("SELECT * FROM Msg WHERE type = :type ORDER BY id DESC")
fun pagingSource(type: String): PagingSource<Int, MsgAndLogs> fun pagingSource(type: String): PagingSource<Int, MsgAndLogs>
@Transaction
@RawQuery(observedEntities = [MsgAndLogs::class])
fun pagingSource(query: SupportSQLiteQuery): PagingSource<Int, MsgAndLogs>
} }

View File

@ -6,19 +6,27 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig import androidx.paging.PagingConfig
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import androidx.sqlite.db.SimpleSQLiteQuery
import com.idormy.sms.forwarder.database.dao.MsgDao import com.idormy.sms.forwarder.database.dao.MsgDao
import com.idormy.sms.forwarder.database.entity.MsgAndLogs import com.idormy.sms.forwarder.database.entity.MsgAndLogs
import com.idormy.sms.forwarder.database.ext.ioThread import com.idormy.sms.forwarder.database.ext.ioThread
import com.xuexiang.xutil.data.DateUtils
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
class MsgViewModel(private val dao: MsgDao) : ViewModel() { class MsgViewModel(private val dao: MsgDao) : ViewModel() {
private var type: String = "sms" private var type: String = "sms"
private var filter: MutableMap<String, Any> = mutableMapOf()
fun setType(type: String): MsgViewModel { fun setType(type: String): MsgViewModel {
this.type = type this.type = type
return this return this
} }
fun setFilter(filter: MutableMap<String, Any>): MsgViewModel {
this.filter = filter
return this
}
val allMsg: Flow<PagingData<MsgAndLogs>> = Pager( val allMsg: Flow<PagingData<MsgAndLogs>> = Pager(
config = PagingConfig( config = PagingConfig(
pageSize = 10, pageSize = 10,
@ -26,11 +34,69 @@ class MsgViewModel(private val dao: MsgDao) : ViewModel() {
initialLoadSize = 10 initialLoadSize = 10
) )
) { ) {
dao.pagingSource(type) if (filter.isEmpty()) {
dao.pagingSource(type)
} else {
val sb = StringBuilder().apply {
append("SELECT * FROM Msg WHERE type = '$type'")
append(getOtherCondition())
append(" ORDER BY id DESC")
}
//Log.d("MsgViewModel", "sql: $sb")
val query = SimpleSQLiteQuery(sb.toString())
dao.pagingSource(query)
}
}.flow.cachedIn(viewModelScope) }.flow.cachedIn(viewModelScope)
fun delete(id: Long) = ioThread { fun delete(id: Long) = ioThread {
dao.delete(id) dao.delete(id)
} }
fun deleteAll() = ioThread {
if (filter.isEmpty()) {
dao.deleteAll(type)
} else {
val sb = StringBuilder().apply {
append("DELETE FROM Msg WHERE type = '$type'")
append(getOtherCondition())
}
//Log.d("MsgViewModel", "sql: $sb")
val query = SimpleSQLiteQuery(sb.toString())
dao.deleteAll(query)
}
}
private fun getOtherCondition(): String {
return StringBuilder().apply {
filter["from"]?.toString()?.takeIf { it.isNotEmpty() }?.let { append(" AND `from` LIKE '%$it%'") }
filter["content"]?.toString()?.takeIf { it.isNotEmpty() }?.let { append(" AND content LIKE '%$it%'") }
filter["title"]?.toString()?.takeIf { it.isNotEmpty() }?.let { append(" AND sim_info LIKE '%$it%'") }
filter["start_time"]?.toString()?.takeIf { it.isNotEmpty() }?.let {
val date = DateUtils.string2Date(it, DateUtils.yyyyMMddHHmmss.get())
append(" AND time >= '${date.time}'")
}
filter["end_time"]?.toString()?.takeIf { it.isNotEmpty() }?.let {
val date = DateUtils.string2Date(it, DateUtils.yyyyMMddHHmmss.get())
append(" AND time <= '${date.time}'")
}
if (filter["sim_slot"] is Int && filter["sim_slot"] != -1) {
append(" AND sim_slot = ${filter["sim_slot"]}")
}
val callTypeFilter = filter["call_type"] as? MutableList<*>
if (!callTypeFilter.isNullOrEmpty()) {
val callTypeString = callTypeFilter.joinToString(",") { it.toString() }
append(" AND call_type IN ($callTypeString)")
}
val forwardStatusFilter = filter["forward_status"] as? MutableList<*>
if (!forwardStatusFilter.isNullOrEmpty()) {
val forwardStatusString = forwardStatusFilter.joinToString(",") { it.toString() }
val subSql = "SELECT DISTINCT msg_id FROM Logs WHERE type = '$type' and forward_status IN ($forwardStatusString)"
append(" AND id in ($subSql)")
}
}.toString()
}
} }

View File

@ -99,25 +99,32 @@ data class MsgInfo(
) )
.replaceTag(getString(R.string.tag_device_name), extraDeviceMark.trim(), needJson) .replaceTag(getString(R.string.tag_device_name), extraDeviceMark.trim(), needJson)
.replaceTag(getString(R.string.tag_app_version), AppUtils.getAppVersionName(), needJson) .replaceTag(getString(R.string.tag_app_version), AppUtils.getAppVersionName(), needJson)
.replaceTag(getString(R.string.tag_call_type), .replaceTag(
CALL_TYPE_MAP[callType.toString()] ?: getString(R.string.unknown_call), needJson) getString(R.string.tag_call_type),
CALL_TYPE_MAP[callType.toString()] ?: getString(R.string.unknown_call), needJson
)
.replaceTag(getString(R.string.tag_ipv4), TaskUtils.ipv4, needJson) .replaceTag(getString(R.string.tag_ipv4), TaskUtils.ipv4, needJson)
.replaceTag(getString(R.string.tag_ipv6), TaskUtils.ipv6, needJson) .replaceTag(getString(R.string.tag_ipv6), TaskUtils.ipv6, needJson)
.replaceTag(getString(R.string.tag_battery_pct), "%.0f%%".format(TaskUtils.batteryPct), needJson) .replaceTag(getString(R.string.tag_battery_pct), "%.0f%%".format(TaskUtils.batteryPct), needJson)
.replaceTag(getString(R.string.tag_battery_status), BatteryUtils.getStatus(TaskUtils.batteryStatus), needJson) .replaceTag(getString(R.string.tag_battery_status), BatteryUtils.getStatus(TaskUtils.batteryStatus), needJson)
.replaceTag(getString(R.string.tag_battery_plugged), BatteryUtils.getPlugged(TaskUtils.batteryPlugged), needJson) .replaceTag(getString(R.string.tag_battery_plugged), BatteryUtils.getPlugged(TaskUtils.batteryPlugged), needJson)
.replaceTag(getString(R.string.tag_battery_info), TaskUtils.batteryInfo, needJson) .replaceTag(getString(R.string.tag_battery_info), TaskUtils.batteryInfo, needJson)
.replaceTag(getString(R.string.tag_battery_info_simple), .replaceTag(
getString(R.string.tag_battery_info_simple),
"%.0f%%".format(TaskUtils.batteryPct) "%.0f%%".format(TaskUtils.batteryPct)
+ with(BatteryUtils.getPlugged(TaskUtils.batteryPlugged)) { + with(BatteryUtils.getPlugged(TaskUtils.batteryPlugged)) {
if (this == getString(R.string.battery_unknown)) "" else " - $this" if (this == getString(R.string.battery_unknown)) "" else " - $this"
} },
needJson
)
.replaceTag(
getString(R.string.tag_net_type), with(NetworkUtils.getNetStateType()) {
if (this == NetworkUtils.NetState.NET_NO || this == NetworkUtils.NetState.NET_UNKNOWN)
this.name
this.name.removePrefix("NET_")
},
needJson
) )
.replaceTag(getString(R.string.tag_net_type), with(NetworkUtils.getNetStateType()) {
if (this == NetworkUtils.NetState.NET_NO || this == NetworkUtils.NetState.NET_UNKNOWN)
this.name
this.name.removePrefix("NET_")
})
.replaceAppNameTag(from, needJson) .replaceAppNameTag(from, needJson)
.replaceLocationTag(needJson) .replaceLocationTag(needJson)
.regexReplace(regexReplace) .regexReplace(regexReplace)

View File

@ -1,10 +1,14 @@
package com.idormy.sms.forwarder.fragment package com.idormy.sms.forwarder.fragment
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.text.InputType
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.RadioGroup
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
@ -14,7 +18,6 @@ import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.activity.MainActivity import com.idormy.sms.forwarder.activity.MainActivity
import com.idormy.sms.forwarder.adapter.MsgPagingAdapter import com.idormy.sms.forwarder.adapter.MsgPagingAdapter
import com.idormy.sms.forwarder.core.BaseFragment import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.database.entity.LogsDetail import com.idormy.sms.forwarder.database.entity.LogsDetail
import com.idormy.sms.forwarder.database.entity.MsgAndLogs import com.idormy.sms.forwarder.database.entity.MsgAndLogs
import com.idormy.sms.forwarder.database.entity.Rule import com.idormy.sms.forwarder.database.entity.Rule
@ -28,20 +31,24 @@ import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.xuexiang.xaop.annotation.SingleClick import com.xuexiang.xaop.annotation.SingleClick
import com.xuexiang.xpage.annotation.Page import com.xuexiang.xpage.annotation.Page
import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.actionbar.TitleBar
import com.xuexiang.xui.widget.button.SmoothCheckBox
import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
import com.xuexiang.xui.widget.picker.widget.TimePickerView
import com.xuexiang.xui.widget.picker.widget.builder.TimePickerBuilder
import com.xuexiang.xui.widget.picker.widget.configure.TimePickerType
import com.xuexiang.xutil.data.DateUtils import com.xuexiang.xutil.data.DateUtils
import com.xuexiang.xutil.resource.ResUtils.getColors import com.xuexiang.xutil.resource.ResUtils.getColors
import com.xuexiang.xutil.resource.ResUtils.getStringArray import com.xuexiang.xutil.resource.ResUtils.getStringArray
import io.reactivex.CompletableObserver import com.xuexiang.xutil.tip.ToastUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale import java.util.Locale
@Suppress("PrivatePropertyName") @Suppress("PrivatePropertyName")
@Page(name = "转发日志") @Page(name = "转发日志")
class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnItemClickListener { class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnItemClickListener {
@ -52,6 +59,11 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
private val viewModel by viewModels<MsgViewModel> { BaseViewModelFactory(context) } private val viewModel by viewModels<MsgViewModel> { BaseViewModelFactory(context) }
private var currentType: String = "sms" private var currentType: String = "sms"
//日志筛选
private var currentFilter: MutableMap<String, Any> = mutableMapOf()
private var logsFilterPopup: MaterialDialog? = null
private var timePicker: TimePickerView? = null
override fun viewBindingInflate( override fun viewBindingInflate(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup, container: ViewGroup,
@ -68,27 +80,28 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
@SingleClick @SingleClick
override fun performAction(view: View) { override fun performAction(view: View) {
MaterialDialog.Builder(requireContext()) MaterialDialog.Builder(requireContext())
.content(R.string.delete_type_log_tips) .content(if (currentFilter.isEmpty()) R.string.delete_type_log_tips else R.string.delete_filter_log_tips)
.positiveText(R.string.lab_yes) .positiveText(R.string.lab_yes)
.negativeText(R.string.lab_no) .negativeText(R.string.lab_no)
.onPositive { _: MaterialDialog?, _: DialogAction? -> .onPositive { _: MaterialDialog?, _: DialogAction? ->
Core.msg.deleteAll(currentType) try {
.subscribeOn(Schedulers.io()) viewModel.setType(currentType).setFilter(currentFilter).deleteAll()
.observeOn(AndroidSchedulers.mainThread()) reloadData()
.subscribe(object : CompletableObserver { XToastUtils.success(if (currentFilter.isEmpty()) R.string.delete_type_log_toast else R.string.delete_filter_log_toast)
override fun onSubscribe(d: Disposable) {} } catch (e: Exception) {
override fun onComplete() { e.message?.let { XToastUtils.error(it) }
XToastUtils.success(R.string.delete_type_log_toast) }
}
override fun onError(e: Throwable) {
e.message?.let { XToastUtils.error(it) }
}
})
} }
.show() .show()
} }
}) })
titleBar!!.addAction(object : TitleBar.ImageAction(R.drawable.ic_filter) {
@SingleClick
override fun performAction(view: View) {
initLogsFilterDialog()
logsFilterPopup?.show()
}
})
return titleBar return titleBar
} }
@ -115,9 +128,8 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
2 -> "app" 2 -> "app"
else -> "sms" else -> "sms"
} }
viewModel.setType(currentType) initLogsFilterDialog(true)
adapter.refresh() reloadData()
binding!!.recyclerView.scrollToPosition(0)
} }
} }
@ -128,7 +140,7 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
binding!!.refreshLayout.setOnRefreshListener { refreshLayout: RefreshLayout -> binding!!.refreshLayout.setOnRefreshListener { refreshLayout: RefreshLayout ->
//adapter.refresh() //adapter.refresh()
lifecycleScope.launch { lifecycleScope.launch {
viewModel.setType(currentType).allMsg.collectLatest { adapter.submitData(it) } viewModel.setType(currentType).setFilter(currentFilter).allMsg.collectLatest { adapter.submitData(it) }
} }
refreshLayout.finishRefresh() refreshLayout.finishRefresh()
} }
@ -186,11 +198,6 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
.title(R.string.details) .title(R.string.details)
.content(detailStr.toString()) .content(detailStr.toString())
.cancelable(true) .cancelable(true)
/*.positiveText(R.string.del)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
viewModel.delete(item.id)
XToastUtils.success(R.string.delete_log_toast)
}*/
.negativeText(R.string.resend) .negativeText(R.string.resend)
.onNegative { _: MaterialDialog?, _: DialogAction? -> .onNegative { _: MaterialDialog?, _: DialogAction? ->
XToastUtils.toast(R.string.resend_toast) XToastUtils.toast(R.string.resend_toast)
@ -201,4 +208,138 @@ class LogsFragment : BaseFragment<FragmentLogsBinding?>(), MsgPagingAdapter.OnIt
override fun onItemRemove(view: View?, id: Int) {} override fun onItemRemove(view: View?, id: Int) {}
private fun reloadData() {
viewModel.setType(currentType).setFilter(currentFilter)
adapter.refresh()
binding!!.recyclerView.scrollToPosition(0)
}
private fun initLogsFilterDialog(needInit: Boolean = false) {
if (logsFilterPopup == null || needInit) {
currentFilter = mutableMapOf()
val logsFilterDialog = View.inflate(requireContext(), R.layout.dialog_logs_filter, null)
val layoutTitle = logsFilterDialog.findViewById<LinearLayout>(R.id.layout_title)
val layoutSimSlot = logsFilterDialog.findViewById<LinearLayout>(R.id.layout_sim_slot)
val layoutCallType = logsFilterDialog.findViewById<LinearLayout>(R.id.layout_call_type)
when (currentType) {
"app" -> {
layoutTitle.visibility = View.VISIBLE
layoutSimSlot.visibility = View.GONE
layoutCallType.visibility = View.GONE
}
"call" -> {
layoutTitle.visibility = View.GONE
layoutSimSlot.visibility = View.VISIBLE
layoutCallType.visibility = View.VISIBLE
}
else -> {
layoutTitle.visibility = View.GONE
layoutSimSlot.visibility = View.VISIBLE
layoutCallType.visibility = View.GONE
}
}
val scbCallType1 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_call_type1)
val scbCallType2 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_call_type2)
val scbCallType3 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_call_type3)
val scbCallType4 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_call_type4)
val scbCallType5 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_call_type5)
val scbCallType6 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_call_type6)
val etFrom = logsFilterDialog.findViewById<EditText>(R.id.et_from)
val etContent = logsFilterDialog.findViewById<EditText>(R.id.et_content)
val etTitle = logsFilterDialog.findViewById<EditText>(R.id.et_title)
val rgSimSlot = logsFilterDialog.findViewById<RadioGroup>(R.id.rg_sim_slot)
val etStartTime = logsFilterDialog.findViewById<EditText>(R.id.et_start_time)
val scbForwardStatus0 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_forward_status_0)
val scbForwardStatus1 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_forward_status_1)
val scbForwardStatus2 = logsFilterDialog.findViewById<SmoothCheckBox>(R.id.scb_forward_status_2)
etStartTime.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
showTimePicker(etStartTime.text.toString().trim(), getString(R.string.start_time), etStartTime)
} else {
timePicker?.dismiss()
}
}
val etEndTime = logsFilterDialog.findViewById<EditText>(R.id.et_end_time)
etEndTime.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
showTimePicker(etEndTime.text.toString().trim(), getString(R.string.end_time), etEndTime)
} else {
timePicker?.dismiss()
}
}
logsFilterPopup = MaterialDialog.Builder(requireContext())
.iconRes(android.R.drawable.ic_menu_search)
.title(R.string.menu_logs)
.customView(logsFilterDialog, true)
.cancelable(false)
.autoDismiss(false)
.neutralText(R.string.reset)
.neutralColor(getColors(R.color.darkGrey))
.onNeutral { dialog: MaterialDialog?, _: DialogAction? ->
dialog?.dismiss()
currentFilter = mutableMapOf()
logsFilterPopup = null
reloadData()
}.positiveText(R.string.search).onPositive { dialog: MaterialDialog?, _: DialogAction? ->
currentFilter = mutableMapOf()
currentFilter["from"] = etFrom.text.toString().trim()
currentFilter["content"] = etContent.text.toString().trim()
currentFilter["title"] = etTitle.text.toString().trim()
currentFilter["start_time"] = etStartTime.text.toString().trim()
currentFilter["end_time"] = etEndTime.text.toString().trim()
currentFilter["sim_slot"] = if (currentType == "app") -1 else when (rgSimSlot.checkedRadioButtonId) {
R.id.rb_sim_slot_1 -> 0
R.id.rb_sim_slot_2 -> 1
else -> -1
}
if (currentType == "call") {
currentFilter["call_type"] = mutableListOf<Int>().apply {
if (scbCallType1.isChecked) add(1)
if (scbCallType2.isChecked) add(2)
if (scbCallType3.isChecked) add(3)
if (scbCallType4.isChecked) add(4)
if (scbCallType5.isChecked) add(5)
if (scbCallType6.isChecked) add(6)
}
}
currentFilter["forward_status"] = mutableListOf<Int>().apply {
if (scbForwardStatus0.isChecked) add(0)
if (scbForwardStatus1.isChecked) add(1)
if (scbForwardStatus2.isChecked) add(2)
}
reloadData()
dialog?.dismiss()
}.build()
}
}
private fun showTimePicker(time: String, title: String, et: EditText) {
et.inputType = InputType.TYPE_NULL
val calendar: Calendar = Calendar.getInstance()
calendar.time = try {
if (time.isEmpty()) Date() else DateUtils.string2Date(time, DateUtils.yyyyMMddHHmmss.get())
} catch (e: Exception) {
Date()
}
timePicker = TimePickerBuilder(context) { date, _ ->
ToastUtils.toast(DateUtils.date2String(date, DateUtils.yyyyMMddHHmmss.get()))
et.setText(DateUtils.date2String(date, DateUtils.yyyyMMddHHmmss.get()))
}
.setTimeSelectChangeListener { date ->
Log.i("pvTime", "onTimeSelectChanged")
et.setText(DateUtils.date2String(date, DateUtils.yyyyMMddHHmmss.get()))
}
.setType(TimePickerType.ALL)
.setTitleText(title)
.isDialog(true)
.setOutSideCancelable(false)
.setDate(calendar)
.build()
timePicker?.show(false)
}
} }

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="23dp"
android:height="23dp"
android:viewportWidth="23"
android:viewportHeight="23">
<path
android:fillColor="#ffffffff"
android:pathData="m12.761,21.5c-0.337,0 -0.645,-0.078 -0.941,-0.235L9.255,19.832C8.627,19.492 8.233,18.83 8.24,18.11L8.24,9.934C8.236,9.812 8.178,9.697 8.083,9.625L2.159,4.85 2.095,4.775C1.541,4.218 1.412,3.389 1.722,2.665 2.023,1.952 2.727,1.49 3.497,1.5L19.482,1.5c0.771,0 1.471,0.455 1.79,1.165 0.316,0.71 0.18,1.549 -0.35,2.11l-0.078,0.075 -5.999,4.826c-0.088,0.075 -0.143,0.19 -0.143,0.31v9.548c0.017,1.07 -0.832,1.95 -1.895,1.967zM3.175,3.688 L9.075,8.423c0.462,0.374 0.733,0.93 0.733,1.525v8.176c0,0.143 0.065,0.285 0.194,0.35l2.561,1.41c0.126,0.061 0.276,0.061 0.401,0 0.119,-0.071 0.19,-0.204 0.19,-0.35L13.155,9.998c0,-0.594 0.262,-1.151 0.723,-1.528L19.792,3.688C19.88,3.569 19.894,3.405 19.826,3.273 19.761,3.138 19.625,3.052 19.479,3.052L3.497,3.052C3.352,3.045 3.212,3.134 3.151,3.273 3.08,3.405 3.09,3.565 3.175,3.688ZM20.702,11.809h-4.202c-0.418,-0.01 -0.748,-0.357 -0.741,-0.774 0,-0.428 0.333,-0.775 0.741,-0.775h4.202c0.407,0 0.74,0.347 0.74,0.775 0.017,0.411 -0.305,0.757 -0.713,0.774zM20.702,14.791h-4.202c-0.418,-0.01 -0.748,-0.357 -0.741,-0.774 0,-0.432 0.333,-0.778 0.741,-0.778h4.202c0.407,0 0.74,0.35 0.74,0.778 0.017,0.41 -0.305,0.757 -0.713,0.774zM20.702,17.774h-4.202c-0.418,-0.014 -0.748,-0.36 -0.741,-0.778 0,-0.424 0.333,-0.774 0.741,-0.774h4.202c0.407,0 0.74,0.35 0.74,0.774 0.014,0.418 -0.312,0.764 -0.727,0.778zM20.702,17.774"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,372 @@
<?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="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/from"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_from"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/logs_keyword_hint"
app:met_clearButton="true" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/logs_keyword_hint"
app:met_clearButton="true" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/msg"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/logs_keyword_hint"
app:met_clearButton="true" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/time"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_start_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/start_time"
android:importantForAutofill="no"
android:inputType="none"
android:singleLine="true"
android:textAlignment="center"
android:textSize="@dimen/text_size_mini"
app:met_clearButton="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/config_margin_5dp"
android:text="@string/cyclic_to"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_end_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/config_margin_5dp"
android:layout_weight="1"
android:hint="@string/end_time"
android:importantForAutofill="no"
android:inputType="none"
android:singleLine="true"
android:textAlignment="center"
android:textSize="@dimen/text_size_mini"
app:met_clearButton="true" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_call_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/type"
android:textStyle="bold" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_call_type3"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/missed_call"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_call_type1"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/incoming_call_ended"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_call_type2"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/outgoing_call_ended"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_call_type4"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/incoming_call_received"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_call_type5"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/incoming_call_answered"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_call_type6"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/outgoing_call_started"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_sim_slot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/slot"
android:textStyle="bold" />
<RadioGroup
android:id="@+id/rg_sim_slot"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_sim_slot_0"
style="@style/rg_rb_style"
android:checked="true"
android:text="@string/battery_unlimited" />
<RadioButton
android:id="@+id/rb_sim_slot_1"
style="@style/rg_rb_style"
android:text="@string/sim_1" />
<RadioButton
android:id="@+id/rb_sim_slot_2"
style="@style/rg_rb_style"
android:text="@string/sim_2" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/config_margin_5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/forward_status"
android:textStyle="bold" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_forward_status_2"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/success"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_forward_status_0"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/failed"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_forward_status_1"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/processing"
android:textSize="@dimen/text_size_small"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>

View File

@ -164,6 +164,8 @@
<string name="quit">Quit</string> <string name="quit">Quit</string>
<string name="del">Delete</string> <string name="del">Delete</string>
<string name="save">Save</string> <string name="save">Save</string>
<string name="reset">Reset</string>
<string name="search">Search</string>
<string name="submit">Submit</string> <string name="submit">Submit</string>
<string name="send">Send</string> <string name="send">Send</string>
<string name="test">Test</string> <string name="test">Test</string>
@ -212,6 +214,8 @@
<string name="delete_log_toast">The log entry is deleted.</string> <string name="delete_log_toast">The log entry is deleted.</string>
<string name="delete_type_log_tips">Are you sure you want to delete all log records for this category?</string> <string name="delete_type_log_tips">Are you sure you want to delete all log records for this category?</string>
<string name="delete_type_log_toast">The category log record has been cleared!</string> <string name="delete_type_log_toast">The category log record has been cleared!</string>
<string name="delete_filter_log_tips">Are you sure you want to delete all log records for the current filter?</string>
<string name="delete_filter_log_toast">All log records for the current filter have been deleted!</string>
<string name="resend_toast">Attempting to resend over the original sender</string> <string name="resend_toast">Attempting to resend over the original sender</string>
<string name="rematch_toast">Rematching rule sending</string> <string name="rematch_toast">Rematching rule sending</string>
<string name="details">Details</string> <string name="details">Details</string>
@ -630,33 +634,10 @@
<string name="time">Time: </string> <string name="time">Time: </string>
<string name="result">Result:</string> <string name="result">Result:</string>
<string name="original_result">Ori. Result:</string> <string name="original_result">Ori. Result:</string>
<string name="forward_status">Result:</string>
<string name="success">Success</string> <string name="success">Success</string>
<string name="failed">Failed</string> <string name="failed">Failed</string>
<string name="processing">Processing</string> <string name="processing">Processing</string>
<string name="tag_from">{{FROM}}</string>
<string name="tag_sms">{{SMS}}</string>
<string name="tag_package_name">{{PACKAGE_NAME}}</string>
<string name="tag_app_name">{{APP_NAME}}</string>
<string name="tag_msg">{{MSG}}</string>
<string name="tag_card_slot">{{CARD_SLOT}}</string>
<string name="tag_card_subid">{{CARD_SUBID}}</string>
<string name="tag_receive_time">{{RECEIVE_TIME}}</string>
<string name="tag_current_time">{{CURRENT_TIME}}</string>
<string name="tag_device_name">{{DEVICE_NAME}}</string>
<string name="tag_app_version">{{APP_VERSION}}</string>
<string name="tag_title">{{TITLE}}</string>
<string name="tag_call_type">{{CALL_TYPE}}</string>
<string name="tag_location">{{LOCATION}}</string>
<string name="tag_location_longitude">{{LOCATION_LONGITUDE}}</string>
<string name="tag_location_latitude">{{LOCATION_LATITUDE}}</string>
<string name="tag_location_address">{{LOCATION_ADDRESS}}</string>
<string name="tag_battery_pct">{{BATTERY_PCT}}</string>
<string name="tag_battery_status">{{BATTERY_STATUS}}</string>
<string name="tag_battery_plugged">{{BATTERY_PLUGGED}}</string>
<string name="tag_battery_info">{{BATTERY_INFO}}</string>
<string name="tag_uid">{{UID}}</string>
<string name="tag_ipv4">{{IPV4}}</string>
<string name="tag_ipv6">{{IPV6}}</string>
<string name="rule_sms">SMS</string> <string name="rule_sms">SMS</string>
<string name="rule_call">CALL</string> <string name="rule_call">CALL</string>
<string name="rule_app">APP</string> <string name="rule_app">APP</string>
@ -1022,6 +1003,7 @@
<string name="matched_rule">Matched rule</string> <string name="matched_rule">Matched rule</string>
<string name="copied_to_clipboard">Copied to clipboard:\n%s</string> <string name="copied_to_clipboard">Copied to clipboard:\n%s</string>
<string name="search_keyword">Search Keyword: %s</string> <string name="search_keyword">Search Keyword: %s</string>
<string name="search_condition">Search Condition: %s</string>
<string name="export_succeeded">Export configuration succeeded!</string> <string name="export_succeeded">Export configuration succeeded!</string>
<string name="export_failed">Export failed, please check write permission!</string> <string name="export_failed">Export failed, please check write permission!</string>
<string name="export_failed_tips">Export failed: %s</string> <string name="export_failed_tips">Export failed: %s</string>
@ -1046,6 +1028,7 @@
<string name="main_title">Main title</string> <string name="main_title">Main title</string>
<string name="subtitle">Subtitle</string> <string name="subtitle">Subtitle</string>
<string name="logs_keyword_hint">Input keywords to fuzzy match</string>
<string name="sms_keyword_hint">Input keywords to fuzzy match SMS content</string> <string name="sms_keyword_hint">Input keywords to fuzzy match SMS content</string>
<string name="contact_keyword_hint">Pure numbers match numbers / non-numbers match names</string> <string name="contact_keyword_hint">Pure numbers match numbers / non-numbers match names</string>
<string name="call_keyword_hint">Input keyword to fuzzy match mobile phone number</string> <string name="call_keyword_hint">Input keyword to fuzzy match mobile phone number</string>
@ -1279,7 +1262,9 @@
<string name="cyclic_from_week">From week</string> <string name="cyclic_from_week">From week</string>
<string name="cyclic_to">To</string> <string name="cyclic_to">To</string>
<string name="start">Start</string> <string name="start">Start</string>
<string name="start_time">Start Time</string>
<string name="end">End</string> <string name="end">End</string>
<string name="end_time">End Time</string>
<string name="interval_seconds_1">Starting from</string> <string name="interval_seconds_1">Starting from</string>
<string name="interval_seconds_2">second, execute every</string> <string name="interval_seconds_2">second, execute every</string>
<string name="interval_seconds_3">seconds.</string> <string name="interval_seconds_3">seconds.</string>

View File

@ -165,6 +165,8 @@
<string name="quit">退出</string> <string name="quit">退出</string>
<string name="del">删除</string> <string name="del">删除</string>
<string name="save">保存</string> <string name="save">保存</string>
<string name="reset">重置</string>
<string name="search">搜索</string>
<string name="submit">提交</string> <string name="submit">提交</string>
<string name="send">发送</string> <string name="send">发送</string>
<string name="test">测试</string> <string name="test">测试</string>
@ -213,6 +215,8 @@
<string name="delete_log_toast">该条日志记录已经删除!</string> <string name="delete_log_toast">该条日志记录已经删除!</string>
<string name="delete_type_log_tips">确定删除该分类的所有日志记录?</string> <string name="delete_type_log_tips">确定删除该分类的所有日志记录?</string>
<string name="delete_type_log_toast">该分类日志记录已经清空!</string> <string name="delete_type_log_toast">该分类日志记录已经清空!</string>
<string name="delete_filter_log_tips">确定删除当前筛选的所有日志记录?</string>
<string name="delete_filter_log_toast">当前筛选的所有日志记录已经删除!</string>
<string name="resend_toast">正在尝试通过原发送通道重发</string> <string name="resend_toast">正在尝试通过原发送通道重发</string>
<string name="rematch_toast">正在重新匹配规则发送</string> <string name="rematch_toast">正在重新匹配规则发送</string>
<string name="details">详情</string> <string name="details">详情</string>
@ -631,33 +635,10 @@
<string name="time">时间:</string> <string name="time">时间:</string>
<string name="result">转发结果:</string> <string name="result">转发结果:</string>
<string name="original_result">原转发状态:</string> <string name="original_result">原转发状态:</string>
<string name="forward_status">状态:</string>
<string name="success">成功</string> <string name="success">成功</string>
<string name="failed">失败</string> <string name="failed">失败</string>
<string name="processing">处理中</string> <string name="processing">处理中</string>
<string name="tag_from">{{FROM}}</string>
<string name="tag_sms">{{SMS}}</string>
<string name="tag_package_name">{{PACKAGE_NAME}}</string>
<string name="tag_app_name">{{APP_NAME}}</string>
<string name="tag_msg">{{MSG}}</string>
<string name="tag_card_slot">{{CARD_SLOT}}</string>
<string name="tag_card_subid">{{CARD_SUBID}}</string>
<string name="tag_receive_time">{{RECEIVE_TIME}}</string>
<string name="tag_current_time">{{CURRENT_TIME}}</string>
<string name="tag_device_name">{{DEVICE_NAME}}</string>
<string name="tag_app_version">{{APP_VERSION}}</string>
<string name="tag_title">{{TITLE}}</string>
<string name="tag_call_type">{{CALL_TYPE}}</string>
<string name="tag_location">{{LOCATION}}</string>
<string name="tag_location_longitude">{{LOCATION_LONGITUDE}}</string>
<string name="tag_location_latitude">{{LOCATION_LATITUDE}}</string>
<string name="tag_location_address">{{LOCATION_ADDRESS}}</string>
<string name="tag_battery_pct">{{BATTERY_PCT}}</string>
<string name="tag_battery_status">{{BATTERY_STATUS}}</string>
<string name="tag_battery_plugged">{{BATTERY_PLUGGED}}</string>
<string name="tag_battery_info">{{BATTERY_INFO}}</string>
<string name="tag_uid">{{UID}}</string>
<string name="tag_ipv4">{{IPV4}}</string>
<string name="tag_ipv6">{{IPV6}}</string>
<string name="rule_sms">短信</string> <string name="rule_sms">短信</string>
<string name="rule_call">来电</string> <string name="rule_call">来电</string>
<string name="rule_app">应用</string> <string name="rule_app">应用</string>
@ -1023,6 +1004,7 @@
<string name="matched_rule">匹配中规则</string> <string name="matched_rule">匹配中规则</string>
<string name="copied_to_clipboard">已复制到剪贴板:\n%s</string> <string name="copied_to_clipboard">已复制到剪贴板:\n%s</string>
<string name="search_keyword">搜索关键字: %s</string> <string name="search_keyword">搜索关键字: %s</string>
<string name="search_condition">搜索条件: %s</string>
<string name="export_succeeded">导出配置成功!</string> <string name="export_succeeded">导出配置成功!</string>
<string name="export_failed">导出失败,请检查写入权限!</string> <string name="export_failed">导出失败,请检查写入权限!</string>
<string name="export_failed_tips">导出失败: %s</string> <string name="export_failed_tips">导出失败: %s</string>
@ -1047,6 +1029,7 @@
<string name="main_title">主标题</string> <string name="main_title">主标题</string>
<string name="subtitle">副标题</string> <string name="subtitle">副标题</string>
<string name="logs_keyword_hint">输入关键字模糊匹配</string>
<string name="sms_keyword_hint">输入关键字模糊匹配短信内容</string> <string name="sms_keyword_hint">输入关键字模糊匹配短信内容</string>
<string name="contact_keyword_hint">纯数字匹配号码/非数字匹配姓名</string> <string name="contact_keyword_hint">纯数字匹配号码/非数字匹配姓名</string>
<string name="call_keyword_hint">输入关键字模糊匹配手机号码</string> <string name="call_keyword_hint">输入关键字模糊匹配手机号码</string>
@ -1280,7 +1263,9 @@
<string name="cyclic_from_week">从星期</string> <string name="cyclic_from_week">从星期</string>
<string name="cyclic_to"></string> <string name="cyclic_to"></string>
<string name="start">起始</string> <string name="start">起始</string>
<string name="start_time">起始时间</string>
<string name="end">结束</string> <string name="end">结束</string>
<string name="end_time">结束时间</string>
<string name="interval_seconds_1"></string> <string name="interval_seconds_1"></string>
<string name="interval_seconds_2">秒开始,每</string> <string name="interval_seconds_2">秒开始,每</string>
<string name="interval_seconds_3">秒钟执行一次</string> <string name="interval_seconds_3">秒钟执行一次</string>

View File

@ -164,7 +164,9 @@
<string name="discard">丟棄</string> <string name="discard">丟棄</string>
<string name="quit">退出</string> <string name="quit">退出</string>
<string name="del">刪除</string> <string name="del">刪除</string>
<string name="save">保存</string> <string name="save">儲存</string>
<string name="reset">重置</string>
<string name="search">搜索</string>
<string name="submit">提交</string> <string name="submit">提交</string>
<string name="send">發送</string> <string name="send">發送</string>
<string name="test">測試</string> <string name="test">測試</string>
@ -213,6 +215,8 @@
<string name="delete_log_toast">該條日誌記錄已刪除!</string> <string name="delete_log_toast">該條日誌記錄已刪除!</string>
<string name="delete_type_log_tips">確定刪除該分類的所有日誌記錄?</string> <string name="delete_type_log_tips">確定刪除該分類的所有日誌記錄?</string>
<string name="delete_type_log_toast">該分類日誌記錄已清空!</string> <string name="delete_type_log_toast">該分類日誌記錄已清空!</string>
<string name="delete_filter_log_tips">確定刪除當前篩選的所有日誌記錄?</string>
<string name="delete_filter_log_toast">當前篩選的所有日誌記錄已經刪除!</string>
<string name="resend_toast">正在嘗試通過原發送通道重發</string> <string name="resend_toast">正在嘗試通過原發送通道重發</string>
<string name="rematch_toast">正在重新匹配規則發送</string> <string name="rematch_toast">正在重新匹配規則發送</string>
<string name="details">詳情</string> <string name="details">詳情</string>
@ -631,33 +635,10 @@
<string name="time">時間:</string> <string name="time">時間:</string>
<string name="result">轉發結果:</string> <string name="result">轉發結果:</string>
<string name="original_result">原轉發狀態:</string> <string name="original_result">原轉發狀態:</string>
<string name="forward_status">狀態:</string>
<string name="success">成功</string> <string name="success">成功</string>
<string name="failed">失敗</string> <string name="failed">失敗</string>
<string name="processing">處理中</string> <string name="processing">處理中</string>
<string name="tag_from">{{FROM}}</string>
<string name="tag_sms">{{SMS}}</string>
<string name="tag_package_name">{{PACKAGE_NAME}}</string>
<string name="tag_app_name">{{APP_NAME}}</string>
<string name="tag_msg">{{MSG}}</string>
<string name="tag_card_slot">{{CARD_SLOT}}</string>
<string name="tag_card_subid">{{CARD_SUBID}}</string>
<string name="tag_receive_time">{{RECEIVE_TIME}}</string>
<string name="tag_current_time">{{CURRENT_TIME}}</string>
<string name="tag_device_name">{{DEVICE_NAME}}</string>
<string name="tag_app_version">{{APP_VERSION}}</string>
<string name="tag_title">{{TITLE}}</string>
<string name="tag_call_type">{{CALL_TYPE}}</string>
<string name="tag_location">{{LOCATION}}</string>
<string name="tag_location_longitude">{{LOCATION_LONGITUDE}}</string>
<string name="tag_location_latitude">{{LOCATION_LATITUDE}}</string>
<string name="tag_location_address">{{LOCATION_ADDRESS}}</string>
<string name="tag_battery_pct">{{BATTERY_PCT}}</string>
<string name="tag_battery_status">{{BATTERY_STATUS}}</string>
<string name="tag_battery_plugged">{{BATTERY_PLUGGED}}</string>
<string name="tag_battery_info">{{BATTERY_INFO}}</string>
<string name="tag_uid">{{UID}}</string>
<string name="tag_ipv4">{{IPV4}}</string>
<string name="tag_ipv6">{{IPV6}}</string>
<string name="rule_sms">簡訊</string> <string name="rule_sms">簡訊</string>
<string name="rule_call">來電</string> <string name="rule_call">來電</string>
<string name="rule_app">應用</string> <string name="rule_app">應用</string>
@ -1023,6 +1004,7 @@
<string name="matched_rule">匹配中規則</string> <string name="matched_rule">匹配中規則</string>
<string name="copied_to_clipboard">已複製到剪貼板:\n%s</string> <string name="copied_to_clipboard">已複製到剪貼板:\n%s</string>
<string name="search_keyword">搜索關鍵字: %s</string> <string name="search_keyword">搜索關鍵字: %s</string>
<string name="search_condition">搜索條件:%s</string>
<string name="export_succeeded">導出配置成功!</string> <string name="export_succeeded">導出配置成功!</string>
<string name="export_failed">導出失敗,請檢查寫入權限!</string> <string name="export_failed">導出失敗,請檢查寫入權限!</string>
<string name="export_failed_tips">導出失敗: %s</string> <string name="export_failed_tips">導出失敗: %s</string>
@ -1047,6 +1029,7 @@
<string name="main_title">主標題</string> <string name="main_title">主標題</string>
<string name="subtitle">副標題</string> <string name="subtitle">副標題</string>
<string name="logs_keyword_hint">輸入關鍵字模糊匹配</string>
<string name="sms_keyword_hint">輸入關鍵字模糊匹配簡訊內容</string> <string name="sms_keyword_hint">輸入關鍵字模糊匹配簡訊內容</string>
<string name="contact_keyword_hint">純數字匹配號碼/非數字匹配姓名</string> <string name="contact_keyword_hint">純數字匹配號碼/非數字匹配姓名</string>
<string name="call_keyword_hint">輸入關鍵字模糊匹配手機號碼</string> <string name="call_keyword_hint">輸入關鍵字模糊匹配手機號碼</string>
@ -1280,7 +1263,9 @@
<string name="cyclic_from_week">從星期</string> <string name="cyclic_from_week">從星期</string>
<string name="cyclic_to"></string> <string name="cyclic_to"></string>
<string name="start">起始</string> <string name="start">起始</string>
<string name="end">結束</string> <string name="start_time">起始时间</string>
<string name="end">结束</string>
<string name="end_time">结束时间</string>
<string name="interval_seconds_1"></string> <string name="interval_seconds_1"></string>
<string name="interval_seconds_2">秒開始,每</string> <string name="interval_seconds_2">秒開始,每</string>
<string name="interval_seconds_3">秒鐘執行一次</string> <string name="interval_seconds_3">秒鐘執行一次</string>

View File

@ -1,4 +1,30 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<string name="tag_from" translatable="false">{{FROM}}</string>
<string name="tag_sms" translatable="false">{{SMS}}</string>
<string name="tag_package_name" translatable="false">{{PACKAGE_NAME}}</string>
<string name="tag_app_name" translatable="false">{{APP_NAME}}</string>
<string name="tag_msg" translatable="false">{{MSG}}</string>
<string name="tag_card_slot" translatable="false">{{CARD_SLOT}}</string>
<string name="tag_card_subid" translatable="false">{{CARD_SUBID}}</string>
<string name="tag_receive_time" translatable="false">{{RECEIVE_TIME}}</string>
<string name="tag_current_time" translatable="false">{{CURRENT_TIME}}</string>
<string name="tag_device_name" translatable="false">{{DEVICE_NAME}}</string>
<string name="tag_app_version" translatable="false">{{APP_VERSION}}</string>
<string name="tag_title" translatable="false">{{TITLE}}</string>
<string name="tag_call_type" translatable="false">{{CALL_TYPE}}</string>
<string name="tag_location" translatable="false">{{LOCATION}}</string>
<string name="tag_location_longitude" translatable="false">{{LOCATION_LONGITUDE}}</string>
<string name="tag_location_latitude" translatable="false">{{LOCATION_LATITUDE}}</string>
<string name="tag_location_address" translatable="false">{{LOCATION_ADDRESS}}</string>
<string name="tag_battery_pct" translatable="false">{{BATTERY_PCT}}</string>
<string name="tag_battery_status" translatable="false">{{BATTERY_STATUS}}</string>
<string name="tag_battery_plugged" translatable="false">{{BATTERY_PLUGGED}}</string>
<string name="tag_battery_info" translatable="false">{{BATTERY_INFO}}</string>
<string name="tag_battery_info_simple" translatable="false">{{BATTERY_INFO_SIMPLE}}</string>
<string name="tag_uid" translatable="false">{{UID}}</string>
<string name="tag_ipv4" translatable="false">{{IPV4}}</string>
<string name="tag_ipv6" translatable="false">{{IPV6}}</string>
<string name="tag_net_type" translatable="false">{{NET_TYPE}}</string>
<string name="type_param_sms">短信</string> <string name="type_param_sms">短信</string>
<string name="type_param_call">通话</string> <string name="type_param_call">通话</string>
@ -165,6 +191,8 @@
<string name="quit">退出</string> <string name="quit">退出</string>
<string name="del">删除</string> <string name="del">删除</string>
<string name="save">保存</string> <string name="save">保存</string>
<string name="reset">重置</string>
<string name="search">搜索</string>
<string name="submit">提交</string> <string name="submit">提交</string>
<string name="send">发送</string> <string name="send">发送</string>
<string name="test">测试</string> <string name="test">测试</string>
@ -213,6 +241,8 @@
<string name="delete_log_toast">该条日志记录已经删除!</string> <string name="delete_log_toast">该条日志记录已经删除!</string>
<string name="delete_type_log_tips">确定删除该分类的所有日志记录?</string> <string name="delete_type_log_tips">确定删除该分类的所有日志记录?</string>
<string name="delete_type_log_toast">该分类日志记录已经清空!</string> <string name="delete_type_log_toast">该分类日志记录已经清空!</string>
<string name="delete_filter_log_tips">确定删除当前筛选的所有日志记录?</string>
<string name="delete_filter_log_toast">当前筛选的所有日志记录已经删除!</string>
<string name="resend_toast">正在尝试通过原发送通道重发</string> <string name="resend_toast">正在尝试通过原发送通道重发</string>
<string name="rematch_toast">正在重新匹配规则发送</string> <string name="rematch_toast">正在重新匹配规则发送</string>
<string name="details">详情</string> <string name="details">详情</string>
@ -631,34 +661,10 @@
<string name="time">时间:</string> <string name="time">时间:</string>
<string name="result">转发结果:</string> <string name="result">转发结果:</string>
<string name="original_result">原转发状态:</string> <string name="original_result">原转发状态:</string>
<string name="forward_status">状态:</string>
<string name="success">成功</string> <string name="success">成功</string>
<string name="failed">失败</string> <string name="failed">失败</string>
<string name="processing">处理中</string> <string name="processing">处理中</string>
<string name="tag_from">{{FROM}}</string>
<string name="tag_sms">{{SMS}}</string>
<string name="tag_package_name">{{PACKAGE_NAME}}</string>
<string name="tag_app_name">{{APP_NAME}}</string>
<string name="tag_msg">{{MSG}}</string>
<string name="tag_card_slot">{{CARD_SLOT}}</string>
<string name="tag_card_subid">{{CARD_SUBID}}</string>
<string name="tag_receive_time">{{RECEIVE_TIME}}</string>
<string name="tag_current_time">{{CURRENT_TIME}}</string>
<string name="tag_device_name">{{DEVICE_NAME}}</string>
<string name="tag_app_version">{{APP_VERSION}}</string>
<string name="tag_title">{{TITLE}}</string>
<string name="tag_call_type">{{CALL_TYPE}}</string>
<string name="tag_location">{{LOCATION}}</string>
<string name="tag_location_longitude">{{LOCATION_LONGITUDE}}</string>
<string name="tag_location_latitude">{{LOCATION_LATITUDE}}</string>
<string name="tag_location_address">{{LOCATION_ADDRESS}}</string>
<string name="tag_battery_pct">{{BATTERY_PCT}}</string>
<string name="tag_battery_status">{{BATTERY_STATUS}}</string>
<string name="tag_battery_plugged">{{BATTERY_PLUGGED}}</string>
<string name="tag_battery_info">{{BATTERY_INFO}}</string>
<string name="tag_battery_info_simple" translatable="false">{{BATTERY_INFO_SIMPLE}}</string>
<string name="tag_uid">{{UID}}</string>
<string name="tag_ipv4">{{IPV4}}</string>
<string name="tag_ipv6">{{IPV6}}</string>
<string name="rule_sms">短信</string> <string name="rule_sms">短信</string>
<string name="rule_call">来电</string> <string name="rule_call">来电</string>
<string name="rule_app">应用</string> <string name="rule_app">应用</string>
@ -1024,6 +1030,7 @@
<string name="matched_rule">匹配中规则</string> <string name="matched_rule">匹配中规则</string>
<string name="copied_to_clipboard">已复制到剪贴板:\n%s</string> <string name="copied_to_clipboard">已复制到剪贴板:\n%s</string>
<string name="search_keyword">搜索关键字: %s</string> <string name="search_keyword">搜索关键字: %s</string>
<string name="search_condition">搜索条件: %s</string>
<string name="export_succeeded">导出配置成功!</string> <string name="export_succeeded">导出配置成功!</string>
<string name="export_failed">导出失败,请检查写入权限!</string> <string name="export_failed">导出失败,请检查写入权限!</string>
<string name="export_failed_tips">导出失败: %s</string> <string name="export_failed_tips">导出失败: %s</string>
@ -1048,6 +1055,7 @@
<string name="main_title">主标题</string> <string name="main_title">主标题</string>
<string name="subtitle">副标题</string> <string name="subtitle">副标题</string>
<string name="logs_keyword_hint">输入关键字模糊匹配</string>
<string name="sms_keyword_hint">输入关键字模糊匹配短信内容</string> <string name="sms_keyword_hint">输入关键字模糊匹配短信内容</string>
<string name="contact_keyword_hint">纯数字匹配号码/非数字匹配姓名</string> <string name="contact_keyword_hint">纯数字匹配号码/非数字匹配姓名</string>
<string name="call_keyword_hint">输入关键字模糊匹配手机号码</string> <string name="call_keyword_hint">输入关键字模糊匹配手机号码</string>
@ -1281,7 +1289,9 @@
<string name="cyclic_from_week">从星期</string> <string name="cyclic_from_week">从星期</string>
<string name="cyclic_to"></string> <string name="cyclic_to"></string>
<string name="start">起始</string> <string name="start">起始</string>
<string name="start_time">起始时间</string>
<string name="end">结束</string> <string name="end">结束</string>
<string name="end_time">结束时间</string>
<string name="interval_seconds_1"></string> <string name="interval_seconds_1"></string>
<string name="interval_seconds_2">秒开始,每</string> <string name="interval_seconds_2">秒开始,每</string>
<string name="interval_seconds_3">秒钟执行一次</string> <string name="interval_seconds_3">秒钟执行一次</string>
@ -1451,5 +1461,4 @@
<string name="bluetooth_not_supported">不支持蓝牙设备</string> <string name="bluetooth_not_supported">不支持蓝牙设备</string>
<string name="start_discovery">搜索设备</string> <string name="start_discovery">搜索设备</string>
<string name="invalid_bluetooth_mac_address">蓝牙设备MAC地址无效例如AA:BB:CC:DD:EE:FF</string> <string name="invalid_bluetooth_mac_address">蓝牙设备MAC地址无效例如AA:BB:CC:DD:EE:FF</string>
<string name="tag_net_type" translatable="false">{{NET_TYPE}}</string>
</resources> </resources>