x1ongzhu 1 жил өмнө
parent
commit
9b49a8aab5

+ 10 - 57
app/src/main/java/com/example/modifier/adapter/BackupAdapter.kt

@@ -30,7 +30,7 @@ import java.util.Date
 class BackupAdapter(
     private val context: Context,
     private val backups: MutableList<BackupItem>,
-    private val backupRepository: BackupRepository
+    private val onItemClickListener: OnItemClickListener
 ) :
     RecyclerView.Adapter<BackupViewHolder>() {
     private val tag = "$baseTag/BackupAdapter"
@@ -44,73 +44,26 @@ class BackupAdapter(
         return BackupViewHolder(binding)
     }
 
-    @SuppressLint("DefaultLocale")
+    interface OnItemClickListener {
+        fun onRestoreClick(backup: BackupItem, position: Int)
+        fun onDeleteClick(backup: BackupItem, position: Int)
+    }
+
+    @SuppressLint("DefaultLocale", "SetTextI18n", "SimpleDateFormat")
     override fun onBindViewHolder(holder: BackupViewHolder, position: Int) {
         val backup = backups[position]
         holder.binding.tvNumber.text = "+${backup.code} ${backup.number}"
         holder.binding.tvTime.text =
             SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date(backup.createdAt))
         holder.binding.tvInfo.text = String.format(
-            "MCC: %s, MNC: %s, Country: %s, SendCount: %d, Stock: %b",
+            "MCC: %s, MNC: %s, Country: %s, SendCount: %d, Stock: %d",
             backup.mcc, backup.mnc, backup.country.uppercase(), backup.sendCount, backup.stock
         )
         holder.binding.btnRestore.setOnClickListener { v: View? ->
-            MaterialAlertDialogBuilder(
-                context
-            )
-                .setTitle("Restore backup")
-                .setMessage("Are you sure you want to restore this backup?")
-                .setPositiveButton("Yes") { dialog: DialogInterface?, which: Int ->
-                    dialog?.dismiss()
-                    Utils.makeLoadingButton(context, holder.binding.btnRestore)
-                    CoroutineScope(Dispatchers.IO).launch {
-                        try {
-                            backupRepository.restore(backup)
-                        } catch (e: Exception) {
-                            e.printStackTrace()
-                        }
-                        withContext(Dispatchers.Main) {
-                            holder.binding.btnRestore.isEnabled = true
-                            holder.binding.btnRestore.icon = AppCompatResources.getDrawable(
-                                context,
-                                R.drawable.ic_settings_backup_restore
-                            )
-                        }
-                    }
-                }
-                .setNegativeButton("No", null)
-                .show()
+            onItemClickListener.onRestoreClick(backup, position)
         }
         holder.binding.btnDel.setOnClickListener { v: View? ->
-            MaterialAlertDialogBuilder(
-                context
-            )
-                .setTitle("Delete backup")
-                .setMessage("Are you sure you want to delete this backup?")
-                .setPositiveButton("Yes") { dialog: DialogInterface?, which: Int ->
-                    CoroutineScope(Dispatchers.IO).launch {
-                        val file = File(backup.path)
-                        if (file.exists()) {
-                            try {
-                                File(backup.path).deleteRecursively()
-
-                            } catch (e: Exception) {
-                                e.printStackTrace()
-                                Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
-                            }
-                        } else {
-                            Log.e("BackupAdapter", "File not found")
-                        }
-                        backups.remove(backup)
-                        withContext(Dispatchers.Main) {
-                            notifyItemRemoved(position)
-                        }
-                        backupRepository.delete(backup)
-                    }
-
-                }
-                .setNegativeButton("No", null)
-                .show()
+            onItemClickListener.onDeleteClick(backup, position)
         }
     }
 

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

@@ -21,7 +21,7 @@ data class BackupItem(
     val path: String,
     val lastUse: Long,
     val type: String,
-    var stock: Boolean,
+    var stock: Int,
     val carrierId: String,
     val carrierName: String
 )

