├── docs
└── images
│ ├── a
│ ├── logo.png
│ ├── Screenshot_2025-06-27-21-15-26-014_com.yn.setbox.jpg
│ ├── Screenshot_2025-06-27-21-15-35-443_com.yn.setbox.jpg
│ └── Screenshot_2025-06-27-21-16-01-143_com.yn.setbox.jpg
├── setbox
├── app
│ ├── .gitignore
│ ├── src
│ │ └── main
│ │ │ ├── res
│ │ │ ├── mipmap
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── themes.xml
│ │ │ │ └── values.xml
│ │ │ ├── anim
│ │ │ │ ├── fade_in.xml
│ │ │ │ └── fade_out.xml
│ │ │ ├── values-ar
│ │ │ │ └── values-ar.xml
│ │ │ └── values-tr
│ │ │ │ └── values-tr.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── yn
│ │ │ │ └── setbox
│ │ │ │ ├── core
│ │ │ │ ├── AppTheme.kt
│ │ │ │ ├── AppLanguage.kt
│ │ │ │ ├── BootCompletedReceiver.kt
│ │ │ │ ├── LocaleManager.kt
│ │ │ │ ├── ShizukuManager.kt
│ │ │ │ ├── PluginManager.kt
│ │ │ │ ├── PermissionManager.kt
│ │ │ │ └── AppPreferences.kt
│ │ │ │ ├── data
│ │ │ │ ├── model
│ │ │ │ │ ├── RemoteModule.kt
│ │ │ │ │ └── Module.kt
│ │ │ │ └── repository
│ │ │ │ │ ├── SettingsApiManager.kt
│ │ │ │ │ └── RepoRepository.kt
│ │ │ │ └── ui
│ │ │ │ ├── viewmodels
│ │ │ │ ├── PermissionViewModelFactory.kt
│ │ │ │ ├── ThemeViewModelFactory.kt
│ │ │ │ ├── RepoViewModelFactory.kt
│ │ │ │ ├── ModuleViewModelFactory.kt
│ │ │ │ ├── ThemeViewModel.kt
│ │ │ │ ├── RepoViewModel.kt
│ │ │ │ ├── PermissionViewModel.kt
│ │ │ │ └── ModuleViewModel.kt
│ │ │ │ ├── navigation
│ │ │ │ └── AppScreen.kt
│ │ │ │ ├── theme
│ │ │ │ ├── Type.kt
│ │ │ │ ├── Color.kt
│ │ │ │ └── Theme.kt
│ │ │ │ ├── dialogs
│ │ │ │ ├── RestartDialog.kt
│ │ │ │ ├── ActivationDialog.kt
│ │ │ │ └── LanguagesDialog.kt
│ │ │ │ ├── components
│ │ │ │ ├── AppToolbar.kt
│ │ │ │ ├── AppToolbarActions.kt
│ │ │ │ ├── ActivationBanner.kt
│ │ │ │ ├── MainContent.kt
│ │ │ │ ├── ModuleItem.kt
│ │ │ │ ├── RepoItem.kt
│ │ │ │ ├── RepoScreen.kt
│ │ │ │ ├── MainScreen.kt
│ │ │ │ └── SettingsContent.kt
│ │ │ │ └── activities
│ │ │ │ ├── SettingsActivity.kt
│ │ │ │ └── MainActivity.kt
│ │ │ ├── assets
│ │ │ └── setbox-plugin-v1.0.0.apk
│ │ │ └── AndroidManifest.xml
│ └── build.gradle.kts
├── .gradle
│ ├── 8.14
│ │ ├── gc.properties
│ │ ├── fileChanges
│ │ │ └── last-build.bin
│ │ ├── checksums
│ │ │ └── checksums.lock
│ │ ├── fileHashes
│ │ │ ├── fileHashes.bin
│ │ │ ├── fileHashes.lock
│ │ │ └── resourceHashesCache.bin
│ │ └── executionHistory
│ │ │ ├── executionHistory.bin
│ │ │ └── executionHistory.lock
│ ├── vcs-1
│ │ └── gc.properties
│ └── buildOutputCleanup
│ │ ├── cache.properties
│ │ ├── outputFiles.bin
│ │ └── buildOutputCleanup.lock
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .gitignore
├── build.gradle.kts
├── gradle.properties
├── settings.gradle.kts
├── gradlew.bat
└── gradlew
├── setbox-plugin
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── app
│ ├── src
│ │ └── main
│ │ │ ├── res
│ │ │ ├── mipmap
│ │ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── com
│ │ │ └── yn
│ │ │ └── setbox
│ │ │ └── plugin
│ │ │ └── SettingsProvider.kt
│ └── build.gradle.kts
├── .gitignore
├── gradle.properties
├── build.gradle.kts
├── settings.gradle.kts
├── gradlew.bat
└── gradlew
├── .gitignore
├── README_ar-EG.md
├── README.md
└── README_tr-TR.md
/docs/images/a:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/setbox/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/setbox/.gradle/vcs-1/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/docs/images/logo.png
--------------------------------------------------------------------------------
/setbox/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Sat Aug 23 16:52:09 GMT 2025
2 | gradle.version=8.14
3 |
--------------------------------------------------------------------------------
/setbox/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/checksums/checksums.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/8.14/checksums/checksums.lock
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/fileHashes/fileHashes.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/8.14/fileHashes/fileHashes.bin
--------------------------------------------------------------------------------
/setbox-plugin/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox-plugin/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/8.14/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/setbox/app/src/main/res/mipmap/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/app/src/main/res/mipmap/ic_launcher.png
--------------------------------------------------------------------------------
/setbox/.gradle/buildOutputCleanup/outputFiles.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/buildOutputCleanup/outputFiles.bin
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/core/AppTheme.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.core
2 |
3 | enum class AppTheme {
4 | LIGHT, DARK, SYSTEM
5 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/build/
2 | **/out/
3 | **/.gradle/
4 | gradlew
5 | gradlew.bat
6 | .idea/
7 | *.iml
8 | .DS_Store
9 | Thumbs.db
10 | *.log
11 | *.tmp
--------------------------------------------------------------------------------
/setbox/app/src/main/assets/setbox-plugin-v1.0.0.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/app/src/main/assets/setbox-plugin-v1.0.0.apk
--------------------------------------------------------------------------------
/setbox/app/src/main/res/mipmap/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/app/src/main/res/mipmap/ic_launcher_round.png
--------------------------------------------------------------------------------
/setbox-plugin/app/src/main/res/mipmap/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox-plugin/app/src/main/res/mipmap/ic_launcher.png
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/fileHashes/resourceHashesCache.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/8.14/fileHashes/resourceHashesCache.bin
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/executionHistory/executionHistory.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/8.14/executionHistory/executionHistory.bin
--------------------------------------------------------------------------------
/setbox/.gradle/buildOutputCleanup/buildOutputCleanup.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/buildOutputCleanup/buildOutputCleanup.lock
--------------------------------------------------------------------------------
/setbox/.gradle/8.14/executionHistory/executionHistory.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/setbox/.gradle/8.14/executionHistory/executionHistory.lock
--------------------------------------------------------------------------------
/setbox-plugin/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SetBox Plugin
4 |
--------------------------------------------------------------------------------
/docs/images/Screenshot_2025-06-27-21-15-26-014_com.yn.setbox.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/docs/images/Screenshot_2025-06-27-21-15-26-014_com.yn.setbox.jpg
--------------------------------------------------------------------------------
/docs/images/Screenshot_2025-06-27-21-15-35-443_com.yn.setbox.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/docs/images/Screenshot_2025-06-27-21-15-35-443_com.yn.setbox.jpg
--------------------------------------------------------------------------------
/docs/images/Screenshot_2025-06-27-21-16-01-143_com.yn.setbox.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YasserNull/setbox/HEAD/docs/images/Screenshot_2025-06-27-21-16-01-143_com.yn.setbox.jpg
--------------------------------------------------------------------------------
/setbox/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/setbox/app/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/setbox/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.apk
3 | *.ap_
4 | *.dex
5 | *.class
6 | /build/
7 | app/build/
8 | **/build/
9 | /.gradle/
10 | /.idea/
11 | /local.properties
12 | .gradle/
13 | captures/
14 | *.log
15 | *.cache
16 | *.tmp
17 | obj/
18 | *.jks
19 | *.keystore
--------------------------------------------------------------------------------
/setbox-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.apk
3 | *.ap_
4 | *.dex
5 | *.class
6 | /build/
7 | app/build/
8 | **/build/
9 | /.gradle/
10 | /.idea/
11 | /local.properties
12 | .gradle/
13 | captures/
14 | *.log
15 | *.cache
16 | *.tmp
17 | obj/
18 | *.jks
19 | *.keystore
--------------------------------------------------------------------------------
/setbox/app/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/setbox/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
--------------------------------------------------------------------------------
/setbox-plugin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
--------------------------------------------------------------------------------
/setbox-plugin/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx512m -Dfile.encoding=UTF-8
2 | android.useAndroidX=true
3 | kotlin.code.style=official
4 | android.nonTransitiveRClass=true
5 | systemProp.org.gradle.internal.http.connectionTimeout=7200000
6 | systemProp.org.gradle.internal.http.socketTimeout=7200000
7 |
--------------------------------------------------------------------------------
/setbox-plugin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application") version "8.0.0" apply false
3 | id("com.android.library") version "8.0.0" apply false
4 | id("org.jetbrains.kotlin.android") version "1.9.25" apply false
5 | }
6 |
7 | tasks.register("clean") {
8 | delete(rootProject.buildDir)
9 | }
--------------------------------------------------------------------------------
/setbox-plugin/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 |
9 | dependencyResolutionManagement {
10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
11 | repositories {
12 | google()
13 | mavenCentral()
14 | }
15 | }
16 |
17 | rootProject.name = "setbox-plugin"
18 |
19 | include(":app")
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/data/model/RemoteModule.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.data.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | // يمثل وحدة (Module) كما هي معروضة في المستودع عن بعد.
6 | @Serializable
7 | data class RemoteModule(
8 | val id: String,
9 | val name: String,
10 | val description: String,
11 | val author: String,
12 | val version: String,
13 | val versionCode: String,
14 | val repository: String
15 | )
--------------------------------------------------------------------------------
/setbox/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application") version "8.4.0" apply false
3 | id("com.android.library") version "8.4.0" apply false
4 | id("org.jetbrains.kotlin.android") version "1.9.25" apply false
5 | id("org.jetbrains.kotlin.plugin.serialization") version "1.9.25"
6 | }
7 |
8 | tasks.register("clean") {
9 | delete(layout.buildDirectory)
10 |
11 | project.allprojects.forEach { project ->
12 | delete(project.layout.buildDirectory)
13 | }
14 | }
--------------------------------------------------------------------------------
/setbox/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 -Dorg.gradle.internal.http.connectionTimeout=7200000 -Dorg.gradle.internal.http.socketTimeout=7200000
2 | android.useAndroidX=true
3 | kotlin.code.style=official
4 | android.nonTransitiveRClass=true
5 | android.suppressUnsupportedCompileSdk=34
6 | org.gradle.parallel=true
7 | org.gradle.configureondemand=true
8 | org.gradle.caching=true
9 | systemProp.org.gradle.internal.http.connectionTimeout=7200000
10 | systemProp.org.gradle.internal.http.socketTimeout=7200000
11 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/data/model/Module.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.data.model
2 |
3 | // يمثل وحدة (Module) مثبتة محليًا.
4 | data class Module(
5 | val id: String,
6 | val name: String,
7 | val version: String,
8 | val versionCode: String?,
9 | val author: String,
10 | val description: String?,
11 | val path: String, // المسار إلى مجلد الوحدة على الجهاز.
12 | val repository: String?, // رابط مستودع GitHub الخاص بالوحدة.
13 | var isEnabled: Boolean = false // هل الوحدة مفعلة حاليًا.
14 | )
--------------------------------------------------------------------------------
/setbox/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 |
9 | dependencyResolutionManagement {
10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
11 | repositories {
12 | google()
13 | mavenCentral()
14 | maven { url = uri("https://jitpack.io") }
15 | maven { url = uri("https://artifactory.appodeal.com/appodeal-public") }
16 | }
17 | }
18 |
19 | rootProject.name = "setbox"
20 | include(":app")
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/viewmodels/PermissionViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.viewmodels
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 |
6 | // مصنع لإنشاء PermissionViewModel.
7 | class PermissionViewModelFactory : ViewModelProvider.Factory {
8 | override fun create(modelClass: Class): T {
9 | if (modelClass.isAssignableFrom(PermissionViewModel::class.java)) {
10 | @Suppress("UNCHECKED_CAST")
11 | return PermissionViewModel() as T
12 | }
13 | throw IllegalArgumentException("Unknown ViewModel class")
14 | }
15 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/viewmodels/ThemeViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.viewmodels
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import com.yn.setbox.core.AppPreferences
6 |
7 | // مصنع لإنشاء ThemeViewModel وتزويده بالـ AppPreferences.
8 | class ThemeViewModelFactory(private val preferences: AppPreferences) : ViewModelProvider.Factory {
9 | override fun create(modelClass: Class): T {
10 | if (modelClass.isAssignableFrom(ThemeViewModel::class.java)) {
11 | @Suppress("UNCHECKED_CAST")
12 | return ThemeViewModel(preferences) as T
13 | }
14 | throw IllegalArgumentException("Unknown ViewModel class")
15 | }
16 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/viewmodels/RepoViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.viewmodels
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import com.yn.setbox.data.repository.RepoRepository
6 |
7 | // مصنع لإنشاء RepoViewModel وتزويده بالـ RepoRepository.
8 | class RepoViewModelFactory(
9 | private val repository: RepoRepository
10 | ) : ViewModelProvider.Factory {
11 | override fun create(modelClass: Class): T {
12 | if (modelClass.isAssignableFrom(RepoViewModel::class.java)) {
13 | @Suppress("UNCHECKED_CAST")
14 | return RepoViewModel(repository) as T
15 | }
16 | throw IllegalArgumentException("Unknown ViewModel class")
17 | }
18 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/core/AppLanguage.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.core
2 |
3 | enum class AppLanguage {
4 | SYSTEM,
5 | ENGLISH,
6 | ARABIC,
7 |
8 | TURKISH;
9 |
10 | companion object {
11 | fun fromTag(tag: String?): AppLanguage {
12 | return when (tag) {
13 | "en" -> ENGLISH
14 | "ar" -> ARABIC
15 | "tr" -> TURKISH
16 | else -> SYSTEM
17 | }
18 | }
19 |
20 | fun toTag(language: AppLanguage): String? {
21 | return when (language) {
22 | ENGLISH -> "en"
23 | ARABIC -> "ar"
24 | TURKISH -> "tr"
25 | SYSTEM -> null
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/navigation/AppScreen.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.navigation
2 |
3 | import androidx.annotation.StringRes
4 | import androidx.compose.material.icons.Icons
5 | import androidx.compose.material.icons.filled.Extension
6 | import androidx.compose.material.icons.outlined.CloudDownload
7 | import androidx.compose.ui.graphics.vector.ImageVector
8 | import com.yn.setbox.R
9 |
10 | // يمثل الشاشات المختلفة في شريط التنقل السفلي.
11 | sealed class AppScreen(val route: String, @StringRes val titleResId: Int, val icon: ImageVector) {
12 | // شاشة الوحدات المثبتة.
13 | object Modules : AppScreen("modules", R.string.screen_title_modules, Icons.Default.Extension)
14 | // شاشة المستودع.
15 | object Repo : AppScreen("repo", R.string.screen_title_repo, Icons.Outlined.CloudDownload)
16 | }
--------------------------------------------------------------------------------
/setbox-plugin/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application")
3 | id("org.jetbrains.kotlin.android")
4 | }
5 | android {
6 | namespace = "com.yn.setbox.plugin"
7 | compileSdk = 22
8 | defaultConfig {
9 | applicationId = "com.yn.setbox.plugin"
10 | minSdk = 21
11 | targetSdk = 22
12 | versionCode = 1
13 | versionName = "1.0"
14 | }
15 | compileOptions {
16 | sourceCompatibility = JavaVersion.VERSION_1_8
17 | targetCompatibility = JavaVersion.VERSION_1_8
18 | }
19 | lint {
20 | abortOnError = false
21 | checkReleaseBuilds = false
22 | }
23 | kotlinOptions {
24 | jvmTarget = "1.8"
25 | }
26 | buildTypes {
27 | release {
28 | isMinifyEnabled = true
29 | isShrinkResources = true
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/viewmodels/ModuleViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.viewmodels
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import com.yn.setbox.core.AppPreferences
6 | import com.yn.setbox.data.repository.ModuleRepository
7 |
8 | // مصنع لإنشاء ModuleViewModel وتزويده بالتبعيات اللازمة.
9 | class ModuleViewModelFactory(
10 | private val appPreferences: AppPreferences,
11 | private val repository: ModuleRepository
12 | ) : ViewModelProvider.Factory {
13 | override fun create(modelClass: Class): T {
14 | if (modelClass.isAssignableFrom(ModuleViewModel::class.java)) {
15 | @Suppress("UNCHECKED_CAST")
16 | return ModuleViewModel(appPreferences, repository) as T
17 | }
18 | throw IllegalArgumentException("Unknown ViewModel class")
19 | }
20 | }
--------------------------------------------------------------------------------
/setbox-plugin/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
10 |
13 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // تعريف أنماط الخطوط المستخدمة في التطبيق.
10 | val Typography = Typography(
11 | bodyLarge = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp,
15 | lineHeight = 24.sp,
16 | letterSpacing = 0.5.sp
17 | ),
18 | titleLarge = TextStyle(
19 | fontFamily = FontFamily.Default,
20 | fontWeight = FontWeight.Normal,
21 | fontSize = 22.sp,
22 | lineHeight = 28.sp,
23 | letterSpacing = 0.sp
24 | ),
25 | labelSmall = TextStyle(
26 | fontFamily = FontFamily.Default,
27 | fontWeight = FontWeight.Medium,
28 | fontSize = 11.sp,
29 | lineHeight = 16.sp,
30 | letterSpacing = 0.5.sp
31 | )
32 | )
--------------------------------------------------------------------------------
/README_ar-EG.md:
--------------------------------------------------------------------------------
1 | **العربية** | [English](README.md) | [Türkçe](README_tr-TR.md)
2 |
3 | # SetBox
4 | 
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## ما هو SetBox؟
12 |
13 | **SetBox** هو تطبيق قوي يتيح لك تعديل إعدادات نظام أندرويد بسهولة عبر إضافات مطوَّرة من قبل المجتمع.
14 |
15 | ---
16 |
17 | ## لماذا تختار SetBox؟
18 |
19 | يقدم SetBox مجموعة واسعة من الميزات، منها:
20 |
21 | - التحكم في الإعدادات بسرعة
22 | - تفعيل وتعطيل الميزات المخفية
23 | - تحسينات مفيدة وبعض إصلاحات النظام
24 |
25 | يعتمد SetBox على مساهمات المجتمع، مما يتيح لأي شخص إنشاء ومشاركة إضافاته الخاصة لتعزيز قدرات التطبيق.
26 |
27 | ---
28 |
29 | ## تفعيل SetBox
30 |
31 | يتطلب تطبيق **SetBox** تفعيلًا لمرة واحدة باستخدام إحدى الطرق التالية:
32 |
33 | - **صلاحيات الروت (Root Access)**: يتطلب جهازًا بصلاحيات الروت.
34 | - **Shizuku**: استخدام تطبيق Shizuku للتفعيل بدون روت.
35 | - **أوامر ADB**: منح الأذونات عبر ADB باستخدام الأمر التالي:
36 |
37 | ```bash
38 | adb pm grant com.yn.setbox.plugin android.permission.WRITE_SECURE_SETTINGS
39 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/core/BootCompletedReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.core
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.util.Log
7 | import com.yn.setbox.data.repository.ModuleRepository
8 | import kotlinx.coroutines.CoroutineScope
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.flow.first
11 | import kotlinx.coroutines.launch
12 |
13 | // يستقبل حدث إقلاع الجهاز (Boot) لتطبيق إعدادات الوحدات المفعلة.
14 | class BootCompletedReceiver : BroadcastReceiver() {
15 | override fun onReceive(context: Context, intent: Intent) {
16 | if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
17 | return
18 | }
19 |
20 | Log.d("BootReceiver", "تم استقبال حدث إقلاع الجهاز. بدء الخدمة.")
21 | val pendingResult = goAsync() // للسماح بمواصلة العمل في الخلفية بعد انتهاء onReceive.
22 | CoroutineScope(Dispatchers.IO).launch {
23 | try {
24 | val appPreferences = AppPreferences(context)
25 | // تم تمرير appPreferences إلى ModuleRepository
26 | val moduleRepository = ModuleRepository(context, appPreferences)
27 |
28 | // الحصول على الوحدات التي كانت مفعلة قبل إعادة التشغيل.
29 | val enabledIds = appPreferences.getEnabledModuleIds().first()
30 | if (enabledIds.isEmpty()) {
31 | Log.d("BootReceiver", "لا توجد وحدات مفعلة.")
32 | return@launch
33 | }
34 |
35 | // تطبيق إعدادات التشغيل "on" لكل وحدة مفعلة.
36 | val allModules = moduleRepository.getModules()
37 | allModules.filter { it.id in enabledIds }.forEach { module ->
38 | Log.i("BootReceiver", "تطبيق إعدادات 'on' للوحدة المفعلة عند الإقلاع: ${module.name}")
39 | moduleRepository.applySettingsFromFile(module.path, "on")
40 | }
41 |
42 | } catch(e: Exception) {
43 | Log.e("BootReceiver", "خطأ أثناء التنفيذ عند الإقلاع", e)
44 | } finally {
45 | pendingResult.finish() // إعلام النظام بأن العمل في الخلفية قد انتهى.
46 | Log.d("BootReceiver", "انتهت الخدمة.")
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.theme
2 |
3 | import androidx.compose.material3.lightColorScheme
4 | import androidx.compose.ui.graphics.Color
5 | import androidx.compose.material3.darkColorScheme
6 |
7 | // لوحة الألوان الافتراضية للثيم الفاتح.
8 | val LightColors = lightColorScheme(
9 | primary = Color(0xFF4A5C92),
10 | onPrimary = Color(0xFFFFFFFF),
11 | primaryContainer = Color(0xFFDBE1FF),
12 | onPrimaryContainer = Color(0xFF00174B),
13 | secondary = Color(0xFF585E72),
14 | onSecondary = Color(0xFFFFFFFF),
15 | secondaryContainer = Color(0xFFDDE1F9),
16 | onSecondaryContainer = Color(0xFF161B2C),
17 | tertiary = Color(0xFF745471),
18 | onTertiary = Color(0xFFFFFFFF),
19 | tertiaryContainer = Color(0xFFFED6F8),
20 | onTertiaryContainer = Color(0xFF2B122B),
21 | error = Color(0xFFB3261E),
22 | onError = Color(0xFFFFFFFF),
23 | errorContainer = Color(0xFFF9DEDC),
24 | onErrorContainer = Color(0xFF410E0B),
25 | background = Color(0xFFFAF8FF),
26 | onBackground = Color(0xFF1A1B21),
27 | surface = Color(0xFFFAF8FF),
28 | onSurface = Color(0xFF1A1B21),
29 | surfaceVariant = Color(0xFFE3E2E9),
30 | onSurfaceVariant = Color(0xFF45464F),
31 | outline = Color(0xFF757680),
32 | )
33 |
34 | // لوحة الألوان الافتراضية للثيم الداكن.
35 | val DarkColors = darkColorScheme(
36 | primary = Color(0xFFB4C5FF),
37 | onPrimary = Color(0xFF1A2E60),
38 | primaryContainer = Color(0xFF324478),
39 | onPrimaryContainer = Color(0xFFDBE1FF),
40 | secondary = Color(0xFFC0C6DC),
41 | onSecondary = Color(0xFF2A3042),
42 | secondaryContainer = Color(0xFF414659),
43 | onSecondaryContainer = Color(0xFFDDE1F9),
44 | tertiary = Color(0xFFE2BBDC),
45 | onTertiary = Color(0xFF422741),
46 | tertiaryContainer = Color(0xFF5A3D58),
47 | onTertiaryContainer = Color(0xFFFED6F8),
48 | error = Color(0xFFF2B8B5),
49 | onError = Color(0xFF601410),
50 | errorContainer = Color(0xFF8C1D18),
51 | onErrorContainer = Color(0xFFF9DEDC),
52 | background = Color(0xFF121318),
53 | onBackground = Color(0xFFE3E2E9),
54 | surface = Color(0xFF121318),
55 | onSurface = Color(0xFFE3E2E9),
56 | surfaceVariant = Color(0xFF45464F),
57 | onSurfaceVariant = Color(0xFFC5C6D0),
58 | outline = Color(0xFF8F909A),
59 | )
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/dialogs/RestartDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.dialogs
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.material3.*
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.res.stringResource
8 | import androidx.compose.ui.unit.dp
9 | import androidx.compose.ui.window.Dialog
10 | import com.yn.setbox.R
11 |
12 | // حوار يطلب من المستخدم إعادة تشغيل التطبيق لتطبيق التغييرات (مثل تغيير اللغة).
13 | @Composable
14 | fun RestartDialog(
15 | onDismissRequest: () -> Unit,
16 | onConfirm: () -> Unit
17 | ) {
18 | Dialog(onDismissRequest = onDismissRequest) {
19 | Surface(
20 | tonalElevation = 8.dp,
21 | shape = MaterialTheme.shapes.medium,
22 | modifier = Modifier
23 | .fillMaxWidth()
24 | .wrapContentHeight()
25 | .padding(16.dp)
26 | ) {
27 | Column(
28 | modifier = Modifier
29 | .padding(16.dp)
30 | .fillMaxWidth()
31 | ) {
32 | Text(
33 | text = stringResource(R.string.restart_required),
34 | style = MaterialTheme.typography.headlineSmall,
35 | color = MaterialTheme.colorScheme.onSurface,
36 | modifier = Modifier.padding(bottom = 12.dp)
37 | )
38 |
39 | Text(
40 | text = stringResource(R.string.restart_message),
41 | style = MaterialTheme.typography.bodyLarge,
42 | color = MaterialTheme.colorScheme.onSurface,
43 | modifier = Modifier.padding(bottom = 24.dp)
44 | )
45 |
46 | Row(
47 | modifier = Modifier.fillMaxWidth(),
48 | horizontalArrangement = Arrangement.End
49 | ) {
50 | TextButton(onClick = onDismissRequest) {
51 | Text(stringResource(R.string.cancel))
52 | }
53 |
54 | Spacer(modifier = Modifier.width(8.dp))
55 |
56 | TextButton(onClick = onConfirm) {
57 | Text(stringResource(R.string.restart))
58 | }
59 | }
60 | }
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/components/AppToolbar.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.components
2 |
3 | import androidx.compose.material.icons.Icons
4 | import androidx.compose.material.icons.filled.Search
5 | import androidx.compose.material3.ExperimentalMaterial3Api
6 | import androidx.compose.material3.Icon
7 | import androidx.compose.material3.IconButton
8 | import androidx.compose.material3.MaterialTheme
9 | import androidx.compose.material3.Text
10 | import androidx.compose.material3.TopAppBar
11 | import androidx.compose.material3.TopAppBarDefaults
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.ui.res.stringResource
14 | import androidx.compose.ui.tooling.preview.Preview
15 | import com.yn.setbox.R
16 | import com.yn.setbox.core.AppTheme
17 | import com.yn.setbox.ui.theme.Theme
18 |
19 | // شريط الأدوات العلوي الرئيسي للتطبيق.
20 | @OptIn(ExperimentalMaterial3Api::class)
21 | @Composable
22 | fun AppToolbar(
23 | onSearchClick: () -> Unit,
24 | onSettingsClick: () -> Unit,
25 | onInstallFromZipClick: () -> Unit
26 | ) {
27 | TopAppBar(
28 | title = {
29 | Text(text = stringResource(R.string.app_name))
30 | },
31 | actions = {
32 | IconButton(onClick = onSearchClick) {
33 | Icon(
34 | imageVector = Icons.Default.Search,
35 | contentDescription = stringResource(R.string.search)
36 | )
37 | }
38 | // قائمة الإجراءات الإضافية (مثل الإعدادات والتثبيت).
39 | AppToolbarActions(
40 | onSettingsClick = onSettingsClick,
41 | onInstallFromZipClick = onInstallFromZipClick
42 | )
43 | },
44 | colors = TopAppBarDefaults.topAppBarColors(
45 | containerColor = MaterialTheme.colorScheme.primary,
46 | titleContentColor = MaterialTheme.colorScheme.onPrimary,
47 | actionIconContentColor = MaterialTheme.colorScheme.onPrimary
48 | )
49 | )
50 | }
51 |
52 | @Preview(showBackground = true)
53 | @Composable
54 | fun AppToolbarPreview() {
55 | Theme(
56 | currentTheme = AppTheme.SYSTEM,
57 | isBlackThemeEnabled = false,
58 | isMaterialYouEnabled = true,
59 | hueShift = 0f,
60 | saturationShift = 0f
61 | ) {
62 | AppToolbar(
63 | onSearchClick = {},
64 | onSettingsClick = {},
65 | onInstallFromZipClick = {}
66 | )
67 | }
68 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **English** | [العربية](README_ar-EG.md) | [Türkçe](README_tr-TR.md)
2 |
3 | # SetBox
4 | 
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## What is SetBox?
12 |
13 | **SetBox** is a powerful application that allows you to easily modify Android system settings through community-developed modules.
14 |
15 | ---
16 |
17 | ## Why Choose SetBox?
18 |
19 | SetBox offers a wide range of features, including:
20 |
21 | - Control settings quickly
22 | - Enable and disable hidden features
23 | - Useful tweaks and some system fixes
24 |
25 | SetBox thrives on community contributions, enabling anyone to create and share their own modules to enhance the app's capabilities.
26 |
27 | ---
28 |
29 | ## Activating SetBox
30 |
31 | The **SetBox** application requires a one-time activation using one of the following methods:
32 |
33 | - **Root Access**: Requires a rooted device.
34 | - **Shizuku**: Use the Shizuku app for non-root activation.
35 | - **ADB Command**: Grant permissions via ADB with the following command:
36 |
37 | ```bash
38 | adb pm grant com.yn.setbox.plugin android.permission.WRITE_SECURE_SETTINGS
39 | ```
40 |
41 | ---
42 |
43 | ## Screenshots
44 |
45 |
46 |
47 |
48 |
49 |
50 | ## Requirements
51 |
52 | - Android 6.0 or higher.
53 | - Installation of the **SetBox Plugin**.
54 | - Activation via one of the supported methods (Root, Shizuku, or ADB).
55 |
56 | ---
57 |
58 | ## Downloads
59 |
60 | Download **SetBox** and the **SetBox Plugin** from the [Releases](https://github.com/YasserNull/setbox/releases) page.
61 |
62 | ---
63 |
64 | ## Contributing
65 |
66 | You can contribute to SetBox in the following ways:
67 |
68 | - Share feedback and suggestions to improve the app.
69 | - Help translate SetBox into your language.
70 | - Create new modules and share them via the community repository: [`setbox-repo`](https://github.com/YasserNull/setbox-repo).
71 |
72 | ---
73 |
74 | ## License
75 |
76 | SetBox is licensed under the [GNU General Public License v3.0](LICENSE).
77 |
78 | ---
79 |
80 | ## Donate
81 |
82 | If you want to support me, I would be very grateful.
83 |
84 | [**PayPal**](https://www.paypal.com/ncp/payment/7X44EWSM9KAVW),
85 | Bitcion
86 | `1LksFFCP2HPdpVsUxfFmZShJFnLLrkZTro`
87 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/components/AppToolbarActions.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.components
2 |
3 | import androidx.compose.foundation.layout.Box
4 | import androidx.compose.material.icons.Icons
5 | import androidx.compose.material.icons.filled.Archive
6 | import androidx.compose.material.icons.filled.Info
7 | import androidx.compose.material.icons.filled.MoreVert
8 | import androidx.compose.material.icons.filled.Settings
9 | import androidx.compose.material3.DropdownMenu
10 | import androidx.compose.material3.DropdownMenuItem
11 | import androidx.compose.material3.Icon
12 | import androidx.compose.material3.IconButton
13 | import androidx.compose.material3.MaterialTheme
14 | import androidx.compose.material3.Text
15 | import androidx.compose.runtime.*
16 | import androidx.compose.ui.res.stringResource
17 | import androidx.compose.ui.tooling.preview.Preview
18 | import com.yn.setbox.R
19 | import com.yn.setbox.core.AppTheme
20 | import com.yn.setbox.ui.theme.Theme
21 |
22 | // القائمة المنسدلة (الإجراءات) في شريط الأدوات العلوي.
23 | @Composable
24 | fun AppToolbarActions(
25 | onSettingsClick: () -> Unit,
26 | onInstallFromZipClick: () -> Unit // معالج النقر للتثبيت من ZIP.
27 | ) {
28 | var showMenu by remember { mutableStateOf(false) }
29 |
30 | Box {
31 | IconButton(onClick = { showMenu = !showMenu }) {
32 | Icon(
33 | Icons.Default.MoreVert,
34 | contentDescription = stringResource(R.string.more_options),
35 | tint = MaterialTheme.colorScheme.onPrimary
36 | )
37 | }
38 | DropdownMenu(
39 | expanded = showMenu,
40 | onDismissRequest = { showMenu = false }
41 | ) {
42 | // خيار "تثبيت من ZIP".
43 | DropdownMenuItem(
44 | text = { Text(stringResource(R.string.install_from_zip)) },
45 | onClick = {
46 | onInstallFromZipClick()
47 | showMenu = false
48 | },
49 | leadingIcon = { Icon(Icons.Default.Archive, contentDescription = null) }
50 | )
51 | DropdownMenuItem(
52 | text = { Text(stringResource(R.string.settings)) },
53 | onClick = {
54 | onSettingsClick()
55 | showMenu = false
56 | },
57 | leadingIcon = { Icon(Icons.Default.Settings, contentDescription = null) }
58 | )
59 | }
60 | }
61 | }
62 |
63 | @Preview(showBackground = true)
64 | @Composable
65 | fun AppToolbarActionsPreview() {
66 | Theme(
67 | currentTheme = AppTheme.SYSTEM,
68 | isBlackThemeEnabled = false,
69 | isMaterialYouEnabled = true,
70 | hueShift = 0f,
71 | saturationShift = 0f
72 | ) {
73 | AppToolbarActions(onSettingsClick = {}, onInstallFromZipClick = {})
74 | }
75 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/components/ActivationBanner.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.components
2 |
3 | import androidx.compose.animation.AnimatedVisibility
4 | import androidx.compose.animation.expandVertically
5 | import androidx.compose.animation.shrinkVertically
6 | import androidx.compose.foundation.clickable
7 | import androidx.compose.foundation.layout.*
8 | import androidx.compose.material3.MaterialTheme
9 | import androidx.compose.material3.Surface
10 | import androidx.compose.material3.Text
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.res.stringResource
15 | import androidx.compose.ui.text.style.TextAlign
16 | import androidx.compose.ui.unit.dp
17 | import com.yn.setbox.R
18 | import com.yn.setbox.core.PermissionManager
19 |
20 | // البانر الذي يظهر في أعلى الشاشة لإعلام المستخدم بحالة تفعيل التطبيق.
21 | @Composable
22 | fun ActivationBanner(
23 | activationState: PermissionManager.ActivationStatus,
24 | onClick: () -> Unit,
25 | ) {
26 | // إخفاء البانر أثناء التحقق أو إذا كان التطبيق مفعلاً لتجنب الوميض.
27 | val isVisible = when (activationState) {
28 | PermissionManager.ActivationStatus.ACTIVATED,
29 | PermissionManager.ActivationStatus.CHECKING -> false
30 | else -> true
31 | }
32 |
33 | AnimatedVisibility(
34 | visible = isVisible,
35 | enter = expandVertically(),
36 | exit = shrinkVertically()
37 | ) {
38 | Surface(
39 | modifier = Modifier
40 | .fillMaxWidth()
41 | .clickable(
42 | enabled = activationState != PermissionManager.ActivationStatus.CHECKING &&
43 | activationState != PermissionManager.ActivationStatus.ACTIVATED,
44 | onClick = onClick
45 | ),
46 | color = MaterialTheme.colorScheme.errorContainer,
47 | contentColor = MaterialTheme.colorScheme.onErrorContainer
48 | ) {
49 | Row(
50 | modifier = Modifier
51 | .fillMaxWidth()
52 | .padding(horizontal = 16.dp, vertical = 12.dp),
53 | verticalAlignment = Alignment.CenterVertically,
54 | horizontalArrangement = Arrangement.Center
55 | ) {
56 | // عرض رسالة مختلفة بناءً على حالة التفعيل.
57 | val textToShow = when (activationState) {
58 | PermissionManager.ActivationStatus.PLUGIN_NOT_INSTALLED -> stringResource(R.string.plugin_not_installed_banner)
59 | else -> stringResource(R.string.app_not_activated_banner)
60 | }
61 | Text(
62 | text = textToShow,
63 | textAlign = TextAlign.Center
64 | )
65 | }
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/README_tr-TR.md:
--------------------------------------------------------------------------------
1 | [English](README.md) | [العربية](README_ar-EG.md) | **Türkçe**
2 |
3 | # SetBox
4 | 
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## SetBox Nedir?
12 |
13 | **SetBox**, topluluk tarafından geliştirilen modüller aracılığıyla Android sistem ayarlarını kolayca değiştirebilmenizi sağlayan güçlü bir uygulamadır.
14 |
15 | ---
16 |
17 | ## Neden SetBox?
18 |
19 | SetBox şu özellikleri sunar:
20 |
21 | - Ayarları hızlıca kontrol etme
22 | - Gizli özellikleri etkinleştirme ve devre dışı bırakma
23 | - Kullanışlı ince ayarlar ve bazı sistem düzeltmeleri
24 |
25 | SetBox, uygulamanın yeteneklerini geliştirmek için herkesin kendi modüllerini oluşturup paylaşmasına olanak tanıyan topluluk katkılarıyla gelişir.
26 |
27 | ---
28 |
29 | ## SetBox'u Etkinleştirme
30 |
31 | **SetBox** uygulamasının bir kerelik etkinleştirme işlemi aşağıdaki yöntemlerden biriyle yapılmalıdır:
32 |
33 | - **Root Erişimi**: Root yapılmış bir cihaz gerektirir.
34 | - **Shizuku**: Root yoksa Shizuku uygulaması ile etkinleştirme.
35 | - **ADB Komutu**: Aşağıdaki ADB komutu ile izin verin:
36 |
37 | ```bash
38 | adb pm grant com.yn.setbox.plugin android.permission.WRITE_SECURE_SETTINGS
39 | ```
40 |
41 | ---
42 |
43 | ## Ekran Görüntüleri
44 |
45 |
46 |
47 |
48 |
49 |
50 | ## Gereksinimler
51 |
52 | - Android 6.0 veya üzeri.
53 | - **SetBox Plugin** kurulumu.
54 | - Desteklenen yöntemlerden biriyle etkinleştirme (Root, Shizuku veya ADB).
55 |
56 | ---
57 |
58 | ## İndirmeler
59 |
60 | **SetBox** ve **SetBox Plugin**'i [Releases](https://github.com/YasserNull/setbox/releases) sayfasından indirin.
61 |
62 | ---
63 |
64 | ## Katkıda Bulunma
65 |
66 | SetBox'a aşağıdaki şekillerde katkıda bulunabilirsiniz:
67 |
68 | - Uygulamayı geliştirmek için geri bildirim ve öneriler paylaşın.
69 | - SetBox'ı kendi dilinize çevirmeye yardımcı olun.
70 | - Yeni modüller oluşturun ve bunları topluluk deposu üzerinden paylaşın: [`setbox-repo`](https://github.com/YasserNull/setbox-repo).
71 |
72 | ---
73 |
74 | ## Lisans
75 |
76 | SetBox, [GNU Genel Kamu Lisansı v3.0](LICENSE) ile lisanslanmıştır.
77 |
78 | ---
79 |
80 | ## Bağış
81 |
82 | Beni desteklemek isterseniz çok minnettar olurum.
83 |
84 | [**PayPal**](https://www.paypal.com/ncp/payment/7X44EWSM9KAVW),
85 | Bitcoin
86 | `1LksFFCP2HPdpVsUxfFmZShJFnLLrkZTro`
87 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/core/LocaleManager.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.core
2 |
3 | import android.content.Context
4 | import android.content.res.Configuration
5 | import android.content.res.Resources
6 | import android.os.Build
7 | import kotlinx.coroutines.CoroutineScope
8 | import kotlinx.coroutines.Dispatchers
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.StateFlow
11 | import kotlinx.coroutines.launch
12 | import java.util.Locale
13 |
14 | // كائن لإدارة لغة التطبيق وتطبيقها.
15 | object LocaleManager {
16 |
17 | // StateFlow لتتبع لغة التطبيق الحالية وإعلام الواجهة بأي تغييرات.
18 | private val _currentAppLanguageState = MutableStateFlow(AppLanguage.SYSTEM)
19 | val currentAppLanguageState: StateFlow = _currentAppLanguageState
20 |
21 | // دالة للحصول على لغة النظام الحالية.
22 | private fun getSystemLocale(): Locale {
23 | val configuration = Resources.getSystem().configuration
24 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
25 | configuration.locales[0]
26 | } else {
27 | @Suppress("DEPRECATION")
28 | configuration.locale
29 | }
30 | }
31 |
32 | // يحول AppLanguage إلى كائن Locale الذي يستخدمه أندرويد.
33 | fun getLocale(language: AppLanguage): Locale {
34 | return when (language) {
35 | AppLanguage.ENGLISH -> Locale("en")
36 | AppLanguage.ARABIC -> Locale("ar")
37 | AppLanguage.TURKISH -> Locale("tr")
38 | AppLanguage.SYSTEM -> getSystemLocale()
39 | }
40 | }
41 |
42 | // حفظ اختيار اللغة في DataStore وتحديث الحالة الفورية.
43 | fun saveLanguage(context: Context, language: AppLanguage) {
44 | val appPreferences = AppPreferences(context)
45 |
46 | CoroutineScope(Dispatchers.IO).launch {
47 | appPreferences.saveLanguage(language.name)
48 | }
49 |
50 | _currentAppLanguageState.value = language
51 | }
52 |
53 | // استرجاع اللغة المحفوظة من DataStore عند بدء تشغيل التطبيق.
54 | suspend fun getSavedLanguage(context: Context): AppLanguage {
55 | val appPreferences = AppPreferences(context)
56 | val savedLanguageString = appPreferences.getLanguage()
57 | val savedLanguage = try {
58 | AppLanguage.valueOf(savedLanguageString)
59 | } catch (e: IllegalArgumentException) {
60 | AppLanguage.SYSTEM // العودة إلى لغة النظام إذا كانت القيمة المحفوظة غير صالحة.
61 | }
62 | _currentAppLanguageState.value = savedLanguage
63 | return savedLanguage
64 | }
65 |
66 | // دالة محورية: تطبق اللغة المختارة على سياق (Context) معين لترجمة الواجهة.
67 | fun applyLocaleToContext(context: Context, language: AppLanguage): Context {
68 | val locale = getLocale(language)
69 | Locale.setDefault(locale)
70 | val config = Configuration(context.resources.configuration)
71 | config.setLocale(locale)
72 | return context.createConfigurationContext(config)
73 | }
74 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/dialogs/ActivationDialog.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.dialogs
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material3.*
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.platform.LocalContext
11 | import androidx.compose.ui.res.stringResource
12 | import androidx.compose.ui.text.font.FontFamily
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.window.Dialog
15 | import com.yn.setbox.R
16 |
17 | // حوار يوضح للمستخدم كيفية تفعيل التطبيق عبر ADB.
18 | @Composable
19 | fun ActivationDialog(
20 | onDismiss: () -> Unit
21 | ) {
22 | val context = LocalContext.current
23 | val githubUrl = "https://github.com/YasserNull/setbox"
24 |
25 | Dialog(onDismissRequest = onDismiss) {
26 | Card(
27 | shape = MaterialTheme.shapes.large
28 | ) {
29 | Column(modifier = Modifier.padding(24.dp)) {
30 | Text(
31 | text = stringResource(R.string.activate_app_title),
32 | style = MaterialTheme.typography.headlineSmall
33 | )
34 | Spacer(Modifier.height(16.dp))
35 |
36 | Text(stringResource(R.string.activate_app_description_adb))
37 | Spacer(Modifier.height(8.dp))
38 |
39 | // عرض أمر ADB الذي يجب على المستخدم تنفيذه.
40 | Surface(
41 | color = MaterialTheme.colorScheme.surfaceVariant,
42 | shape = RoundedCornerShape(8.dp)
43 | ) {
44 | Column(Modifier.padding(horizontal = 12.dp, vertical = 8.dp)) {
45 | Text(
46 | text = "adb shell pm grant com.yn.setbox.plugin android.permission.WRITE_SECURE_SETTINGS",
47 | fontFamily = FontFamily.Monospace,
48 | style = MaterialTheme.typography.bodyMedium
49 | )
50 | }
51 | }
52 |
53 | Spacer(Modifier.height(24.dp))
54 |
55 | Row(
56 | modifier = Modifier.fillMaxWidth(),
57 | horizontalArrangement = Arrangement.End
58 | ) {
59 | TextButton(
60 | onClick = {
61 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(githubUrl))
62 | context.startActivity(intent)
63 | }
64 | ) {
65 | Text(stringResource(R.string.github_details))
66 | }
67 | Spacer(Modifier.width(8.dp))
68 | TextButton(onClick = onDismiss) {
69 | Text(stringResource(R.string.close))
70 | }
71 | }
72 | }
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
45 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/setbox/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application")
3 | id("org.jetbrains.kotlin.android")
4 | }
5 |
6 | android {
7 | namespace = "com.yn.setbox"
8 | compileSdk = 34
9 | defaultConfig {
10 | applicationId = "com.yn.setbox"
11 | minSdk = 23
12 | targetSdk = 34
13 | versionCode = 1
14 | versionName = "1.0"
15 | multiDexEnabled = true
16 | vectorDrawables {
17 | useSupportLibrary = true
18 | }
19 | }
20 |
21 | buildFeatures {
22 | compose = true
23 | buildConfig = true
24 | }
25 |
26 | composeOptions {
27 | kotlinCompilerExtensionVersion = "1.5.15"
28 | }
29 |
30 | compileOptions {
31 | sourceCompatibility = JavaVersion.VERSION_17
32 | targetCompatibility = JavaVersion.VERSION_17
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = "17"
37 | freeCompilerArgs += "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api"
38 | }
39 | buildTypes {
40 | release {
41 | isMinifyEnabled = true
42 | isShrinkResources = true
43 | }
44 | }
45 | }
46 |
47 | dependencies {
48 | implementation(platform("androidx.compose:compose-bom:2024.10.00"))
49 | implementation("androidx.compose.material3:material3")
50 | implementation("androidx.compose.ui:ui")
51 | implementation("androidx.compose.ui:ui-graphics")
52 | implementation("androidx.compose.ui:ui-tooling-preview")
53 | implementation("androidx.compose.material:material-ripple")
54 | implementation("androidx.compose.material:material-icons-extended")
55 | implementation("androidx.activity:activity-compose:1.9.3")
56 | implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.6")
57 | implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.6")
58 | implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6")
59 | implementation("androidx.core:core-ktx:1.13.1")
60 | implementation("androidx.multidex:multidex:2.0.1")
61 | implementation("androidx.datastore:datastore-preferences:1.0.0")
62 | implementation("com.google.accompanist:accompanist-systemuicontroller:0.30.1")
63 | debugImplementation("androidx.compose.ui:ui-tooling")
64 | implementation("com.google.accompanist:accompanist-swiperefresh:0.32.0")
65 | debugImplementation("androidx.compose.ui:ui-test-manifest")
66 | implementation("dev.rikka.shizuku:api:12.1.0")
67 | implementation("dev.rikka.shizuku:provider:12.1.0")
68 | implementation("com.google.accompanist:accompanist-systemuicontroller:0.30.1")
69 | implementation("androidx.activity:activity-ktx:1.8.2")
70 | implementation("io.ktor:ktor-client-core:2.3.6")
71 | implementation("io.ktor:ktor-client-android:2.3.6")
72 | implementation("io.ktor:ktor-client-content-negotiation:2.3.6")
73 | implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.6")
74 | implementation("androidx.navigation:navigation-compose:2.7.7")
75 | implementation("org.slf4j:slf4j-nop:2.0.12")
76 | implementation("org.snakeyaml:snakeyaml-engine:2.7")
77 | implementation("com.google.accompanist:accompanist-systemuicontroller:0.32.0")
78 | }
--------------------------------------------------------------------------------
/setbox/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/setbox-plugin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/viewmodels/ThemeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.viewmodels
2 |
3 | import androidx.compose.runtime.State
4 | import androidx.compose.runtime.mutableStateOf
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.yn.setbox.core.AppPreferences
8 | import com.yn.setbox.core.AppTheme
9 | import kotlinx.coroutines.launch
10 |
11 | // ViewModel لإدارة حالة الثيم والتفاعل مع تفضيلات المستخدم.
12 | class ThemeViewModel(private val preferences: AppPreferences) : ViewModel() {
13 |
14 | private val _currentTheme = mutableStateOf(AppTheme.SYSTEM)
15 | val currentTheme: State = _currentTheme
16 |
17 | private val _isBlackThemeEnabled = mutableStateOf(false)
18 | val isBlackThemeEnabled: State = _isBlackThemeEnabled
19 |
20 | private val _isMaterialYouEnabled = mutableStateOf(true)
21 | val isMaterialYouEnabled: State = _isMaterialYouEnabled
22 |
23 | private val _hueShift = mutableStateOf(0f)
24 | val hueShift: State = _hueShift
25 |
26 | private val _saturationShift = mutableStateOf(0f)
27 | val saturationShift: State = _saturationShift
28 |
29 | init {
30 | // مراقبة التغييرات في DataStore لتحديث حالة الواجهة تلقائيًا.
31 | viewModelScope.launch {
32 | preferences.getTheme().collect { themeName ->
33 | _currentTheme.value = AppTheme.valueOf(themeName)
34 | }
35 | }
36 | viewModelScope.launch {
37 | preferences.isBlackThemeEnabled().collect { isEnabled ->
38 | _isBlackThemeEnabled.value = isEnabled
39 | }
40 | }
41 | viewModelScope.launch {
42 | preferences.isMaterialYouEnabled().collect { isEnabled ->
43 | _isMaterialYouEnabled.value = isEnabled
44 | }
45 | }
46 | viewModelScope.launch {
47 | preferences.getHueShift().collect { shift ->
48 | _hueShift.value = shift
49 | }
50 | }
51 | viewModelScope.launch {
52 | preferences.getSaturationShift().collect { shift ->
53 | _saturationShift.value = shift
54 | }
55 | }
56 | }
57 |
58 | // الدوال التالية تقوم بحفظ الإعدادات الجديدة في DataStore.
59 | fun setTheme(theme: AppTheme) {
60 | viewModelScope.launch {
61 | preferences.saveTheme(theme.name)
62 | }
63 | }
64 |
65 | fun setBlackThemeEnabled(enabled: Boolean) {
66 | viewModelScope.launch {
67 | preferences.setBlackThemeEnabled(enabled)
68 | }
69 | }
70 |
71 | fun setMaterialYouEnabled(enabled: Boolean) {
72 | viewModelScope.launch {
73 | preferences.setMaterialYouEnabled(enabled)
74 | }
75 | }
76 |
77 | fun setHueShift(shift: Float) {
78 | viewModelScope.launch {
79 | preferences.saveHueShift(shift)
80 | }
81 | }
82 |
83 | fun setSaturationShift(shift: Float) {
84 | viewModelScope.launch {
85 | preferences.saveSaturationShift(shift)
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/setbox/app/src/main/java/com/yn/setbox/ui/viewmodels/RepoViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.yn.setbox.ui.viewmodels
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.yn.setbox.data.model.RemoteModule
6 | import com.yn.setbox.data.repository.RepoRepository
7 | import kotlinx.coroutines.flow.MutableStateFlow
8 | import kotlinx.coroutines.flow.StateFlow
9 | import kotlinx.coroutines.flow.asStateFlow
10 | import kotlinx.coroutines.flow.update
11 | import kotlinx.coroutines.launch
12 |
13 | // حالة التنزيل لكل عنصر في المستودع.
14 | enum class DownloadState { IDLE, DOWNLOADING, COMPLETED, FAILED }
15 |
16 | // ViewModel لإدارة الوحدات المتاحة في المستودع عن بعد.
17 | class RepoViewModel(private val repository: RepoRepository) : ViewModel() {
18 |
19 | private val _modules = MutableStateFlow>(emptyList())
20 | val modules: StateFlow> = _modules.asStateFlow()
21 |
22 | private val _isLoading = MutableStateFlow(false)
23 | val isLoading: StateFlow = _isLoading.asStateFlow()
24 |
25 | // متغيرات حالة للتعامل مع الأخطاء وتصحيحها.
26 | private val _errorMessage = MutableStateFlow(null)
27 | val errorMessage: StateFlow = _errorMessage.asStateFlow()
28 |
29 | private val _rawJsonForDebug = MutableStateFlow(null)
30 | val rawJsonForDebug: StateFlow = _rawJsonForDebug.asStateFlow()
31 |
32 | // تتبع حالة التنزيل لكل وحدة على حدة.
33 | private val _downloadStates = MutableStateFlow