diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 103e00c..44ca2d9 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -3,30 +3,39 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 7667460..e4c0e5c 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -13,7 +13,7 @@ android {
minSdk = 31
targetSdk = 34
versionCode = 1
- versionName = "2.0.0"
+ versionName = "3.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -56,6 +56,9 @@ dependencies {
// YukiHook
implementation ("com.highcapable.yukihookapi:api:1.2.0")
+ // RootBear
+ implementation("com.scottyab:rootbeer-lib:0.1.0")
+
// Compose
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5e0be84..8e1c5aa 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,11 @@
-
+
+
+
+
+
+
+
+
+
+
+ android:screenOrientation="portrait"
+ android:theme="@style/Theme.NotificationCode">
diff --git a/app/src/main/assets/xposed_init b/app/src/main/assets/xposed_init
index f2b6885..9819d79 100644
--- a/app/src/main/assets/xposed_init
+++ b/app/src/main/assets/xposed_init
@@ -1 +1 @@
-ru.n00byara.notificationcode.hook.Hook_YukiHookXposedInit
\ No newline at end of file
+ru.n00byara.notificationcode.components.hook.Hook_YukiHookXposedInit
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/Constants.kt b/app/src/main/java/ru/n00byara/notificationcode/Constants.kt
index e00b632..305cc4d 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/Constants.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/Constants.kt
@@ -7,4 +7,10 @@ object Constants {
const val SWITCH_CODE = "switch_code"
const val SWITCH_PHONE = "switch_phone"
const val SWITHC_TRACK_NUMBER = "switch_track_number"
+ const val USE_CASE = "use_case"
+ const val EXTRA_TEXT = "android.text"
+ const val EXTRA_TITLE = "android.title"
+ const val SHAZAM_APP_NAME = "Shazam"
+ const val SHAZAM_CHANNEL_ID = "notification_shazam_match_v1"
+ const val SHAZAM_PACKAGE = "com.shazam.android"
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/components/application/ApplicationsList.kt b/app/src/main/java/ru/n00byara/notificationcode/components/application/ApplicationsList.kt
new file mode 100644
index 0000000..fb2a266
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/application/ApplicationsList.kt
@@ -0,0 +1,37 @@
+package ru.n00byara.notificationcode.components.application
+
+import android.content.Context
+import android.content.pm.PackageManager
+
+class ApplicationsList(private val context: Context) {
+ private val pm = context.packageManager
+ private val allInstalledApplications = pm.getInstalledApplications(PackageManager.GET_META_DATA)
+
+ fun getApplications(): List {
+ var result = mutableListOf()
+
+ allInstalledApplications.forEach { applicationInfo ->
+ val appInfo = InstalledAppInfo(this.pm, applicationInfo)
+
+ if (!appInfo.isSystem && appInfo.name != "Shazam") {
+ result.add(appInfo)
+ }
+ }
+
+ return result
+ }
+
+ fun getAllApplications(): List {
+ var result = mutableListOf()
+
+ allInstalledApplications.forEach { applicationInfo ->
+ val appInfo = InstalledAppInfo(this.pm, applicationInfo)
+
+ if (!appInfo.isSystem) {
+ result.add(appInfo)
+ }
+ }
+
+ return result
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/applicationinfo/HookedAppInfo.kt b/app/src/main/java/ru/n00byara/notificationcode/components/application/HookedAppInfo.kt
similarity index 83%
rename from app/src/main/java/ru/n00byara/notificationcode/applicationinfo/HookedAppInfo.kt
rename to app/src/main/java/ru/n00byara/notificationcode/components/application/HookedAppInfo.kt
index f4e5beb..6939d2f 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/applicationinfo/HookedAppInfo.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/application/HookedAppInfo.kt
@@ -1,4 +1,4 @@
-package ru.n00byara.notificationcode.applicationinfo
+package ru.n00byara.notificationcode.components.application
import android.content.Context
import android.content.pm.ApplicationInfo
@@ -11,13 +11,15 @@ class HookedAppInfo(hookedContext: Context) {
val isActive: Boolean
val isSystem: Boolean
val name: String
+ val packageName: String
init {
val pm = hookedContext.packageManager
val applicationInfo = hookedContext.applicationInfo
name = applicationInfo.loadLabel(pm).toString()
+ packageName = applicationInfo.packageName
isSystem = !((applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 0)
- isActive = prefs.getBoolean(Constants.APPLICATION_PREF + name)
+ isActive = prefs.getBoolean(Constants.APPLICATION_PREF + packageName)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/applicationinfo/InstalledAppInfo.kt b/app/src/main/java/ru/n00byara/notificationcode/components/application/InstalledAppInfo.kt
similarity index 56%
rename from app/src/main/java/ru/n00byara/notificationcode/applicationinfo/InstalledAppInfo.kt
rename to app/src/main/java/ru/n00byara/notificationcode/components/application/InstalledAppInfo.kt
index 5bfc23c..ac9d838 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/applicationinfo/InstalledAppInfo.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/application/InstalledAppInfo.kt
@@ -1,18 +1,24 @@
-package ru.n00byara.notificationcode.applicationinfo
+package ru.n00byara.notificationcode.components.application
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import ru.n00byara.notificationcode.Constants
+import ru.n00byara.notificationcode.models.SettingsModel
class InstalledAppInfo(private val pm: PackageManager, private val applicationInfo: ApplicationInfo) {
+ val settingsModel = SettingsModel()
val name: String
val icon: Drawable
val isSystem: Boolean
+ val packageName: String
+ val isActive: Boolean
init {
name = applicationInfo.loadLabel(pm).toString()
+ packageName = applicationInfo.packageName
isSystem = !((applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 0)
-
+ isActive = settingsModel.getBoolean(Constants.APPLICATION_PREF + packageName)
icon = applicationInfo.loadIcon(pm)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/clip/Clip.kt b/app/src/main/java/ru/n00byara/notificationcode/components/clip/Clip.kt
similarity index 86%
rename from app/src/main/java/ru/n00byara/notificationcode/clip/Clip.kt
rename to app/src/main/java/ru/n00byara/notificationcode/components/clip/Clip.kt
index 468e5a6..c5fb558 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/clip/Clip.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/clip/Clip.kt
@@ -1,16 +1,19 @@
-package ru.n00byara.notificationcode.clip
+package ru.n00byara.notificationcode.components.clip
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
-import com.highcapable.yukihookapi.hook.factory.prefs
-import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
+import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge
import ru.n00byara.notificationcode.Constants
import java.util.regex.Matcher
import java.util.regex.Pattern
-class Clip(private val context: Context, private val contentText: CharSequence, private val contentTitle: CharSequence? = null) {
- val prefs = ModuleApplication().prefs(Constants.SETTINGS_NAME)
+class Clip(
+ private val context: Context,
+ private val contentText: CharSequence,
+ private val contentTitle: CharSequence? = null,
+ val prefs: YukiHookPrefsBridge
+) {
val regExps = RegExps.regExps
val compositeRegExp = RegExps.regExpForCompositeCode
diff --git a/app/src/main/java/ru/n00byara/notificationcode/clip/RegExps.kt b/app/src/main/java/ru/n00byara/notificationcode/components/clip/RegExps.kt
similarity index 91%
rename from app/src/main/java/ru/n00byara/notificationcode/clip/RegExps.kt
rename to app/src/main/java/ru/n00byara/notificationcode/components/clip/RegExps.kt
index 2418961..95a2e01 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/clip/RegExps.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/clip/RegExps.kt
@@ -1,4 +1,4 @@
-package ru.n00byara.notificationcode.clip
+package ru.n00byara.notificationcode.components.clip
object RegExps {
val regExps = listOf(
diff --git a/app/src/main/java/ru/n00byara/notificationcode/hook/Hook.kt b/app/src/main/java/ru/n00byara/notificationcode/components/hook/Hook.kt
similarity index 78%
rename from app/src/main/java/ru/n00byara/notificationcode/hook/Hook.kt
rename to app/src/main/java/ru/n00byara/notificationcode/components/hook/Hook.kt
index d54b7d8..a33fdc8 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/hook/Hook.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/hook/Hook.kt
@@ -1,11 +1,11 @@
-package ru.n00byara.notificationcode.hook
+package ru.n00byara.notificationcode.components.hook
import com.highcapable.yukihookapi.YukiHookAPI.encase
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
import ru.n00byara.notificationcode.Constants
-import ru.n00byara.notificationcode.hook.entity.SystemUIHooker
+import ru.n00byara.notificationcode.components.hook.entity.SystemUIHooker
@InjectYukiHookWithXposed
object Hook : IYukiHookXposedInit {
diff --git a/app/src/main/java/ru/n00byara/notificationcode/components/hook/entity/SystemUIHooker.kt b/app/src/main/java/ru/n00byara/notificationcode/components/hook/entity/SystemUIHooker.kt
new file mode 100644
index 0000000..37640db
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/hook/entity/SystemUIHooker.kt
@@ -0,0 +1,68 @@
+package ru.n00byara.notificationcode.components.hook.entity
+
+import android.app.Notification
+import android.content.Context
+import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
+import com.highcapable.yukihookapi.hook.factory.constructor
+import com.highcapable.yukihookapi.hook.factory.prefs
+import com.highcapable.yukihookapi.hook.type.android.ContextClass
+import com.highcapable.yukihookapi.hook.type.android.NotificationClass
+import com.highcapable.yukihookapi.hook.type.android.Notification_BuilderClass
+import com.highcapable.yukihookapi.hook.type.android.ParcelClass
+import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
+import ru.n00byara.notificationcode.Constants
+import ru.n00byara.notificationcode.components.application.HookedAppInfo
+import ru.n00byara.notificationcode.components.clip.Clip
+
+object SystemUIHooker : YukiBaseHooker() {
+ override fun onHook() {
+ loadApp {
+ val prefs = ModuleApplication().prefs(Constants.SETTINGS_NAME)
+ var context: Context? = null
+
+ Notification_BuilderClass.constructor {
+ param(ContextClass, NotificationClass)
+ }.hook {
+ after {
+ context = args(0).cast()
+ }
+ }
+
+ NotificationClass.constructor {
+ param(ParcelClass)
+ }.hook().after {
+ if (prefs.getInt(Constants.USE_CASE) == 0) {
+ val notification = instance()
+
+ context?.let { context ->
+ val appInfo = HookedAppInfo(context)
+
+ if (appInfo.isSystem) {
+ notification.extras?.let { extras ->
+ extras.getCharSequence(Constants.EXTRA_TEXT)?.let { contentText ->
+ Clip(appContext!!, contentText, prefs = prefs)
+ }
+ }
+ } else {
+ if (appInfo.isActive) {
+ notification.extras?.let { extras ->
+ extras.getCharSequence(Constants.EXTRA_TEXT)?.let { contentText ->
+ if (appInfo.name == Constants.SHAZAM_APP_NAME && notification.getChannelId() == Constants.SHAZAM_CHANNEL_ID) {
+ val contentTitle = extras.getCharSequence(Constants.EXTRA_TITLE)
+
+ Clip(appContext!!, contentText, contentTitle, prefs = prefs)
+ } else {
+ Clip(appContext!!, contentText, prefs = prefs)
+ }
+ }
+ }
+ } else {
+ // .. ??
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/components/permission/Permission.kt b/app/src/main/java/ru/n00byara/notificationcode/components/permission/Permission.kt
new file mode 100644
index 0000000..1fc8000
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/permission/Permission.kt
@@ -0,0 +1,20 @@
+package ru.n00byara.notificationcode.components.permission
+
+import android.content.Context
+import android.content.Intent
+import android.provider.Settings
+
+class Permission(private val context: Context) {
+ fun requestPermissions() {
+ val intent = Intent(this.context, PermissionRequestActivity::class.java)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ context.startActivity(intent)
+ }
+
+ fun checkPermission(): Boolean {
+ val notificationListener =
+ arrayOf(Settings.Secure.getString(context.contentResolver, "enabled_notification_listeners")).joinToString()
+
+ return notificationListener.contains(this.context.packageName)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/components/permission/PermissionRequestActivity.kt b/app/src/main/java/ru/n00byara/notificationcode/components/permission/PermissionRequestActivity.kt
new file mode 100644
index 0000000..8394ff0
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/permission/PermissionRequestActivity.kt
@@ -0,0 +1,22 @@
+package ru.n00byara.notificationcode.components.permission
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+/* This class is bullshit because I don't find way of start activity from view model. */
+
+class PermissionRequestActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (savedInstanceState == null) {
+ requestPermissions()
+ }
+ }
+
+ private fun requestPermissions() {
+ val intent = Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS")
+ startActivityForResult(intent, 0)
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/components/service/NotificationService.kt b/app/src/main/java/ru/n00byara/notificationcode/components/service/NotificationService.kt
new file mode 100644
index 0000000..afc788f
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/components/service/NotificationService.kt
@@ -0,0 +1,47 @@
+package ru.n00byara.notificationcode.components.service
+
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+import com.highcapable.yukihookapi.hook.factory.prefs
+import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
+import ru.n00byara.notificationcode.Constants
+import ru.n00byara.notificationcode.components.application.ApplicationsList
+import ru.n00byara.notificationcode.components.clip.Clip
+
+class NotificationService : NotificationListenerService() {
+ val prefs = ModuleApplication.appContext.prefs(Constants.SETTINGS_NAME)
+ override fun onNotificationPosted(sbn: StatusBarNotification) {
+ val applicationsList = ApplicationsList(this.baseContext).getAllApplications()
+ val appInfo = applicationsList.find { it.packageName == sbn.packageName }
+
+ if (prefs.getInt(Constants.USE_CASE) == 1) {
+ appInfo?.let { appInfo ->
+ val notification = sbn.notification
+
+ if (appInfo.isSystem) {
+ notification.extras?.let { extras ->
+ extras.getCharSequence(Constants.EXTRA_TEXT)?.let { contentText ->
+ Clip(this.baseContext, contentText, prefs = prefs)
+ }
+ }
+ } else {
+ if (appInfo.isActive) {
+ notification.extras?.let { extras ->
+ extras.getCharSequence(Constants.EXTRA_TEXT)?.let { contentText ->
+ if (appInfo.name == Constants.SHAZAM_APP_NAME && notification.channelId == Constants.SHAZAM_CHANNEL_ID) {
+ val contentTitle = extras.getCharSequence(Constants.EXTRA_TITLE)
+
+ Clip(this.baseContext, contentText, contentTitle, prefs = prefs)
+ } else {
+ Clip(this.baseContext, contentText, prefs = prefs)
+ }
+ }
+ }
+ } else {
+ // .. ??
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/hook/entity/SystemUIHooker.kt b/app/src/main/java/ru/n00byara/notificationcode/hook/entity/SystemUIHooker.kt
deleted file mode 100644
index 61e0341..0000000
--- a/app/src/main/java/ru/n00byara/notificationcode/hook/entity/SystemUIHooker.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package ru.n00byara.notificationcode.hook.entity
-
-import android.app.Notification
-import android.content.Context
-import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
-import com.highcapable.yukihookapi.hook.factory.constructor
-import com.highcapable.yukihookapi.hook.type.android.ContextClass
-import com.highcapable.yukihookapi.hook.type.android.NotificationClass
-import com.highcapable.yukihookapi.hook.type.android.Notification_BuilderClass
-import com.highcapable.yukihookapi.hook.type.android.ParcelClass
-import ru.n00byara.notificationcode.applicationinfo.HookedAppInfo
-import ru.n00byara.notificationcode.clip.Clip
-
-object SystemUIHooker : YukiBaseHooker() {
- const val EXTRA_TEXT = "android.text"
- const val EXTRA_TITLE = "android.title"
- override fun onHook() {
- loadApp {
- var context: Context? = null
-
- Notification_BuilderClass.constructor {
- param(ContextClass, NotificationClass)
- }.hook {
- after {
- context = args(0).cast()
- }
- }
-
- NotificationClass.constructor {
- param(ParcelClass)
- }.hook().after {
- val notification = instance()
-
- context?.let { context ->
- val appInfo = HookedAppInfo(context)
-
- if (appInfo.isSystem) {
- notification.extras?.let { extras ->
- extras.getCharSequence(EXTRA_TEXT)?.let { contentText ->
- Clip(appContext!!, contentText)
- }
- }
- } else {
- if (appInfo.isActive) {
- notification.extras?.let { extras ->
- extras.getCharSequence(EXTRA_TEXT)?.let { contentText ->
- if (appInfo.name == "Shazam" && notification.getChannelId() == "notification_shazam_match_v1") {
- val contentTitle = extras.getCharSequence(EXTRA_TITLE)
-
- Clip(appContext!!, contentText, contentTitle)
- } else {
- Clip(appContext!!, contentText)
- }
- }
- }
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/models/SettingsModel.kt b/app/src/main/java/ru/n00byara/notificationcode/models/SettingsModel.kt
index b61f97d..bdcb177 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/models/SettingsModel.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/models/SettingsModel.kt
@@ -9,8 +9,8 @@ class SettingsModel {
private val prefs = ModuleApplication.appContext.prefs(Constants.SETTINGS_NAME)
val isActive = YukiHookAPI.Status.isXposedModuleActive
- fun getBoolean(prefName: String): Boolean {
- return this.prefs.getBoolean(prefName, )
+ fun getBoolean(prefName: String, value: Boolean = false): Boolean {
+ return this.prefs.getBoolean(prefName, value)
}
fun setBoolean(prefName: String, value: Boolean) {
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt
new file mode 100644
index 0000000..2d6a93a
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/GlobalSettingsActivity.kt
@@ -0,0 +1,38 @@
+package ru.n00byara.notificationcode.ui.activities
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.lifecycle.ViewModelProvider
+import ru.n00byara.notificationcode.ui.components.topbar.TopBar
+import ru.n00byara.notificationcode.ui.theme.NotificationCodeTheme
+import ru.n00byara.notificationcode.ui.screens.GlobalSettingsScreen
+import ru.n00byara.notificationcode.ui.viewmodels.GlobalSettingsActivityViewModel
+import ru.n00byara.notificationcode.ui.viewmodels.GlobalSettingsActivityViewModelFactory
+import ru.n00byara.notificationcode.ui.viewmodels.GlobalSettingsScreenViewModel
+
+class GlobalSettingsActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val globalSettingsScreenViewModel = ViewModelProvider(this).get(GlobalSettingsScreenViewModel::class.java)
+ val globalSettingsActivityViewModel = ViewModelProvider(this, GlobalSettingsActivityViewModelFactory(this::finish)).get(GlobalSettingsActivityViewModel::class.java)
+
+ setContent {
+ NotificationCodeTheme {
+ val topBarModel by globalSettingsActivityViewModel.topBarUiState.collectAsState()
+
+ Scaffold(
+ topBar = {
+ TopBar(topBarModel)
+ }
+ ) { paddingValues ->
+ GlobalSettingsScreen(globalSettingsScreenViewModel, globalSettingsActivityViewModel::setTopBarTitle, paddingValues)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/MainActivity.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt
similarity index 57%
rename from app/src/main/java/ru/n00byara/notificationcode/ui/activities/MainActivity.kt
rename to app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt
index d9781e8..c45053e 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/activities/MainActivity.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/activities/SettingsActivity.kt
@@ -4,13 +4,10 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@@ -18,42 +15,53 @@ import androidx.navigation.compose.rememberNavController
import ru.n00byara.notificationcode.ui.components.bottomnavigationbar.BottomNavBar
import ru.n00byara.notificationcode.ui.components.bottomnavigationbar.BottomNavBarModel
import ru.n00byara.notificationcode.ui.components.bottomnavigationbar.Screen
+import ru.n00byara.notificationcode.ui.components.permissionalertdialog.PermissionAlertDialog
import ru.n00byara.notificationcode.ui.components.topbar.TopBar
-import ru.n00byara.notificationcode.ui.components.topbar.TopBarModel
+import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialog
import ru.n00byara.notificationcode.ui.screens.ApplicationsScreen
import ru.n00byara.notificationcode.ui.screens.SettingsScreen
import ru.n00byara.notificationcode.ui.theme.NotificationCodeTheme
import ru.n00byara.notificationcode.ui.viewmodels.ApplicationsScreenViewModel
-import ru.n00byara.notificationcode.ui.viewmodels.MainActivityViewModel
+import ru.n00byara.notificationcode.ui.viewmodels.SettingsActivityViewModel
import ru.n00byara.notificationcode.ui.viewmodels.SettingsScreenViewModel
-class MainActivity : ComponentActivity() {
+class SettingsActivity : ComponentActivity() {
companion object {
const val PREF_SCREEN_ROUTE = "selected_screen_route"
const val PREF_SCREEN_SELECTED = "selected_screen_index"
}
- @OptIn(ExperimentalMaterial3Api::class)
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val mainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
+ val settingsActivityViewModel = ViewModelProvider(this).get(SettingsActivityViewModel::class.java)
val settingsScreenViewModel = ViewModelProvider(this).get(SettingsScreenViewModel::class.java)
val applicationsScreenViewModel = ViewModelProvider(this).get(ApplicationsScreenViewModel::class.java)
setContent {
NotificationCodeTheme {
- val topBarTitle = ""
- val topBarTitleState = remember {
- mutableStateOf(topBarTitle)
+ val openRootDialogState = settingsActivityViewModel.openRootDialogState
+ if (openRootDialogState.value) {
+ val useCaseAlertDialogModel by settingsActivityViewModel.useCaseAlertDialogUiState.collectAsState()
+ UseCaseAlertDialog(useCaseAlertDialogModel)
+ }
+
+ val openNonRootDialogState = settingsActivityViewModel.openNonRootDialogState
+ if (openNonRootDialogState.value) {
+ val permissionAlertDialogModel by settingsActivityViewModel.permissionAlertDialogState.collectAsState()
+ PermissionAlertDialog(permissionAlertDialogModel)
}
- val topBarModel = TopBarModel(topBarTitleState)
+
+
+ val topBarModel by settingsActivityViewModel.topBarUiState.collectAsState()
val navController = rememberNavController()
+
val bottomNavBarModel = BottomNavBarModel(
- navController,
- PREF_SCREEN_SELECTED,
- mainActivityViewModel.getScreenSelected(PREF_SCREEN_SELECTED, 0),
- mainActivityViewModel::setScreenSelected
+ navController = navController,
+ prefName = PREF_SCREEN_SELECTED,
+ selected = settingsActivityViewModel.getScreenSelected(PREF_SCREEN_SELECTED, 0),
+ setSelected = settingsActivityViewModel::setScreenSelected
)
Scaffold(
@@ -66,22 +74,22 @@ class MainActivity : ComponentActivity() {
) { innerPadding ->
NavHost(
navController,
- startDestination = mainActivityViewModel.getScreenRoute(PREF_SCREEN_ROUTE, Screen.Settings.route),
+ settingsActivityViewModel.getScreenRoute(PREF_SCREEN_ROUTE, Screen.Settings.route),
Modifier.padding(innerPadding)
) {
composable(Screen.Settings.route) {
- mainActivityViewModel.setScreenRoute(PREF_SCREEN_ROUTE, Screen.Settings.route)
+ settingsActivityViewModel.setScreenRoute(PREF_SCREEN_ROUTE, Screen.Settings.route)
SettingsScreen(
settingsScreenViewModel,
- topBarTitleState,
+ settingsActivityViewModel::updateTopBarTitle
)
}
composable(Screen.ApplicationsList.route) {
- mainActivityViewModel.setScreenRoute(PREF_SCREEN_ROUTE, Screen.ApplicationsList.route)
+ settingsActivityViewModel.setScreenRoute(PREF_SCREEN_ROUTE, Screen.ApplicationsList.route)
ApplicationsScreen(
applicationsScreenViewModel,
- topBarTitleState
+ settingsActivityViewModel::updateTopBarTitle
)
}
}
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocard/ApplicationInfoCheckBox.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocheckbox/ApplicationInfoCheckBox.kt
similarity index 97%
rename from app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocard/ApplicationInfoCheckBox.kt
rename to app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocheckbox/ApplicationInfoCheckBox.kt
index 3dfb4d4..87ea4e8 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocard/ApplicationInfoCheckBox.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocheckbox/ApplicationInfoCheckBox.kt
@@ -1,4 +1,4 @@
-package ru.n00byara.notificationcode.ui.components.applicationinfocard
+package ru.n00byara.notificationcode.ui.components.applicationinfocheckbox
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
@@ -34,14 +34,14 @@ fun ApplicationInfoCheckBox(
}
Card(
- modifier =Modifier
+ modifier = Modifier
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp, top = 7.dp, bottom = 7.dp)
.clip(RoundedCornerShape(19.dp))
.clickable {
checkedState.value = !checkedState.value
applicationInfoCheckBoxModel.setState(
- Constants.APPLICATION_PREF + applicationInfoCheckBoxModel.appInfo.name,
+ Constants.APPLICATION_PREF + applicationInfoCheckBoxModel.appInfo.packageName,
checkedState.value
)
}
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocard/ApplicationInfoCheckBoxModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocheckbox/ApplicationInfoCheckBoxModel.kt
similarity index 71%
rename from app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocard/ApplicationInfoCheckBoxModel.kt
rename to app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocheckbox/ApplicationInfoCheckBoxModel.kt
index 38ecdef..5c1b436 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocard/ApplicationInfoCheckBoxModel.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/applicationinfocheckbox/ApplicationInfoCheckBoxModel.kt
@@ -1,6 +1,6 @@
-package ru.n00byara.notificationcode.ui.components.applicationinfocard
+package ru.n00byara.notificationcode.ui.components.applicationinfocheckbox
-import ru.n00byara.notificationcode.applicationinfo.InstalledAppInfo
+import ru.n00byara.notificationcode.components.application.InstalledAppInfo
data class ApplicationInfoCheckBoxModel(
val appInfo: InstalledAppInfo,
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt
index 75c3246..039a784 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/bottomnavigationbar/BottomNavBar.kt
@@ -1,5 +1,6 @@
package ru.n00byara.notificationcode.ui.components.bottomnavigationbar
+import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
@@ -13,9 +14,16 @@ import androidx.compose.ui.res.stringResource
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.currentBackStackEntryAsState
+import com.google.accompanist.systemuicontroller.rememberSystemUiController
@Composable
fun BottomNavBar(bottomNavBarModel: BottomNavBarModel) {
+ val systemUiController = rememberSystemUiController()
+ systemUiController.setNavigationBarColor(
+ Color.Transparent,
+ darkIcons = !isSystemInDarkTheme()
+ )
+
val items = listOf(Screen.Settings, Screen.ApplicationsList)
val selectedState by remember {
mutableStateOf(bottomNavBarModel.selected)
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissionalertdialog/PermissionAlertDialog.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissionalertdialog/PermissionAlertDialog.kt
new file mode 100644
index 0000000..2c8ed72
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissionalertdialog/PermissionAlertDialog.kt
@@ -0,0 +1,88 @@
+package ru.n00byara.notificationcode.ui.components.permissionalertdialog
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Card
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import ru.n00byara.notificationcode.R
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun PermissionAlertDialog(permissionAlertDialogModel: PermissionAlertDialogModel) {
+ AlertDialog(
+ onDismissRequest = {
+ permissionAlertDialogModel.openDialogState.value = false
+ },
+ ) {
+ Card(
+ modifier = Modifier
+ .wrapContentHeight()
+ .clip(RoundedCornerShape(19.dp))
+ ) {
+ Column(
+ modifier = Modifier
+ .padding(10.dp)
+ ) {
+ Row(
+ modifier = Modifier.padding(start = 7.dp, end = 7.dp, top = 7.dp, bottom = 15.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.alert_dialog_permisson_firs_launch_text),
+ fontSize = 20.sp
+ )
+ }
+
+ Row(
+ modifier = Modifier
+ .padding(start = 20.dp, end = 20.dp)
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Button(
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onSecondaryContainer
+ ),
+ onClick = {
+ permissionAlertDialogModel.openSettings()
+ permissionAlertDialogModel.openDialogState.value = false
+ }
+ ) {
+ Text(
+ text = stringResource(R.string.alert_dealog_permission_first_launch_ok)
+ )
+ }
+
+ Button(
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onSecondaryContainer
+ ),
+ onClick = { permissionAlertDialogModel.openDialogState.value = false }
+ ) {
+ Text(
+ text = stringResource(R.string.alert_dealog_permission_first_launch_cancel)
+ )
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissionalertdialog/PermissionAlertDialogModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissionalertdialog/PermissionAlertDialogModel.kt
new file mode 100644
index 0000000..3c726d0
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/permissionalertdialog/PermissionAlertDialogModel.kt
@@ -0,0 +1,8 @@
+package ru.n00byara.notificationcode.ui.components.permissionalertdialog
+
+import androidx.compose.runtime.MutableState
+
+data class PermissionAlertDialogModel(
+ val openDialogState: MutableState,
+ val openSettings: () -> Unit
+)
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt
index 0cc4dbc..b552e0b 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/Switcher.kt
@@ -26,7 +26,7 @@ fun Switcher(switcherModel: SwitcherModel) {
mutableStateOf(switcherModel.state)
}
- if (!switcherModel.moduleActive) chechedState.value = false
+ if (!switcherModel.moduleActive && switcherModel.isRoot) chechedState.value = false
Card(
Modifier
@@ -49,7 +49,9 @@ fun Switcher(switcherModel: SwitcherModel) {
Switch(
chechedState.value,
{
- if (switcherModel.moduleActive) {
+ if (
+ (switcherModel.moduleActive && switcherModel.isRoot) || (!switcherModel.moduleActive && !switcherModel.isRoot)
+ ) {
chechedState.value = it
switcherModel.setState(switcherModel.prefName, it)
}
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt
index ba8fee0..5caaec7 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/switcher/SwitcherModel.kt
@@ -5,5 +5,6 @@ data class SwitcherModel(
val prefName: String,
val state: Boolean,
val setState: (String, Boolean) -> Unit,
- val moduleActive: Boolean
+ val moduleActive: Boolean,
+ val isRoot: Boolean
)
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt
index 116510f..5174143 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBar.kt
@@ -14,11 +14,9 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
@Composable
fun TopBar(topBarModel: TopBarModel) {
val systemUiController = rememberSystemUiController()
- systemUiController.setSystemBarsColor(
+ systemUiController.setStatusBarColor(
Color.Transparent,
- darkIcons =
- if (isSystemInDarkTheme()) false
- else true
+ darkIcons = !isSystemInDarkTheme()
)
CenterAlignedTopAppBar(
@@ -29,12 +27,11 @@ fun TopBar(topBarModel: TopBarModel) {
),
title = {
Text(
- topBarModel.title.value
+ topBarModel.title
)
},
- actions = {
-
- },
+ navigationIcon = { topBarModel.navigationIcon?.invoke() },
+ actions = { topBarModel.actions?.invoke(this) },
scrollBehavior = topBarModel.scrollBehavior,
)
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBarModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBarModel.kt
index 92b423a..3fa4321 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBarModel.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/topbar/TopBarModel.kt
@@ -1,10 +1,13 @@
package ru.n00byara.notificationcode.ui.components.topbar
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.Composable
data class TopBarModel @OptIn(ExperimentalMaterial3Api::class) constructor(
- val title: MutableState,
- val scrollBehavior: TopAppBarScrollBehavior? = null
+ var title: String = "",
+ val scrollBehavior: TopAppBarScrollBehavior? = null,
+ val actions: (@Composable RowScope.() -> Unit)? = null,
+ val navigationIcon: (@Composable ()-> Unit)? = null
)
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt
new file mode 100644
index 0000000..b0783db
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialog.kt
@@ -0,0 +1,94 @@
+package ru.n00byara.notificationcode.ui.components.usecasealertdialog
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.selection.selectableGroup
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Card
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.RadioButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import ru.n00byara.notificationcode.R
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun UseCaseAlertDialog(useCaseAlertDialogModel: UseCaseAlertDialogModel) {
+ AlertDialog(
+ onDismissRequest = {
+ useCaseAlertDialogModel.openDialogState.value = false
+ },
+ ) {
+ val cases = listOf(R.string.alert_dialog_use_case_root, R.string.alert_dialog_use_case_non_root)
+
+ Card(
+ modifier = Modifier
+ .wrapContentHeight()
+ .clip(RoundedCornerShape(19.dp))
+ ) {
+ Column(
+ modifier = Modifier.padding(10.dp)
+ ) {
+ Row(
+ modifier = Modifier
+ .padding(7.dp)
+ .fillMaxWidth()
+ ) {
+ Text(
+ text = stringResource(R.string.alert_dialog_use_case),
+ fontSize = 15.sp,
+ fontWeight = FontWeight.Bold
+ )
+ }
+
+ val (selectedOption, onOptionSelected) = remember { mutableStateOf(cases[useCaseAlertDialogModel.selectedCaseIndex]) }
+
+ Column(
+ modifier = Modifier.selectableGroup()
+ ) {
+ cases.forEachIndexed { index, case ->
+ UseCaseCheckBox(case, selectedOption, onOptionSelected, useCaseAlertDialogModel.setSelectItem, index)
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun UseCaseCheckBox(
+ case: Int,
+ selectedOption: Int,
+ onOptionSelected: (Int) -> Unit,
+ setSelectItem: ((Int) -> Unit)?,
+ index: Int
+) {
+ Row(
+ modifier = Modifier.padding(7.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ RadioButton (
+ (case == selectedOption),
+ {
+ onOptionSelected(case)
+ setSelectItem?.invoke(index)
+ }
+ )
+ Text(
+ text = stringResource(case)
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialogModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialogModel.kt
new file mode 100644
index 0000000..255f3d9
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/components/usecasealertdialog/UseCaseAlertDialogModel.kt
@@ -0,0 +1,9 @@
+package ru.n00byara.notificationcode.ui.components.usecasealertdialog
+
+import androidx.compose.runtime.MutableState
+
+data class UseCaseAlertDialogModel(
+ val openDialogState: MutableState,
+ val setSelectItem: ((Int) -> Unit)?,
+ val selectedCaseIndex: Int = 0
+)
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/ApplicationsScreen.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/ApplicationsScreen.kt
index f280a3d..58492bf 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/ApplicationsScreen.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/ApplicationsScreen.kt
@@ -3,29 +3,29 @@ package ru.n00byara.notificationcode.ui.screens
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import ru.n00byara.notificationcode.Constants
import ru.n00byara.notificationcode.R
-import ru.n00byara.notificationcode.ui.components.applicationinfocard.ApplicationInfoCheckBox
-import ru.n00byara.notificationcode.ui.components.applicationinfocard.ApplicationInfoCheckBoxModel
+import ru.n00byara.notificationcode.ui.components.applicationinfocheckbox.ApplicationInfoCheckBox
+import ru.n00byara.notificationcode.ui.components.applicationinfocheckbox.ApplicationInfoCheckBoxModel
import ru.n00byara.notificationcode.ui.viewmodels.ApplicationsScreenViewModel
+import kotlin.reflect.KFunction1
@Composable
fun ApplicationsScreen(
applicationsScreenViewModel: ApplicationsScreenViewModel = viewModel(),
- topBarTitleState: MutableState
+ setTopBarTitle: KFunction1,
) {
- topBarTitleState.value = stringResource(R.string.screen_application_title)
+ setTopBarTitle(stringResource(R.string.screen_application_title))
LazyColumn {
itemsIndexed(
- applicationsScreenViewModel.getApplications()
+ applicationsScreenViewModel.applications
) { _, appInfo ->
val applicationInfoCheckBoxModel = ApplicationInfoCheckBoxModel(
appInfo,
- applicationsScreenViewModel.getApplicationState(Constants.APPLICATION_PREF + appInfo.name),
+ applicationsScreenViewModel.getApplicationState(Constants.APPLICATION_PREF + appInfo.packageName),
applicationsScreenViewModel::setApplicationState
)
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt
new file mode 100644
index 0000000..bad23a2
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/GlobalSettingsScreen.kt
@@ -0,0 +1,105 @@
+package ru.n00byara.notificationcode.ui.screens
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Card
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.lifecycle.viewmodel.compose.viewModel
+import ru.n00byara.notificationcode.R
+import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialog
+import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialogModel
+import ru.n00byara.notificationcode.ui.viewmodels.GlobalSettingsScreenViewModel
+
+@Composable
+fun GlobalSettingsScreen(
+ globalSettingsScreenViewModel: GlobalSettingsScreenViewModel = viewModel(),
+ setTopBarTitle: (String) -> Unit,
+ paddingValues: PaddingValues
+) {
+ setTopBarTitle(stringResource(R.string.screen_global_settings_title))
+
+ LazyColumn(
+ Modifier.padding(paddingValues)
+ ) {
+ if (globalSettingsScreenViewModel.isRoot) {
+ item {
+ val useCaseDialogModel by globalSettingsScreenViewModel.useCaseDialogState.collectAsState()
+ UseCaseDialog(useCaseDialogModel)
+ }
+ }
+ }
+}
+
+data class UseCaseDialogModel(
+ val openDialogState: MutableState,
+ var useCaseTitle: Int = 0,
+ var setSelectItem: ((Int) -> Unit)? = null,
+ var selectedCaseIndex: Int = 0
+)
+
+@Composable
+fun UseCaseDialog(
+ useCaseDialogModel: UseCaseDialogModel,
+) {
+ useCaseDialogModel.openDialogState.value
+
+
+ val useCaseAlertDialogModel = UseCaseAlertDialogModel(
+ useCaseDialogModel.openDialogState,
+ useCaseDialogModel.setSelectItem,
+ useCaseDialogModel.selectedCaseIndex
+ )
+
+ if (useCaseAlertDialogModel.openDialogState.value) {
+ UseCaseAlertDialog(useCaseAlertDialogModel)
+ }
+
+ Card(
+ Modifier
+ .padding(start = 15.dp, end = 15.dp, top = 7.dp, bottom = 7.dp)
+ .wrapContentHeight()
+ .clip(RoundedCornerShape(19.dp))
+ .clickable {
+ useCaseAlertDialogModel.openDialogState.value = !useCaseAlertDialogModel.openDialogState.value
+ }
+
+ ) {
+ Column(
+ Modifier
+ .padding(10.dp)
+ .fillMaxWidth()
+
+ ) {
+ Row {
+ Text(
+ stringResource(R.string.alert_dialog_use_case),
+ fontSize = 15.sp,
+ fontWeight = FontWeight.Bold
+ )
+ }
+ Row {
+ Text(
+ stringResource(useCaseDialogModel.useCaseTitle),
+ fontSize = 15.sp
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt
index c69e3bb..e33849c 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/screens/SettingsScreen.kt
@@ -17,7 +17,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
@@ -30,17 +29,20 @@ import ru.n00byara.notificationcode.R
import ru.n00byara.notificationcode.ui.components.switcher.Switcher
import ru.n00byara.notificationcode.ui.components.switcher.SwitcherModel
import ru.n00byara.notificationcode.ui.viewmodels.SettingsScreenViewModel
+import kotlin.reflect.KFunction1
@Composable
fun SettingsScreen(
settingsScreenViewModel: SettingsScreenViewModel = viewModel(),
- topBarTitle: MutableState,
+ setTopBarTitle: KFunction1,
) {
- topBarTitle.value = stringResource(R.string.screen_settings_title)
+ setTopBarTitle(stringResource(R.string.screen_settings_title))
LazyColumn {
- item {
- LsposedInfoCard(settingsScreenViewModel.isActive)
+ if (settingsScreenViewModel.isRoot) {
+ item {
+ LsposedInfoCard(settingsScreenViewModel.isActive)
+ }
}
itemsIndexed(
@@ -50,28 +52,32 @@ fun SettingsScreen(
Constants.SWITCH_CODE,
settingsScreenViewModel.getBoolean(Constants.SWITCH_CODE),
settingsScreenViewModel::setBoolean,
- settingsScreenViewModel.isActive
+ settingsScreenViewModel.isActive,
+ settingsScreenViewModel.isRoot
),
SwitcherModel(
R.string.switcher_phone,
Constants.SWITCH_PHONE,
settingsScreenViewModel.getBoolean(Constants.SWITCH_PHONE),
settingsScreenViewModel::setBoolean,
- settingsScreenViewModel.isActive
+ settingsScreenViewModel.isActive,
+ settingsScreenViewModel.isRoot
),
SwitcherModel(
R.string.switcher_shazam,
- Constants.APPLICATION_PREF + "Shazam",
- settingsScreenViewModel.getBoolean(Constants.APPLICATION_PREF + "Shazam"),
+ Constants.APPLICATION_PREF + Constants.SHAZAM_PACKAGE,
+ settingsScreenViewModel.getBoolean(Constants.APPLICATION_PREF + Constants.SHAZAM_PACKAGE),
settingsScreenViewModel::setBoolean,
- settingsScreenViewModel.isActive
+ settingsScreenViewModel.isActive,
+ settingsScreenViewModel.isRoot
),
SwitcherModel(
R.string.switcher_track_numbers,
Constants.SWITHC_TRACK_NUMBER,
settingsScreenViewModel.getBoolean(Constants.SWITHC_TRACK_NUMBER),
settingsScreenViewModel::setBoolean,
- settingsScreenViewModel.isActive
+ settingsScreenViewModel.isActive,
+ settingsScreenViewModel.isRoot
)
)
) { _, item ->
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/ApplicationsScreenViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/ApplicationsScreenViewModel.kt
index 33e47b1..ab2d94f 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/ApplicationsScreenViewModel.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/ApplicationsScreenViewModel.kt
@@ -1,30 +1,15 @@
package ru.n00byara.notificationcode.ui.viewmodels
import android.app.Application
-import android.content.pm.PackageManager
import androidx.lifecycle.AndroidViewModel
-import ru.n00byara.notificationcode.applicationinfo.InstalledAppInfo
+import ru.n00byara.notificationcode.components.application.ApplicationsList
import ru.n00byara.notificationcode.models.SettingsModel
class ApplicationsScreenViewModel(application: Application) : AndroidViewModel(application) {
private val context = application.applicationContext
- private val pm = context.packageManager
- private val allInstalledApplications = pm.getInstalledApplications(PackageManager.GET_META_DATA)
+ private val applicationsList = ApplicationsList(this.context)
private val settings = SettingsModel()
-
- fun getApplications(): List {
- var result = mutableListOf()
-
- allInstalledApplications.forEach { applicationInfo ->
- val appInfo = InstalledAppInfo(this.pm, applicationInfo)
-
- if (!appInfo.isSystem && appInfo.name != "Shazam") {
- result.add(appInfo)
- }
- }
-
- return result
- }
+ val applications = applicationsList.getApplications()
fun getApplicationState(prefName: String): Boolean {
return this.settings.getBoolean(prefName)
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt
new file mode 100644
index 0000000..ffa26b1
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsActivityViewModel.kt
@@ -0,0 +1,44 @@
+package ru.n00byara.notificationcode.ui.viewmodels
+
+import android.annotation.SuppressLint
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import ru.n00byara.notificationcode.ui.components.topbar.TopBarModel
+import kotlin.reflect.KFunction0
+
+class GlobalSettingsActivityViewModel(private val finishActivity: KFunction0) : ViewModel() {
+ private val _topBarUiState = MutableStateFlow(TopBarModel())
+ val topBarUiState: StateFlow = this._topBarUiState.asStateFlow()
+
+ @SuppressLint("RestrictedApi")
+ fun setTopBarTitle(title: String) {
+ this._topBarUiState.value = TopBarModel(
+ title,
+ navigationIcon = {
+ IconButton(onClick = {
+ this.finishActivity()
+ }) {
+ Icon(Icons.Filled.ArrowBack, "Back")
+ }
+ }
+ )
+ }
+}
+
+class GlobalSettingsActivityViewModelFactory(
+ private val finishActivity: KFunction0
+) : ViewModelProvider.NewInstanceFactory() {
+ override fun create(modelClass: Class): T {
+ if (modelClass.isAssignableFrom(GlobalSettingsActivityViewModel::class.java)) {
+ return GlobalSettingsActivityViewModel(this.finishActivity) as T
+ }
+ throw IllegalArgumentException("Unknown class name")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsScreenViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsScreenViewModel.kt
new file mode 100644
index 0000000..51aec5d
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/GlobalSettingsScreenViewModel.kt
@@ -0,0 +1,54 @@
+package ru.n00byara.notificationcode.ui.viewmodels
+
+import android.app.Application
+import androidx.compose.runtime.mutableStateOf
+import androidx.lifecycle.AndroidViewModel
+import com.scottyab.rootbeer.RootBeer
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import ru.n00byara.notificationcode.Constants
+import ru.n00byara.notificationcode.R
+import ru.n00byara.notificationcode.components.permission.Permission
+import ru.n00byara.notificationcode.models.SettingsModel
+import ru.n00byara.notificationcode.ui.screens.UseCaseDialogModel
+
+class GlobalSettingsScreenViewModel(application: Application) : AndroidViewModel(application) {
+ lateinit private var permission: Permission
+ private val context = application.applicationContext
+ private val settings = SettingsModel()
+ private val openDialogState = mutableStateOf(false)
+ private val _useCaseDialogState = MutableStateFlow(
+ UseCaseDialogModel(this.openDialogState)
+ )
+ val useCaseDialogState: StateFlow = this._useCaseDialogState.asStateFlow()
+ val isRoot = RootBeer(this.context).isRooted
+
+ init {
+ setVariantDialogDescription()
+ this._useCaseDialogState.value.selectedCaseIndex = this.settings.getInt(Constants.USE_CASE)
+ this._useCaseDialogState.value.setSelectItem = this::setUseCase
+ }
+
+ private fun setUseCase(case: Int) {
+ this.permission = Permission(this.context)
+
+ if (case == 1 && !this.permission.checkPermission()) {
+ this.permission.requestPermissions()
+ }
+
+ this.settings.setInt(Constants.USE_CASE, case)
+ this._useCaseDialogState.value.selectedCaseIndex = this.settings.getInt(Constants.USE_CASE)
+ this.setVariantDialogDescription()
+ this.openDialogState.value = false
+ }
+
+ // 0 == Root 1 == Non Root
+ private fun setVariantDialogDescription() {
+ if (this.settings.getInt(Constants.USE_CASE) == 0) {
+ this._useCaseDialogState.value.useCaseTitle = R.string.alert_dialog_use_case_root
+ } else {
+ this._useCaseDialogState.value.useCaseTitle = R.string.alert_dialog_use_case_non_root
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/MainActivityViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/MainActivityViewModel.kt
deleted file mode 100644
index 052d986..0000000
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/MainActivityViewModel.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package ru.n00byara.notificationcode.ui.viewmodels
-
-import androidx.lifecycle.ViewModel
-import ru.n00byara.notificationcode.models.SettingsModel
-
-class MainActivityViewModel : ViewModel() {
- private val settings = SettingsModel()
-
- fun getScreenRoute(prefName: String, value: String = ""): String {
- return this.settings.getString(prefName, value)
- }
-
- fun setScreenRoute(prefName: String, value: String) {
- this.settings.setString(prefName, value)
- }
-
- fun getScreenSelected(prefName: String, value: Int = 0): Int {
- return this.settings.getInt(prefName, value)
- }
-
- fun setScreenSelected(prefName: String, value: Int) {
- this.settings.setInt(prefName, value)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt
new file mode 100644
index 0000000..ae356f6
--- /dev/null
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsActivityViewModel.kt
@@ -0,0 +1,119 @@
+package ru.n00byara.notificationcode.ui.viewmodels
+
+import android.app.Application
+import android.content.Intent
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.runtime.mutableStateOf
+import androidx.lifecycle.AndroidViewModel
+import com.scottyab.rootbeer.RootBeer
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import ru.n00byara.notificationcode.Constants
+import ru.n00byara.notificationcode.components.permission.Permission
+import ru.n00byara.notificationcode.models.SettingsModel
+import ru.n00byara.notificationcode.ui.activities.GlobalSettingsActivity
+import ru.n00byara.notificationcode.ui.components.permissionalertdialog.PermissionAlertDialogModel
+import ru.n00byara.notificationcode.ui.components.topbar.TopBarModel
+import ru.n00byara.notificationcode.ui.components.usecasealertdialog.UseCaseAlertDialogModel
+
+class SettingsActivityViewModel(application: Application) : AndroidViewModel(application) {
+ companion object {
+ private const val IS_FIRST_LAUNCH = "is_first_launch"
+ }
+
+ private val context = application.applicationContext
+ private var permission = Permission(this.context)
+ private val settings = SettingsModel()
+ private val _topBarUiState = MutableStateFlow(TopBarModel())
+ val topBarUiState: StateFlow = _topBarUiState.asStateFlow()
+ val isRooted = RootBeer(this.context).isRooted
+ val isFirstLaunch = this.settings.getBoolean(IS_FIRST_LAUNCH, true)
+ val openRootDialogState = mutableStateOf(false)
+ val openNonRootDialogState = mutableStateOf(false)
+ private val _useCaseAlertDialogUiState = MutableStateFlow(
+ UseCaseAlertDialogModel(
+ this.openRootDialogState,
+ this::setSelectedCase,
+ 0
+ )
+ )
+ val useCaseAlertDialogUiState: StateFlow = this._useCaseAlertDialogUiState
+ private val _permissionAlertDialogState = MutableStateFlow(
+ PermissionAlertDialogModel(
+ openDialogState = this.openNonRootDialogState,
+ openSettings = this::openSettings
+ )
+ )
+ val permissionAlertDialogState: StateFlow = this._permissionAlertDialogState
+
+ init {
+
+ if (isFirstLaunch) {
+ if (this.isRooted) {
+ this.openRootDialogState.value = true
+ this.settings.setInt(Constants.USE_CASE, 0)
+ } else {
+ this.openNonRootDialogState.value = true
+ this.settings.setInt(Constants.USE_CASE, 1)
+ }
+
+ this.settings.setBoolean(IS_FIRST_LAUNCH, false)
+ }
+ }
+
+ private fun openSettings() {
+ this.permission.requestPermissions()
+ }
+
+ private fun setSelectedCase(case: Int) {
+ if (case == 1 && !this.permission.checkPermission()) {
+ this.permission.requestPermissions()
+
+ }
+
+ this.settings.setInt(Constants.USE_CASE, case)
+ this.openRootDialogState.value = false
+ }
+
+ fun updateTopBarTitle(title: String) {
+ this._topBarUiState.value = TopBarModel(
+ title = title,
+ actions = if (this.isRooted) {
+ {
+ IconButton(onClick = {
+ val intent = Intent(this@SettingsActivityViewModel.context, GlobalSettingsActivity::class.java)
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ this@SettingsActivityViewModel.context.startActivity(intent)
+ }) {
+ Icon(
+ imageVector = Icons.Default.Settings,
+ contentDescription = "Settings"
+ )
+ }
+ }
+ } else {
+ null
+ }
+ )
+ }
+
+ fun getScreenRoute(prefName: String, value: String = ""): String {
+ return this.settings.getString(prefName, value)
+ }
+
+ fun setScreenRoute(prefName: String, value: String) {
+ this.settings.setString(prefName, value)
+ }
+
+ fun getScreenSelected(prefName: String, value: Int = 0): Int {
+ return this.settings.getInt(prefName, value)
+ }
+
+ fun setScreenSelected(prefName: String, value: Int) {
+ this.settings.setInt(prefName, value)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt
index 6dc0bc1..6dba1f1 100644
--- a/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt
+++ b/app/src/main/java/ru/n00byara/notificationcode/ui/viewmodels/SettingsScreenViewModel.kt
@@ -1,12 +1,14 @@
package ru.n00byara.notificationcode.ui.viewmodels
import androidx.lifecycle.ViewModel
+import ru.n00byara.notificationcode.Constants
import ru.n00byara.notificationcode.models.SettingsModel
class SettingsScreenViewModel : ViewModel() {
+
private val settingsModel = SettingsModel()
val isActive = this.settingsModel.isActive
-
+ val isRoot = this.settingsModel.getInt(Constants.USE_CASE) == 0
fun getBoolean(prefName: String): Boolean {
return this.settingsModel.getBoolean(prefName)
}
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index 869dbbf..6d0ab7b 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -11,4 +11,10 @@
Module is inactive
Applications
To configure the module, you need to enable it and then restart SystemUI
+ Use case
+ App Settings
+ Restart the applications to save the changes
+ For the service to work, provide permission to listen to notifications
+ Cancel
+ OK
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index b16a1cb..6095925 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -11,4 +11,10 @@
Модуль выключен
Приложения
Для настройки модуля, его необходимо включить и после перезапустить SystemUI
+ Вариант использования
+ Настройки приложения
+ Что бы изменения вступили в силу перезапустите приложения
+ Для работы сервиса предоставьте разрешение на прослушивание уведомлений
+ Отмена
+ Предоставить
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f0390b8..274509c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -12,4 +12,13 @@
Module is inactive
Applications
To configure the module, you need to enable it and then restart SystemUI
+ Use case
+ Non root
+ Root
+ GlobalSettingsActivity
+ App Settings
+ Restart the applications to save the changes
+ For the service to work, provide permission to listen to notifications
+ Cancel
+ OK
\ No newline at end of file
diff --git a/app/src/main/resources/META-INF/yukihookapi_init b/app/src/main/resources/META-INF/yukihookapi_init
index f5c3013..67aa75f 100644
--- a/app/src/main/resources/META-INF/yukihookapi_init
+++ b/app/src/main/resources/META-INF/yukihookapi_init
@@ -1 +1 @@
-ru.n00byara.notificationcode.hook.Hook
\ No newline at end of file
+ru.n00byara.notificationcode.components.hook.Hook
\ No newline at end of file