+ 4 - 4
app/src/main/java/com/example/modifier/data/BackupItemDao.kt

@@ -28,14 +28,14 @@ interface BackupItemDao {
     suspend fun getAllR(): List<BackupItem>
 
     @Query("SELECT * FROM backupitem WHERE number LIKE :number ORDER BY id")
-    suspend fun getAll(number:String): List<BackupItem>
+    suspend fun getAll(number: String): List<BackupItem>
 
     @Query("SELECT * FROM backupitem WHERE number LIKE :number ORDER BY id DESC")
-    suspend fun getAllR(number:String): List<BackupItem>
+    suspend fun getAllR(number: String): List<BackupItem>
 
     @Query("SELECT * FROM backupitem WHERE country = :country AND number = :number limit 1")
     suspend fun findBackupForNumber(country: String, number: String): BackupItem?
 
-    @Query("SELECT * FROM backupitem WHERE number != :number AND (stock = 1 OR lastUse < :time) order by createdAt limit 1")
-    suspend fun findBackupForRestore(number: String, time: Long): BackupItem?
+    @Query("SELECT * FROM backupitem WHERE number != :number AND stock = 1 order by createdAt limit 1")
+    suspend fun findBackupForRestore(number: String): BackupItem?
 }

+ 11 - 0
app/src/main/java/com/example/modifier/http/api/RcsNumberApi.kt

@@ -37,6 +37,9 @@ class RcsNumberApi() {
 
         @Resource("configured")
         class Configured(val parent: Id)
+
+        @Resource("stockFlag/{flag}")
+        class UpdateStockFlag(val parent: Id, val flag: Int)
     }
 
     companion object {
@@ -129,5 +132,13 @@ class RcsNumberApi() {
                 null
             }
         }
+
+        suspend fun updateStockFlag(id: Int, flag: Int) {
+            try {
+                ktorClient.put(Id.UpdateStockFlag(Id(RcsNumberApi(), id), flag))
+            } catch (e: Exception) {
+                Log.e(TAG, "Update Stock Flag Error: ${e.message}", e)
+            }
+        }
     }
 }

+ 41 - 28
app/src/main/java/com/example/modifier/repo/BackupRepository.kt

@@ -1,5 +1,6 @@
 package com.example.modifier.repo
 
+import android.annotation.SuppressLint
 import android.content.Context
 import androidx.core.content.ContextCompat
 import com.example.modifier.Utils
@@ -13,7 +14,9 @@ import com.example.modifier.data.BackupItemDao
 import com.example.modifier.extension.clear
 import com.example.modifier.extension.disable
 import com.example.modifier.extension.enable
+import com.example.modifier.http.api.RcsNumberApi
 import com.example.modifier.model.SpoofedSimInfo
+import com.example.modifier.service.ModifierService
 import com.example.modifier.utils.clearConv
 import com.example.modifier.utils.shellRun
 import kotlinx.coroutines.delay
