xiongzhu 1 год назад
Родитель
Сommit
661cc1f81b

+ 1 - 1
app/build.gradle

@@ -24,7 +24,7 @@ android {
         applicationId "com.example.modifier"
         minSdk 29
         targetSdk 34
-        versionCode 139
+        versionCode 140
         versionName "1.0.1"
         archivesBaseName = "modifier-${versionCode}"
 

+ 2 - 1
app/src/main/java/com/example/modifier/data/AppPreferences.kt

@@ -6,5 +6,6 @@ data class AppPreferences(
     val name: String,
     val preventClean: Boolean,
     val preventRequest: Boolean,
-    val preventReset: Boolean
+    val preventReset: Boolean,
+    val storeNum: Int,
 )

+ 0 - 13
app/src/main/java/com/example/modifier/data/AppRuntimeFlags.kt

@@ -1,13 +0,0 @@
-package com.example.modifier.data
-
-import com.example.modifier.enums.RequestNumberState
-
-data class AppRuntimeFlags(
-    val running: Boolean = false,
-    val requesting: Boolean = false,
-    val preparing: Boolean = false,
-    val checkingConnection: Boolean = false,
-    val suspended: Boolean = false,
-    val requestNumberState: RequestNumberState = RequestNumberState.IDLE,
-    val storing: Boolean = false,
-)

+ 8 - 5
app/src/main/java/com/example/modifier/data/AppState.kt

@@ -1,6 +1,6 @@
 package com.example.modifier.data
 
-import com.example.modifier.enums.RequestNumberState
+import com.example.modifier.enums.ReqState
 
 data class AppState(
     val send: Boolean,
@@ -8,10 +8,13 @@ data class AppState(
     val successNum: Int,
     val requestedNum: Int,
     val running: Boolean,
-    val requesting: Boolean,
     val preparing: Boolean,
     val checkingConnection: Boolean,
-    val busy: Boolean,
     val suspended: Boolean,
-    val requestNumberState: RequestNumberState
-)
+    val reqState: ReqState,
+    val storing: Boolean = false,
+) {
+
+    val busy: Boolean
+        get() = running || preparing || checkingConnection || storing || reqState != ReqState.NONE
+}

+ 3 - 2
app/src/main/java/com/example/modifier/enums/RequestNumberState.kt → app/src/main/java/com/example/modifier/enums/ReqState.kt

@@ -1,7 +1,8 @@
 package com.example.modifier.enums
 
-enum class RequestNumberState {
-    IDLE,
+enum class ReqState {
+    NONE,
+    CLEAN,
     RESET,
     BACKUP,
     RESTORE,

+ 13 - 2
app/src/main/java/com/example/modifier/repo/AppPrefsRepo.kt

@@ -6,6 +6,7 @@ import android.os.Build
 import android.provider.Settings
 import androidx.datastore.preferences.core.booleanPreferencesKey
 import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.intPreferencesKey
 import androidx.datastore.preferences.core.stringPreferencesKey
 import androidx.datastore.preferences.preferencesDataStore
 import com.example.modifier.BuildConfig
@@ -33,6 +34,7 @@ class AppPrefsRepo private constructor(private val context: Context) {
         val PREVENT_CLEAN = booleanPreferencesKey("prevent_clean")
         val PREVENT_REQUEST = booleanPreferencesKey("prevent_request")
         val PREVENT_RESET = booleanPreferencesKey("prevent_reset")
+        val STORE_NUM = intPreferencesKey("store_num")
     }
 
     val appPrefs = MutableStateFlow(
@@ -42,7 +44,8 @@ class AppPrefsRepo private constructor(private val context: Context) {
             name = Build.DEVICE,
             preventClean = false,
             preventRequest = false,
-            preventReset = false
+            preventReset = false,
+            storeNum = 20
         )
     )
 
@@ -65,13 +68,15 @@ class AppPrefsRepo private constructor(private val context: Context) {
         val preventClean = it[PreferencesKeys.PREVENT_CLEAN] ?: false
         val preventRequest = it[PreferencesKeys.PREVENT_REQUEST] ?: false
         val preventReset = it[PreferencesKeys.PREVENT_RESET] ?: false
+        val storeNum = it[PreferencesKeys.STORE_NUM] ?: 20
         AppPreferences(
             server = server,
             id = id,
             name = name,
             preventClean = preventClean,
             preventRequest = preventRequest,
-            preventReset = preventReset
+            preventReset = preventReset,
+            storeNum = storeNum
         )
     }
 
@@ -120,4 +125,10 @@ class AppPrefsRepo private constructor(private val context: Context) {
             preferences[PreferencesKeys.PREVENT_RESET] = preventReset
         }
     }
+
+    suspend fun updateStoreNum(storeNum: Int) {
+        context.appPreferencesDataStore.edit { preferences ->
+            preferences[PreferencesKeys.STORE_NUM] = storeNum
+        }
+    }
 }

+ 21 - 46
app/src/main/java/com/example/modifier/repo/AppStateRepo.kt

@@ -7,16 +7,13 @@ import androidx.datastore.preferences.core.edit
 import androidx.datastore.preferences.core.intPreferencesKey
 import androidx.datastore.preferences.preferencesDataStore
 import com.example.modifier.BuildConfig
-import com.example.modifier.Utils
 import com.example.modifier.baseTag
-import com.example.modifier.data.AppRuntimeFlags
 import com.example.modifier.data.AppState
-import com.example.modifier.enums.RequestNumberState
+import com.example.modifier.enums.ReqState
 import com.example.modifier.utils.getContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 
@@ -36,8 +33,6 @@ class AppStateRepo private constructor(private val context: Context) {
         val REQUESTED_NUM = intPreferencesKey("requested_num")
     }
 
-    val appRuntimeFlags = MutableStateFlow(AppRuntimeFlags())
-
     val appState = MutableStateFlow(
         AppState(
             send = false,
@@ -45,42 +40,24 @@ class AppStateRepo private constructor(private val context: Context) {
             successNum = 0,
             requestedNum = 0,
             running = false,
-            requesting = false,
             preparing = false,
             checkingConnection = false,
-            busy = false,
             suspended = false,
-            requestNumberState = RequestNumberState.IDLE
+            reqState = ReqState.NONE
         )
     )
 
-    private val appStateFlow =
-        context.appStateDataStore.data.combine(appRuntimeFlags) { preferences, runtimeFlags ->
-            val sPrefs =
-                context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE)
-            val busy =
-                runtimeFlags.running || runtimeFlags.requesting || runtimeFlags.preparing || runtimeFlags.checkingConnection
-            AppState(
-                send = preferences[PreferencesKeys.SEND] ?: false,
-                executedNum = preferences[PreferencesKeys.EXECUTED_NUM] ?: 0,
-                successNum = preferences[PreferencesKeys.SUCCESS_NUM]
-                    ?: sPrefs.getInt("sendCount", 0),
-                requestedNum = preferences[PreferencesKeys.REQUESTED_NUM]
-                    ?: sPrefs.getInt("requestNumberCount", 0),
-                running = runtimeFlags.running,
-                requesting = runtimeFlags.requesting,
-                preparing = runtimeFlags.preparing,
-                checkingConnection = runtimeFlags.checkingConnection,
-                busy = runtimeFlags.running || runtimeFlags.requesting || runtimeFlags.preparing || runtimeFlags.checkingConnection || runtimeFlags.storing,
-                suspended = runtimeFlags.suspended,
-                requestNumberState = runtimeFlags.requestNumberState
-            )
-        }
-
     init {
         CoroutineScope(Dispatchers.IO).launch {
-            appStateFlow.collect {
-                appState.emit(it)
+            context.appStateDataStore.data.collect { preferences ->
+                appState.update {
+                    it.copy(
+                        send = preferences[PreferencesKeys.SEND] ?: false,
+                        executedNum = preferences[PreferencesKeys.EXECUTED_NUM] ?: 0,
+                        successNum = preferences[PreferencesKeys.SUCCESS_NUM] ?: 0,
+                        requestedNum = preferences[PreferencesKeys.REQUESTED_NUM] ?: 0
+                    )
+                }
             }
         }
     }
@@ -99,6 +76,7 @@ class AppStateRepo private constructor(private val context: Context) {
     suspend fun incrementRequestedNum() {
         context.appStateDataStore.edit { preferences ->
             val requestedNum = (preferences[PreferencesKeys.REQUESTED_NUM] ?: 0) + 1
+            Log.i(TAG, "incrementRequestedNum: $requestedNum")
             preferences[PreferencesKeys.REQUESTED_NUM] = requestedNum
         }
     }
@@ -129,24 +107,21 @@ class AppStateRepo private constructor(private val context: Context) {
 
     fun updateRuntimeFlags(
         running: Boolean? = null,
-        requesting: Boolean? = null,
         preparing: Boolean? = null,
         checkingConnection: Boolean? = null,
         suspended: Boolean? = null,
-        requestNumberState: RequestNumberState? = null,
+        reqState: ReqState? = null,
         storing: Boolean? = null
     ) {
-        val value = appRuntimeFlags.value
-        appRuntimeFlags.update {
+        appState.update {
             it.copy(
-                running = running ?: value.running,
-                requesting = requesting ?: value.requesting,
-                preparing = preparing ?: value.preparing,
-                checkingConnection = checkingConnection ?: value.checkingConnection,
-                suspended = suspended ?: value.suspended,
-                requestNumberState = requestNumberState ?: value.requestNumberState,
-                storing = storing ?: value.storing
+                running = running ?: it.running,
+                preparing = preparing ?: it.preparing,
+                checkingConnection = checkingConnection ?: it.checkingConnection,
+                suspended = suspended ?: it.suspended,
+                reqState = reqState ?: it.reqState,
+                storing = storing ?: it.storing
             )
         }
     }
-}
+}

+ 43 - 32
app/src/main/java/com/example/modifier/service/ModifierService.kt

@@ -27,7 +27,7 @@ import com.example.modifier.TraverseResult
 import com.example.modifier.baseTag
 import com.example.modifier.data.AppDatabase
 import com.example.modifier.databinding.FloatingWindowBinding
-import com.example.modifier.enums.RequestNumberState
+import com.example.modifier.enums.ReqState
 import com.example.modifier.http.api.RcsNumberApi
 import com.example.modifier.repo.AppPrefsRepo
 import com.example.modifier.repo.AppStateRepo
@@ -47,6 +47,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.FlowPreview
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
@@ -174,11 +175,16 @@ class ModifierService : AccessibilityService() {
                 gmsgStateRepository,
                 backupRepository,
             )
+            launch {
+                appStateRepo.appState.debounce(200).collect {
+                    socketClient.reportDeviceStatues()
+                }
+            }
             launch {
                 appStateRepo.appState.collect {
                     withContext(Dispatchers.Main) {
                         binding.swSend.isChecked = it.send
-                        binding.btnReq.isEnabled = !it.requesting
+                        binding.btnReq.isEnabled = it.reqState == ReqState.NONE
                         binding.tvCount.text = "${it.successNum} / ${it.executedNum}"
                         if (it.suspended) {
                             binding.btnReq.backgroundTintList = ContextCompat.getColorStateList(
@@ -191,43 +197,48 @@ class ModifierService : AccessibilityService() {
                                 R.color.btn_color
                             )
                         }
-                        when (it.requestNumberState) {
-                            RequestNumberState.IDLE -> {
+                        when (it.reqState) {
+                            ReqState.NONE -> {
                                 binding.tvStatus.visibility = GONE
                                 binding.tvStatus.text = ""
                             }
 
-                            RequestNumberState.RESET -> {
+                            ReqState.CLEAN -> {
+                                binding.tvStatus.visibility = VISIBLE
+                                binding.tvStatus.text = "cleaning messages"
+                            }
+
+                            ReqState.RESET -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "resetting GMS"
                             }
 
-                            RequestNumberState.BACKUP -> {
+                            ReqState.BACKUP -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "backing up"
                             }
 
-                            RequestNumberState.RESTORE -> {
+                            ReqState.RESTORE -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "restoring"
                             }
 
-                            RequestNumberState.REQUEST -> {
+                            ReqState.REQUEST -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "requesting number"
                             }
 
-                            RequestNumberState.OTP_1 -> {
+                            ReqState.OTP_1 -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "waiting for OTP sent"
                             }
 
-                            RequestNumberState.OTP_2 -> {
+                            ReqState.OTP_2 -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "waiting for OTP received"
                             }
 
-                            RequestNumberState.CONFIG -> {
+                            ReqState.CONFIG -> {
                                 binding.tvStatus.visibility = VISIBLE
                                 binding.tvStatus.text = "waiting for configuration"
                             }
@@ -336,9 +347,10 @@ class ModifierService : AccessibilityService() {
         val popup = PopupMenu(context, v)
         popup.menuInflater.inflate(menuRes, popup.menu)
         popup.menu.findItem(R.id.store_numbers).isEnabled =
-            !appStateRepo.appRuntimeFlags.value.storing
+            !appStateRepo.appState.value.storing
+        popup.menu.findItem(R.id.check_availability).isEnabled =
+            !appStateRepo.appState.value.checkingConnection
         popup.setOnMenuItemClickListener { item ->
-            binding.btnMore.isEnabled = false
             CoroutineScope(Dispatchers.IO).launch {
                 when (item.itemId) {
                     R.id.inspect -> {
@@ -347,7 +359,9 @@ class ModifierService : AccessibilityService() {
                     }
 
                     R.id.check_availability -> {
+                        appStateRepo.updateRuntimeFlags(checkingConnection = true)
                         taskRunner.checkRcsA10y()
+                        appStateRepo.updateRuntimeFlags(checkingConnection = false)
                     }
 
                     R.id.toggle_on -> {
@@ -364,7 +378,7 @@ class ModifierService : AccessibilityService() {
                     }
 
                     R.id.store_numbers -> {
-                        if (!appStateRepo.appRuntimeFlags.value.storing) {
+                        if (!appStateRepo.appState.value.storing) {
                             launch {
                                 storeNumbers()
                             }
@@ -387,10 +401,6 @@ class ModifierService : AccessibilityService() {
                         }
                     }
                 }
-
-                withContext(Dispatchers.Main) {
-                    binding.btnMore.isEnabled = true
-                }
             }
             true
         }
@@ -402,17 +412,19 @@ class ModifierService : AccessibilityService() {
     }
 
     private suspend fun storeNumbers() {
+        val num = appPrefsRepo.appPrefs.value.storeNum
+        if (num <= 0) {
+            return
+        }
         appStateRepo.updateRuntimeFlags(storing = true)
         var success = true
         var retry = 0
-        val num = 10
         repeat(num) {
             Log.i(TAG, "storeNumbers: $it")
             try {
                 if (success || retry > 3) {
                     taskRunner.reset()
                 }
-                appStateRepo.updateRuntimeFlags(requesting = true)
                 taskRunner.requestNumberAtomic()
                 spoofedSimInfoRepo.updateSpoofedSimInfo(
                     spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value.copy(
@@ -420,27 +432,26 @@ class ModifierService : AccessibilityService() {
                     ),
                     suspend = false
                 )
-                appStateRepo.updateRuntimeFlags(requesting = false)
-                if (it < num - 1) {
-                    appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.BACKUP)
-                    taskRunner.screenController.toggleRcsSwitch(false)
-                    backupRepository.backup(type = "auto", sendCount = 0, stock = 1)
-                    RcsNumberApi.updateStockFlag(
-                        id = spoofedSimInfoRepo.spoofedSimInfo.value.numberId,
-                        flag = 1
-                    )
-                }
+                appStateRepo.updateRuntimeFlags(reqState = ReqState.BACKUP)
+                taskRunner.screenController.toggleRcsSwitch(false)
+                backupRepository.backup(type = "auto", sendCount = 0, stock = 1)
+                RcsNumberApi.updateStockFlag(
+                    id = spoofedSimInfoRepo.spoofedSimInfo.value.numberId,
+                    flag = 1
+                )
                 success = true
                 retry = 0
             } catch (e: Exception) {
-                appStateRepo.updateRuntimeFlags(requesting = false)
                 success = false
                 retry++
                 Log.i(TAG, "Error store number, retry: $retry", e)
             }
         }
+        if (success) {
+            taskRunner.reset()
+        }
         appStateRepo.updateRuntimeFlags(
-            requestNumberState = RequestNumberState.IDLE,
+            reqState = ReqState.NONE,
             storing = false
         )
     }

+ 2 - 1
app/src/main/java/com/example/modifier/service/SocketClient.kt

@@ -4,6 +4,7 @@ import android.os.Build
 import android.util.Log
 import com.example.modifier.BuildConfig
 import com.example.modifier.baseTag
+import com.example.modifier.enums.ReqState
 import com.example.modifier.model.InstallApkAction
 import com.example.modifier.model.RunScriptAction
 import com.example.modifier.model.RunScriptResult
@@ -205,7 +206,7 @@ class SocketClient(
             dataObj.put("busy", AppStateRepo.instance.appState.value.busy)
             dataObj.put("currentCountry", SpoofedSimInfoRepo.instance.spoofedSimInfo.value.country)
             dataObj.put("ip", getIPAddress().joinToString(","))
-            dataObj.put("requesting", AppStateRepo.instance.appState.value.requesting)
+            dataObj.put("requesting", AppStateRepo.instance.appState.value.reqState == ReqState.REQUEST)
             dataObj.put("suspended", AppStateRepo.instance.appState.value.suspended)
             data.put("data", dataObj)
             mSocket.emit("message", data)

+ 16 - 17
app/src/main/java/com/example/modifier/service/TaskRunner.kt

@@ -13,7 +13,7 @@ import com.example.modifier.constants.PACKAGE_GMS
 import com.example.modifier.constants.PACKAGE_MESSAGING
 import com.example.modifier.enums.RcsConfigureState
 import com.example.modifier.enums.RcsConnectionStatus
-import com.example.modifier.enums.RequestNumberState
+import com.example.modifier.enums.ReqState
 import com.example.modifier.exception.RequestNumberException
 import com.example.modifier.exception.RequestNumberException.Companion.ErrorCode
 import com.example.modifier.extension.kill
@@ -230,7 +230,7 @@ class TaskRunner(
             withTimeout(1.hours) {
                 while (true) {
                     delay(100)
-                    appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.RESET)
+                    appStateRepo.updateRuntimeFlags(reqState = ReqState.RESET)
                     gmsgStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
                     spoofedSimInfoRepo.mock()
                     resetAll()
@@ -291,7 +291,7 @@ class TaskRunner(
             withTimeout(1.hours) {
                 while (true) {
                     delay(100)
-                    appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.RESET)
+                    appStateRepo.updateRuntimeFlags(reqState = ReqState.RESET)
                     gmsgStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
                     spoofedSimInfoRepo.mock()
                     resetAll()
@@ -346,10 +346,11 @@ class TaskRunner(
                 }
             }
         }
+        appStateRepo.updateRuntimeFlags(reqState = ReqState.NONE)
     }
 
     suspend fun requestNumberAtomic() {
-        appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.REQUEST)
+        appStateRepo.updateRuntimeFlags(reqState = ReqState.REQUEST)
         gmsgStateRepository.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
         val device = DeviceApi.getDevice(appPrefsRepo.appPrefs.value.id)
         val rcsNumber = RcsNumberApi.getRcsNumber(
@@ -359,7 +360,7 @@ class TaskRunner(
         )
         Log.i(TAG, "requestNumber response: $rcsNumber")
 
-        appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.OTP_1)
+        appStateRepo.updateRuntimeFlags(reqState = ReqState.OTP_1)
 
         spoofedSimInfoRepo.updateSpoofedSimInfo(
             SpoofedSimInfo(
@@ -425,11 +426,11 @@ class TaskRunner(
             throw RequestNumberException(ErrorCode.CODE_NUMBER_EXPIRED)
         }
 
-        appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.OTP_2)
+        appStateRepo.updateRuntimeFlags(reqState = ReqState.OTP_2)
         val otp = RcsNumberApi.waitForOtp(rcsNumber.id)
             ?: throw RequestNumberException(ErrorCode.CODE_OTP_NOT_RECEIVED)
 
-        appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.CONFIG)
+        appStateRepo.updateRuntimeFlags(reqState = ReqState.CONFIG)
 
         val configured = run configuring@{
             repeat(2) {
@@ -474,14 +475,13 @@ class TaskRunner(
         if (appPrefsRepo.appPrefs.value.preventRequest) {
             return
         }
-        if (appStateRepo.appState.value.requesting) {
+        if (appStateRepo.appState.value.reqState != ReqState.NONE) {
             return
         }
-
-        appStateRepo.updateRuntimeFlags(requesting = true)
+        appStateRepo.updateRuntimeFlags(reqState = ReqState.CLEAN)
         clearConv()
         if (spoofedSimInfoRepo.spoofedSimInfo.value.available) {
-            appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.BACKUP)
+            appStateRepo.updateRuntimeFlags(reqState = ReqState.BACKUP)
             backupRepository.backup(
                 type = "auto",
                 sendCount = appStateRepo.appState.value.successNum
@@ -489,12 +489,12 @@ class TaskRunner(
         }
 
         var needRest = reset
-        var requestSuccess = withTimeoutOrNull(2.hours) {
+        val requestSuccess = withTimeoutOrNull(2.hours) {
             while (true) {
                 delay(200)
                 try {
                     if (requestMode == 2 && !noBackup) {
-                        appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.RESTORE)
+                        appStateRepo.updateRuntimeFlags(reqState = ReqState.RESTORE)
                         val backup = backupRepository.findBackupForRestore(
                             spoofedSimInfoRepo.spoofedSimInfo.value.number
                         )
@@ -506,13 +506,13 @@ class TaskRunner(
                             } else {
                                 backup.stock = 3
                                 backupRepository.update(backup)
-                                appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.BACKUP)
+                                appStateRepo.updateRuntimeFlags(reqState = ReqState.BACKUP)
                                 continue
                             }
                         }
                     }
 
-                    needRest = needRest || appStateRepo.appState.value.requestedNum > 5
+                    needRest = needRest || appStateRepo.appState.value.requestedNum > 3
                     if (needRest && !appPrefsRepo.appPrefs.value.preventReset) {
                         reset()
                         needRest = false
@@ -544,8 +544,7 @@ class TaskRunner(
             appStateRepo.updateSend(false)
         }
         appStateRepo.updateRuntimeFlags(
-            requesting = false,
-            requestNumberState = RequestNumberState.IDLE,
+            reqState = ReqState.NONE,
             suspended = requestSuccess != true
         )
     }

+ 13 - 0
app/src/main/java/com/example/modifier/ui/settings/SettingsFragment.kt

@@ -19,6 +19,7 @@ import androidx.activity.result.ActivityResultLauncher
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
+import androidx.core.widget.addTextChangedListener
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.lifecycleScope
 import com.example.modifier.R
@@ -304,6 +305,15 @@ class SettingsFragment : Fragment() {
                 }
 
             }
+
+            binding.etStoreNum.addTextChangedListener { text: Editable? ->
+                val storeNum = text.toString().toIntOrNull()
+                if (storeNum != null) {
+                    CoroutineScope(Dispatchers.IO).launch {
+                        appPrefsRepo.updateStoreNum(storeNum)
+                    }
+                }
+            }
         }
 
         viewLifecycleOwner.lifecycleScope.launch {
@@ -314,6 +324,9 @@ class SettingsFragment : Fragment() {
                     binding.switchClean.isChecked = it.preventClean
                     binding.switchRequest.isChecked = it.preventRequest
                     binding.swReset.isChecked = it.preventReset
+                    if (binding.etStoreNum.text.toString() != it.storeNum.toString()) {
+                        binding.etStoreNum.setText(it.storeNum.toString())
+                    }
                 }
             }
             launch {

+ 15 - 0
app/src/main/res/layout/fragment_settings.xml

@@ -326,10 +326,25 @@
                         android:orientation="vertical"
                         android:padding="16dp">
 
+                        <com.google.android.material.textfield.TextInputLayout
+
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:hint="Store num">
+
+                            <com.google.android.material.textfield.TextInputEditText
+                                android:id="@+id/et_store_num"
+                                android:layout_width="match_parent"
+                                android:layout_height="wrap_content"
+                                android:inputType="number"
+                                android:lines="1" />
+                        </com.google.android.material.textfield.TextInputLayout>
+
                         <com.google.android.material.materialswitch.MaterialSwitch
                             android:id="@+id/switch_clean"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content"
+                            android:layout_marginTop="8dp"
                             android:text="DO NOT CLEAN" />
 
                         <com.google.android.material.materialswitch.MaterialSwitch