@@ -24,15 +27,10 @@ import java.util.Optional
 class BackupRepository(
     private val context: Context,
     private val dao: BackupItemDao,
-    private val spoofedSimInfoRepo: SpoofedSimInfoRepo
 ) {
     private val tag = "$baseTag/BackupRepository"
-    suspend fun backup(
-        spoofedSimInfo: SpoofedSimInfo,
-        type: String,
-        sendCount: Int,
-        stock: Boolean = false
-    ): BackupItem {
+    suspend fun backup(type: String, sendCount: Int, stock: Int = 0): BackupItem {
+        val spoofedSimInfoRepo = SpoofedSimInfoRepo.instance
         clearConv()
         delay(3000)
 //        ModifierService.instance!!.toggleRcsSwitch(false)
@@ -74,6 +72,7 @@ class BackupRepository(
 
         shellRun(*cmds.toTypedArray())
 
+        val spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value
         val backup = BackupItem(
             createdAt = Date().time,
             numberId = spoofedSimInfo.numberId,
@@ -98,38 +97,37 @@ class BackupRepository(
             File(it.path).deleteRecursively()
             dao.delete(it)
             backup.sendCount += it.sendCount
-            backup.stock = false
         }
 
         backup.id = dao.insert(backup).toInt()
         return backup
     }
 
+    @SuppressLint("SdCardPath")
     suspend fun restore(backup: BackupItem): Boolean {
-        spoofedSimInfoRepo.updateSpoofedSimInfo(
-            SpoofedSimInfo(
-                numberId = backup.numberId,
-                number = backup.number,
-                mcc = backup.mcc,
-                mnc = backup.mnc,
-                country = backup.country,
-                areaCode = backup.code,
-                iccid = backup.iccid,
-                imei = backup.imei,
-                imsi = backup.imsi,
-                available = true,
-                carrierId = backup.carrierId,
-                carrierName = backup.carrierName
-            ),
-            false
+        val spoofedSimInfoRepo = SpoofedSimInfoRepo.instance
+        val simInfo = SpoofedSimInfo(
+            numberId = backup.numberId,
+            number = backup.number,
+            mcc = backup.mcc,
+            mnc = backup.mnc,
+            country = backup.country,
+            areaCode = backup.code,
+            iccid = backup.iccid,
+            imei = backup.imei,
+            imsi = backup.imsi,
+            available = false,
+            carrierId = backup.carrierId,
+            carrierName = backup.carrierName
         )
+        spoofedSimInfoRepo.updateSpoofedSimInfo(spoofedSimInfo = simInfo, suspend = false)
         val packages = mutableListOf(
             PACKAGE_MESSAGING,
             PACKAGE_GMS,
             PACKAGE_GSF
         )
 
-        shellRun(PACKAGE_MESSAGING.disable())
+        shellRun(PACKAGE_MESSAGING.clear(), "sleep 2", PACKAGE_MESSAGING.disable())
         for (pkg in listOf(PACKAGE_MESSAGING)) {
             for (item in listOf("data.tar.gz", "data_de.tar.gz", "data_ext.tar.gz")) {
                 val file = File("${backup.path}/$pkg/$item")
@@ -184,9 +182,24 @@ class BackupRepository(
             "sleep 3",
             CMD_MESSAGING_APP,
             "sleep 5",
-            "am start -a android.intent.action.SENDTO -d sms:+18583199738 --es sms_body \"Test\" --ez exit_on_sent false"
         )
 
+        val taskRunner = ModifierService.instance?.taskRunner
+        if (true == taskRunner?.checkRcsA10y()) {
+            spoofedSimInfoRepo.updateSpoofedSimInfo(
+                spoofedSimInfo = simInfo.copy(available = true),
+                suspend = false
+            )
+            if (backup.stock == 1) {
+                RcsNumberApi.updateStockFlag(backup.numberId, 2)
+            }
+
+        } else {
+            if (backup.stock == 1) {
+                RcsNumberApi.updateStockFlag(backup.numberId, 3)
+            }
+        }
+
         return true
     }
 
@@ -194,7 +207,7 @@ class BackupRepository(
         dao.delete(backupItem)
     }
 
-    suspend fun findBackupForRestore(number: String, time: Long): BackupItem? {
-        return dao.findBackupForRestore(number, time)
+    suspend fun findBackupForRestore(number: String): BackupItem? {
+        return dao.findBackupForRestore(number)
     }
 }

+ 10 - 21
app/src/main/java/com/example/modifier/service/ModifierService.kt

@@ -5,7 +5,6 @@ import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.PixelFormat
 import android.os.Build
-import android.text.InputType
 import android.util.DisplayMetrics
 import android.util.Log
 import android.view.Gravity
@@ -18,7 +17,6 @@ import android.view.View.VISIBLE
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityEvent
 import android.widget.CompoundButton
-import android.widget.EditText
 import android.widget.FrameLayout
 import androidx.annotation.MenuRes
 import androidx.appcompat.widget.PopupMenu
@@ -28,10 +26,9 @@ import com.example.modifier.R
 import com.example.modifier.baseTag
 import com.example.modifier.TraverseResult
 import com.example.modifier.data.AppDatabase
-import com.example.modifier.data.AppState
 import com.example.modifier.databinding.FloatingWindowBinding
 import com.example.modifier.enums.RequestNumberState
-import com.example.modifier.model.SpoofedSimInfo
+import com.example.modifier.http.api.RcsNumberApi
 import com.example.modifier.repo.AppPrefsRepo
 import com.example.modifier.repo.AppStateRepo
 import com.example.modifier.repo.BackupRepository
@@ -42,16 +39,13 @@ import com.example.modifier.utils.hasRootAccess
 import com.example.modifier.utils.isRebooted
 import com.example.modifier.utils.killPhoneProcess
 import com.example.modifier.utils.optimize
-import com.example.modifier.utils.resetAll
 import com.example.modifier.utils.restartSelf
 import com.example.modifier.utils.setBatteryLevel
 import com.example.modifier.utils.syncTime
 import com.google.android.material.color.DynamicColors
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import java.util.Timer
@@ -64,9 +58,11 @@ import kotlin.time.Duration.Companion.seconds
 
 @SuppressLint("SetTextI18n")
 class ModifierService : AccessibilityService() {
+    @SuppressLint("StaticFieldLeak")
     companion object {
         private const val TAG = "$baseTag/Service"
         const val NAME: String = BuildConfig.APPLICATION_ID + ".service.ModifierService"
+        val instance: ModifierService? = null
     }
 
     private lateinit var binding: FloatingWindowBinding
@@ -78,15 +74,9 @@ class ModifierService : AccessibilityService() {
     private val screenInspector by lazy { ScreenInspector(this) }
     private val screenController by lazy { ScreenController(this, screenInspector) }
     private val spoofedSimInfoRepo = SpoofedSimInfoRepo.instance
-    private val backupRepository by lazy {
-        BackupRepository(
-            this,
-            backupItemDao,
-            spoofedSimInfoRepo
-        )
-    }
+    private val backupRepository by lazy { BackupRepository(this, backupItemDao) }
     private lateinit var socketClient: SocketClient
-    private lateinit var taskRunner: TaskRunner
+    lateinit var taskRunner: TaskRunner
     private lateinit var uiContext: Context
 
     override fun onAccessibilityEvent(event: AccessibilityEvent) {}
@@ -327,7 +317,7 @@ class ModifierService : AccessibilityService() {
 
         binding.btnReq.setOnClickListener {
             CoroutineScope(Dispatchers.IO).launch {
-                taskRunner.requestNumber(reset = false, noBackup = true)
+                taskRunner.requestNumberOnTask(reset = false, noBackup = true)
             }
         }
 
@@ -447,11 +437,10 @@ class ModifierService : AccessibilityService() {
                 appStateRepo.updateRuntimeFlags(requesting = false)
                 if (it < num - 1) {
                     appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.BACKUP)
-                    backupRepository.backup(
-                        spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value,
-                        type = "auto",
-                        sendCount = 0,
-                        stock = true
+                    backupRepository.backup(type = "auto", sendCount = 0, stock = 1)
+                    RcsNumberApi.updateStockFlag(
+                        id = spoofedSimInfoRepo.spoofedSimInfo.value.numberId,
+                        flag = 1
                     )
                 }
                 success = true

+ 4 - 2
app/src/main/java/com/example/modifier/service/ScreenInspector.kt

@@ -22,8 +22,10 @@ class ScreenInspector(val context: AccessibilityService) {
         if (node == null) {
             return
         }
-
-        val className = node.className.toString()
+        val packageInfo = context.packageManager.getPackageInfo(
+            node.packageName.toString(), 0
+        )
+        val className = node.className?.toString()
         val name = node.viewIdResourceName
         val text = Optional.ofNullable(node.text).map { obj: CharSequence -> obj.toString() }
             .orElse(null)

+ 9 - 29
app/src/main/java/com/example/modifier/service/TaskRunner.kt

@@ -1,8 +1,6 @@
 package com.example.modifier.service
 
 import android.content.Context
-import android.text.TextUtils
-import android.util.Base64
 import android.util.Log
 import android.view.accessibility.AccessibilityNodeInfo
 import com.example.modifier.baseTag
@@ -36,12 +34,10 @@ import com.example.modifier.repo.AppStateRepo
 import com.example.modifier.repo.BackupRepository
 import com.example.modifier.repo.GoogleMessageStateRepository
 import com.example.modifier.repo.SpoofedSimInfoRepo
-import com.example.modifier.utils.changeClashProfile
 import com.example.modifier.utils.clearConv
 import com.example.modifier.utils.genICCID
 import com.example.modifier.utils.genIMEI
 import com.example.modifier.utils.genIMSI
-import com.example.modifier.utils.isClashInstalled
 import com.example.modifier.utils.isOldVersion
 import com.example.modifier.utils.resetAll
 import com.example.modifier.utils.shellRun
@@ -59,8 +55,6 @@ import io.ktor.utils.io.core.isEmpty
 import io.ktor.utils.io.core.readBytes
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
@@ -70,7 +64,6 @@ import java.io.File
 import java.time.LocalDateTime
 import java.time.temporal.ChronoUnit
 import kotlin.coroutines.coroutineContext
-import kotlin.time.Duration.Companion.days
 import kotlin.time.Duration.Companion.hours
 import kotlin.time.Duration.Companion.minutes
 import kotlin.time.Duration.Companion.seconds
@@ -176,7 +169,7 @@ class TaskRunner(
                 appStateRepo.updateRuntimeFlags(checkingConnection = true)
                 if (!checkRcsA10y()) {
                     onError(Exception("RCS not available"))
-                    requestNumber()
+                    requestNumberOnTask()
                     appStateRepo.updateRuntimeFlags(checkingConnection = false)
                     return
                 }
@@ -203,7 +196,7 @@ class TaskRunner(
             onSuccess(TaskExecutionResult(success, fail))
             if (taskConfig.requestNumberInterval in 1..appStateRepo.appState.value.successNum) {
                 delay(3000)
-                requestNumber()
+                requestNumberOnTask()
             } else if (taskConfig.cleanCount in 1..appStateRepo.appState.value.executedNum && !appPrefsRepo.appPrefs.value.preventClean) {
                 delay(3000)
                 clearConv();
@@ -218,7 +211,7 @@ class TaskRunner(
                 appStateRepo.updateRuntimeFlags(checkingConnection = true)
                 if (!checkRcsA10y()) {
                     onError(Exception("RCS not available"))
-                    requestNumber()
+                    requestNumberOnTask()
                 }
                 appStateRepo.updateRuntimeFlags(checkingConnection = false)
             }
@@ -344,7 +337,7 @@ class TaskRunner(
                     Log.i(tag, "waitForRcsState: $resetSuccess")
                     appStateRepo.resetRequestedNum()
                     if (resetSuccess) {
-                        delay(3000)
+                        delay(1000)
                         break
                     }
                 }
@@ -473,11 +466,7 @@ class TaskRunner(
         }
     }
 
-    suspend fun requestNumber(
-        reset: Boolean = false,
-        noBackup: Boolean = false,
-        fresh: Boolean = false
-    ) {
+    suspend fun requestNumberOnTask(reset: Boolean = false, noBackup: Boolean = false) {
         appStateRepo.updateRuntimeFlags(suspended = false)
         if (appPrefsRepo.appPrefs.value.preventRequest) {
             return
@@ -491,10 +480,8 @@ class TaskRunner(
         if (spoofedSimInfoRepo.spoofedSimInfo.value.available) {
             appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.BACKUP)
             backupRepository.backup(
-                spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value,
                 type = "auto",
-                sendCount = appStateRepo.appState.value.successNum,
-                stock = fresh
+                sendCount = appStateRepo.appState.value.successNum
             )
         }
 
@@ -506,19 +493,13 @@ class TaskRunner(
                 try {
                     if (requestMode == 2 && !noBackup) {
                         val backup = backupRepository.findBackupForRestore(
-                            spoofedSimInfoRepo.spoofedSimInfo.value.number,
-                            System.currentTimeMillis() - 2.days.inWholeMilliseconds
+                            spoofedSimInfoRepo.spoofedSimInfo.value.number
                         )
                         if (backup != null) {
                             if (backupRepository.restore(backup)) {
                                 return@withTimeoutOrNull true
                             } else {
                                 appStateRepo.updateRuntimeFlags(requestNumberState = RequestNumberState.BACKUP)
-                                backupRepository.backup(
-                                    spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value,
-                                    type = "auto",
-                                    sendCount = 0
-                                )
                                 continue
                             }
                         }
@@ -544,9 +525,7 @@ class TaskRunner(
         }
         if (requestSuccess == true) {
             spoofedSimInfoRepo.updateSpoofedSimInfo(
-                spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value.copy(
-                    available = true
-                ),
+                spoofedSimInfo = spoofedSimInfoRepo.spoofedSimInfo.value.copy(available = true),
                 suspend = false
             )
             appStateRepo.resetSuccessNum()
@@ -701,4 +680,5 @@ class TaskRunner(
             onError(e)
         }
     }
+
 }

+ 83 - 8
app/src/main/java/com/example/modifier/ui/backup/BackupFragment.kt

@@ -1,11 +1,14 @@
 package com.example.modifier.ui.backup
 
 import android.content.Context
+import android.content.DialogInterface
 import android.os.Bundle
 import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
 import androidx.core.view.ViewCompat
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.widget.doAfterTextChanged
@@ -14,32 +17,32 @@ import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.asFlow
 import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
-import com.example.modifier.baseTag
 import com.example.modifier.adapter.BackupAdapter
+import com.example.modifier.baseTag
 import com.example.modifier.data.AppDatabase
 import com.example.modifier.data.BackupItem
 import com.example.modifier.databinding.FragmentBackupBinding
-import com.example.modifier.model.SpoofedSimInfo
 import com.example.modifier.repo.BackupRepository
-import com.example.modifier.repo.SpoofedSimInfoRepo
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.FlowPreview
-import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import java.io.File
 
 class BackupFragment : Fragment() {
     private val tag = "$baseTag/BackupFragment"
     private lateinit var binding: FragmentBackupBinding
     private val list = mutableListOf<BackupItem>()
     private lateinit var adapter: BackupAdapter
-    private val spoofedSimInfoRepo = SpoofedSimInfoRepo.instance
+    private lateinit var onItemClickListener: BackupAdapter.OnItemClickListener
     private val backupItemDao by lazy {
         AppDatabase.getDatabase(requireContext()).itemDao()
     }
     private val backupRepository by lazy {
-        BackupRepository(requireContext(), backupItemDao, spoofedSimInfoRepo)
+        BackupRepository(requireContext(), backupItemDao)
     }
     private var sort: Boolean
         get() {
@@ -51,6 +54,7 @@ class BackupFragment : Fragment() {
                 .putBoolean("sort", value).apply()
         }
     private val searchText = MutableLiveData<String>()
+    private lateinit var progressDialog: AlertDialog
 
     @OptIn(FlowPreview::class)
     override fun onCreateView(
@@ -58,8 +62,72 @@ class BackupFragment : Fragment() {
         savedInstanceState: Bundle?
     ): View {
         if (!this::binding.isInitialized) {
+            progressDialog = MaterialAlertDialogBuilder(requireContext())
+                .setTitle("Please wait...")
+                .setMessage("Processing...")
+                .setCancelable(false)
+                .create()
             binding = FragmentBackupBinding.inflate(inflater, container, false)
-            adapter = BackupAdapter(requireContext(), list, backupRepository)
+            onItemClickListener = object : BackupAdapter.OnItemClickListener {
+                override fun onRestoreClick(backup: BackupItem, position: Int) {
+                    MaterialAlertDialogBuilder(requireContext())
+                        .setTitle("Restore backup")
+                        .setMessage("Are you sure you want to restore this backup?")
+                        .setPositiveButton("Yes") { dialog: DialogInterface?, which: Int ->
+                            dialog?.dismiss()
+                            progressDialog.show()
+                            CoroutineScope(Dispatchers.IO).launch {
+                                try {
+                                    backupRepository.restore(backup)
+                                } catch (e: Exception) {
+                                    e.printStackTrace()
+                                }
+                                withContext(Dispatchers.Main) {
+                                    progressDialog.dismiss()
+                                    Toast.makeText(
+                                        requireContext(),
+                                        "Restore completed",
+                                        Toast.LENGTH_SHORT
+                                    ).show()
+                                }
+                            }
+                        }
+                        .setNegativeButton("No", null)
+                        .show()
+                }
+
+                override fun onDeleteClick(backup: BackupItem, position: Int) {
+                    progressDialog.show()
+                    CoroutineScope(Dispatchers.IO).launch {
+                        val file = File(backup.path)
+                        if (file.exists()) {
+                            try {
+                                File(backup.path).deleteRecursively()
+
+                            } catch (e: Exception) {
+                                e.printStackTrace()
+                                Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
+                            }
+                        } else {
+                            Log.e("BackupAdapter", "File not found")
+                        }
+                        list.remove(backup)
+                        withContext(Dispatchers.Main) {
+                            adapter.notifyDataSetChanged()
+                        }
+                        backupRepository.delete(backup)
+                        withContext(Dispatchers.Main) {
+                            progressDialog.dismiss()
+                            Toast.makeText(
+                                requireContext(),
+                                "Backup deleted",
+                                Toast.LENGTH_SHORT
+                            ).show()
+                        }
+                    }
+                }
+            }
+            adapter = BackupAdapter(requireContext(), list, onItemClickListener)
             binding.rvBackup.adapter = adapter
             binding.rvBackup.layoutManager = LinearLayoutManager(requireContext())
             binding.btnSort.setOnClickListener {
@@ -72,11 +140,18 @@ class BackupFragment : Fragment() {
             }
             binding.btnAdd.setOnClickListener {
                 lifecycleScope.launch {
+                    progressDialog.show()
                     withContext(Dispatchers.IO) {
-                        val backup = backupRepository.backup(spoofedSimInfoRepo.spoofedSimInfo.value, "manual", 0)
+                        val backup = backupRepository.backup(type = "manual", sendCount = 0)
                         list.add(0, backup)
                     }
                     adapter.notifyItemInserted(0)
+                    progressDialog.dismiss()
+                    Toast.makeText(
+                        requireContext(),
+                        "Backup created",
+                        Toast.LENGTH_SHORT
+                    ).show()
                 }
             }
             binding.etSearch.doAfterTextChanged {

+ 7 - 3
app/src/main/java/com/example/modifier/utils/System.kt

@@ -154,10 +154,14 @@ suspend fun optimize() {
         "dumpsys deviceidle whitelist +com.google.android.apps.messaging",
         "dumpsys deviceidle whitelist +${BuildConfig.APPLICATION_ID}",
         "cmd netpolicy add restrict-background-blacklist ${info.uid}",
-        "settings put global window_animation_scale 0",
-        "settings put global transition_animation_scale 0",
-        "settings put global animator_duration_scale 0"
     )
+    if (Build.MODEL.startsWith("SM-F707") || Build.MODEL.startsWith("SM-F711")) {
+        shellRun(
+            "settings put global window_animation_scale 0",
+            "settings put global transition_animation_scale 0",
+            "settings put global animator_duration_scale 0"
+        )
+    }
 }
 
 suspend fun syncTime() {

+ 0 - 1
app/src/main/res/layout/item_backup.xml

@@ -52,7 +52,6 @@
                         app:layout_constraintTop_toTopOf="parent" />
                 </androidx.constraintlayout.widget.ConstraintLayout>
 
-
                 <com.google.android.material.textview.MaterialTextView
                     android:id="@+id/tv_info"
                     android:layout_width="wrap_content"