diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4b947956..1c917161 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,6 +5,7 @@ plugins { id("com.android.application") kotlin("android") id("kotlin-parcelize") + kotlin("plugin.serialization") } val composeVersion = "1.1.1" @@ -93,6 +94,7 @@ val languages: String get() { dependencies { implementation(kotlin("reflect")) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") // AndroidX implementation("androidx.core:core-ktx:1.7.0") @@ -146,6 +148,8 @@ dependencies { implementation("com.squareup.retrofit2:retrofit:$retrofitVersion") implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion") + implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0") + testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b9f5a5bf..a00bb840 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -12,11 +12,11 @@ # public *; #} --keep class com.vanced.manager.network.model.AppDto { +-keep class com.vanced.manager.network.dto.GithubReleaseDto { *; } --keep class com.vanced.manager.network.model.DataDto { +-keep class com.vanced.manager.network.dto.GithubReleaseAssetDto { *; } diff --git a/app/src/main/java/com/vanced/manager/ManagerApplication.kt b/app/src/main/java/com/vanced/manager/ManagerApplication.kt index eb39aee2..b22a632e 100644 --- a/app/src/main/java/com/vanced/manager/ManagerApplication.kt +++ b/app/src/main/java/com/vanced/manager/ManagerApplication.kt @@ -15,12 +15,11 @@ class ManagerApplication : Application() { modules( apiModule, + customTabsModule, + datasourceModule, downloaderModule, installerModule, - mapperModule, networkModule, - packageManagerModule, - preferenceModule, repositoryModule, serviceModule, viewModelModule, diff --git a/app/src/main/java/com/vanced/manager/core/preferences/CheckboxPreference.kt b/app/src/main/java/com/vanced/manager/core/preferences/CheckboxPreference.kt deleted file mode 100644 index ceb47e2f..00000000 --- a/app/src/main/java/com/vanced/manager/core/preferences/CheckboxPreference.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.vanced.manager.core.preferences - -data class CheckboxPreference( - val title: String, - val key: String, -) diff --git a/app/src/main/java/com/vanced/manager/core/preferences/RadioButtonPreference.kt b/app/src/main/java/com/vanced/manager/core/preferences/RadioButtonPreference.kt deleted file mode 100644 index 491b4fbf..00000000 --- a/app/src/main/java/com/vanced/manager/core/preferences/RadioButtonPreference.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.vanced.manager.core.preferences - -data class RadioButtonPreference( - val title: String, - val key: String -) diff --git a/app/src/main/java/com/vanced/manager/core/preferences/holder/PreferenceHolder.kt b/app/src/main/java/com/vanced/manager/core/preferences/holder/PreferenceHolder.kt index 3da7135c..9769bbb3 100644 --- a/app/src/main/java/com/vanced/manager/core/preferences/holder/PreferenceHolder.kt +++ b/app/src/main/java/com/vanced/manager/core/preferences/holder/PreferenceHolder.kt @@ -1,20 +1,13 @@ package com.vanced.manager.core.preferences.holder -import com.vanced.manager.core.preferences.managerBooleanPreference -import com.vanced.manager.core.preferences.managerLongPreference import com.vanced.manager.core.preferences.managerStringPreference import com.vanced.manager.core.preferences.managerStringSetPreference -import com.vanced.manager.ui.theme.defAccentColor -var useCustomTabsPref by managerBooleanPreference(USE_CUSTOM_TABS_KEY) var managerVariantPref by managerStringPreference( MANAGER_VARIANT_KEY, MANAGER_VARIANT_DEFAULT_VALUE ) -var managerThemePref by managerStringPreference(MANAGER_THEME_KEY, MANAGER_THEME_DEFAULT_VALUE) -var managerAccentColorPref by managerLongPreference(MANAGER_ACCENT_COLOR_KEY, defAccentColor) - var vancedThemePref by managerStringPreference(APP_VANCED_THEME_KEY, VANCED_THEME_DEFAULT_VALUE) var vancedVersionPref by managerStringPreference(APP_VANCED_VERSION_KEY, APP_VERSION_DEFAULT_VALUE) var vancedLanguagesPref by managerStringSetPreference( @@ -22,7 +15,4 @@ var vancedLanguagesPref by managerStringSetPreference( VANCED_LANGUAGE_DEFAULT_VALUE ) -var musicVersionPref by managerStringPreference(APP_MUSIC_VERSION_KEY, APP_VERSION_DEFAULT_VALUE) - -var vancedEnabled by managerBooleanPreference(VANCED_ENABLED_KEY, APP_ENABLED_DEFAULT_VALUE) -var musicEnabled by managerBooleanPreference(MUSIC_ENABLED_KEY, APP_ENABLED_DEFAULT_VALUE) \ No newline at end of file +var musicVersionPref by managerStringPreference(APP_MUSIC_VERSION_KEY, APP_VERSION_DEFAULT_VALUE) \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/core/util/Variant.kt b/app/src/main/java/com/vanced/manager/core/util/Variant.kt deleted file mode 100644 index 850f40cf..00000000 --- a/app/src/main/java/com/vanced/manager/core/util/Variant.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.vanced.manager.core.util - -enum class Variant { - - Root, Nonroot - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/datasource/PkgInfoDatasource.kt b/app/src/main/java/com/vanced/manager/datasource/PkgInfoDatasource.kt new file mode 100644 index 00000000..bbcfd0c4 --- /dev/null +++ b/app/src/main/java/com/vanced/manager/datasource/PkgInfoDatasource.kt @@ -0,0 +1,50 @@ +package com.vanced.manager.datasource + +import android.annotation.SuppressLint +import android.content.pm.PackageManager +import android.os.Build + +interface PkgInfoDatasource { + + fun getVersionCode(packageName: String): Int? + + fun getVersionName(packageName: String): String? + +} + +class PkgInfoDatasourceImpl( + private val packageManager: PackageManager +) : PkgInfoDatasource { + + private companion object { + const val FLAG_NOTHING = 0 + const val VERSION_IGNORE_MAJOR = 0xFFFFFFFF + } + + @SuppressLint("WrongConstant") + override fun getVersionCode(packageName: String): Int? { + return try { + val packageInfo = packageManager.getPackageInfo(packageName, FLAG_NOTHING) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + packageInfo.longVersionCode.and(VERSION_IGNORE_MAJOR).toInt() + } else { + @Suppress("DEPRECATION") + packageInfo.versionCode + } + } catch (e: PackageManager.NameNotFoundException) { + null + } + } + + @Suppress("DEPRECATION") + @SuppressLint("WrongConstant") + override fun getVersionName(packageName: String): String? { + return try { + packageManager + .getPackageInfo(packageName, FLAG_NOTHING) + .versionName + } catch (e: PackageManager.NameNotFoundException) { + null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/datasource/PreferenceDatasource.kt b/app/src/main/java/com/vanced/manager/datasource/PreferenceDatasource.kt new file mode 100644 index 00000000..7fd5c2fe --- /dev/null +++ b/app/src/main/java/com/vanced/manager/datasource/PreferenceDatasource.kt @@ -0,0 +1,68 @@ +package com.vanced.manager.datasource + +import android.content.SharedPreferences + +interface PreferenceDatasource { + + var managerUseCustomTabs: Boolean + var managerMode: String + var managerTheme: String + +} + +class PreferenceDatasourceImpl( + private val sharedPreferences: SharedPreferences +) : PreferenceDatasource { + + override var managerUseCustomTabs: Boolean + get() = getBoolean(PreferenceData.MANAGER_USE_CUSTOM_TABS_KEY, PreferenceData.MANAGER_USE_CUSTOM_TABS_DEFAULT_VALUE) + set(value) { + putBoolean(PreferenceData.MANAGER_USE_CUSTOM_TABS_KEY, value) + } + + override var managerMode: String + get() = getString(PreferenceData.MANAGER_MODE_KEY, PreferenceData.MANAGER_MODE_DEFAULT_VALUE) + set(value) { + putString(PreferenceData.MANAGER_MODE_KEY, value) + } + + override var managerTheme: String + get() = getString(PreferenceData.MANAGER_THEME_KEY, PreferenceData.MANAGER_THEME_DEFAULT_VALUE) + set(value) { + putString(PreferenceData.MANAGER_THEME_KEY, value) + } + + private fun getString(key: String, defaultValue: String): String { + return sharedPreferences.getString(key, defaultValue) ?: defaultValue + } + + private fun getBoolean(key: String, defaultValue: Boolean): Boolean { + return sharedPreferences.getBoolean(key, defaultValue) + } + + private fun putString(key: String, value: String) { + sharedPreferences.edit().putString(key, value).apply() + } + + private fun putBoolean(key: String, value: Boolean) { + sharedPreferences.edit().putBoolean(key, value).apply() + } +} + +object PreferenceData { + + const val MANAGER_USE_CUSTOM_TABS_KEY = "manager_behaviour_use_custom_tabs" + const val MANAGER_USE_CUSTOM_TABS_DEFAULT_VALUE = true + + const val MANAGER_MODE_KEY = "manager_behaviour_mode" + const val MANAGER_MODE_VALUE_ROOT = "root" + const val MANAGER_MODE_VALUE_NONROOT= "nonroot" + const val MANAGER_MODE_DEFAULT_VALUE = MANAGER_MODE_VALUE_NONROOT + + const val MANAGER_THEME_KEY = "manager_appearance_theme" + const val MANAGER_THEME_VALUE_LIGHT = "light" + const val MANAGER_THEME_VALUE_DARK = "dark" + const val MANAGER_THEME_VALUE_SYSTEM_DEFAULT = "system_default" + const val MANAGER_THEME_DEFAULT_VALUE = MANAGER_THEME_VALUE_SYSTEM_DEFAULT + +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/CustomTabsModule.kt b/app/src/main/java/com/vanced/manager/di/CustomTabsModule.kt new file mode 100644 index 00000000..ea29dcad --- /dev/null +++ b/app/src/main/java/com/vanced/manager/di/CustomTabsModule.kt @@ -0,0 +1,13 @@ +package com.vanced.manager.di + +import androidx.browser.customtabs.CustomTabsIntent +import org.koin.dsl.module + +val customTabsModule = module { + fun provideChromeCustomTabs(): CustomTabsIntent { + return CustomTabsIntent.Builder() + .build() + } + + single { provideChromeCustomTabs() } +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/DatasourceModule.kt b/app/src/main/java/com/vanced/manager/di/DatasourceModule.kt new file mode 100644 index 00000000..9984dff7 --- /dev/null +++ b/app/src/main/java/com/vanced/manager/di/DatasourceModule.kt @@ -0,0 +1,31 @@ +package com.vanced.manager.di + +import android.content.Context +import com.vanced.manager.datasource.PkgInfoDatasource +import com.vanced.manager.datasource.PkgInfoDatasourceImpl +import com.vanced.manager.datasource.PreferenceDatasource +import com.vanced.manager.datasource.PreferenceDatasourceImpl +import org.koin.android.ext.koin.androidContext +import org.koin.dsl.module + +val datasourceModule = module { + + fun providePkgInfoDatasource( + context: Context + ): PkgInfoDatasource { + return PkgInfoDatasourceImpl( + packageManager = context.packageManager + ) + } + + fun providePreferenceDatasource( + context: Context + ): PreferenceDatasource { + return PreferenceDatasourceImpl( + sharedPreferences = context.getSharedPreferences("manager_settings", Context.MODE_PRIVATE) + ) + } + + single { providePkgInfoDatasource(androidContext()) } + single { providePreferenceDatasource(androidContext()) } +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/MapperModule.kt b/app/src/main/java/com/vanced/manager/di/MapperModule.kt deleted file mode 100644 index e6a8159c..00000000 --- a/app/src/main/java/com/vanced/manager/di/MapperModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.vanced.manager.di - -import android.content.Context -import com.vanced.manager.domain.datasource.PackageInformationDataSource -import com.vanced.manager.network.model.AppDtoMapper -import com.vanced.manager.network.model.DataDtoMapper -import org.koin.dsl.module - -val mapperModule = module { - - fun provideAppMapper( - packageInformationDataSource: PackageInformationDataSource, - context: Context, - ) = AppDtoMapper(packageInformationDataSource, context) - - fun provideJsonMapper( - appDtoMapper: AppDtoMapper - ) = DataDtoMapper(appDtoMapper) - - single { provideAppMapper(get(), get()) } - single { provideJsonMapper(get()) } -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/PackageManagerModule.kt b/app/src/main/java/com/vanced/manager/di/PackageManagerModule.kt deleted file mode 100644 index 9c4170b2..00000000 --- a/app/src/main/java/com/vanced/manager/di/PackageManagerModule.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.vanced.manager.di - -import android.content.Context -import com.vanced.manager.domain.datasource.PackageInformationDataSource -import com.vanced.manager.domain.datasource.PackageInformationDataSourceImpl -import com.vanced.manager.domain.pkg.PkgManager -import com.vanced.manager.domain.pkg.PkgManagerImpl -import org.koin.dsl.module - -val packageManagerModule = module { - - fun providePackageManager( - context: Context - ): PkgManager = - PkgManagerImpl( - packageManager = context.packageManager - ) - - fun providePackageInformationDataSource( - pkgManager: PkgManager - ): PackageInformationDataSource = - PackageInformationDataSourceImpl(pkgManager) - - single { providePackageManager(get()) } - single { providePackageInformationDataSource(get()) } -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/PreferenceModule.kt b/app/src/main/java/com/vanced/manager/di/PreferenceModule.kt deleted file mode 100644 index 4c934494..00000000 --- a/app/src/main/java/com/vanced/manager/di/PreferenceModule.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.vanced.manager.di - -import android.content.Context -import org.koin.dsl.module - -val preferenceModule = module { - - fun provideDatastore( - context: Context - ) = context.getSharedPreferences("manager_settings", Context.MODE_PRIVATE) - - single { provideDatastore(get()) } -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/RepositoryModule.kt b/app/src/main/java/com/vanced/manager/di/RepositoryModule.kt index fae09460..a58352e3 100644 --- a/app/src/main/java/com/vanced/manager/di/RepositoryModule.kt +++ b/app/src/main/java/com/vanced/manager/di/RepositoryModule.kt @@ -1,25 +1,31 @@ package com.vanced.manager.di -import com.vanced.manager.network.DataService -import com.vanced.manager.network.model.DataDtoMapper -import com.vanced.manager.repository.DataRepository -import com.vanced.manager.repository.MainRepository -import com.vanced.manager.repository.MirrorRepository -import org.koin.core.qualifier.named +import com.vanced.manager.datasource.PkgInfoDatasource +import com.vanced.manager.datasource.PreferenceDatasource +import com.vanced.manager.network.GithubService +import com.vanced.manager.repository.* import org.koin.dsl.module val repositoryModule = module { - fun provideMainRepository( - dataService: DataService, - dataDtoMapper: DataDtoMapper - ) = MainRepository(dataService, dataDtoMapper) + fun provideGithubRepository( + githubService: GithubService, + pkgInfoDatasource: PkgInfoDatasource + ): AppRepository { + return AppRepositoryImpl( + githubService = githubService, + pkgInfoDatasource = pkgInfoDatasource + ) + } - fun provideMirrorRepository( - dataService: DataService, - dataDtoMapper: DataDtoMapper - ) = MirrorRepository(dataService, dataDtoMapper) + fun providePreferenceRepository( + preferenceDatasource: PreferenceDatasource + ): PreferenceRepository { + return PreferenceRepositoryImpl( + preferenceDatasource = preferenceDatasource + ) + } - single { provideMainRepository(get(named("main")), get()) } - single { provideMirrorRepository(get(named("mirror")), get()) } + single { provideGithubRepository(get(), get()) } + single { providePreferenceRepository(get()) } } \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/ServiceModule.kt b/app/src/main/java/com/vanced/manager/di/ServiceModule.kt index 5da133f8..c828e70f 100644 --- a/app/src/main/java/com/vanced/manager/di/ServiceModule.kt +++ b/app/src/main/java/com/vanced/manager/di/ServiceModule.kt @@ -1,35 +1,31 @@ package com.vanced.manager.di -import com.google.gson.GsonBuilder -import com.vanced.manager.network.DataService -import com.vanced.manager.network.util.BASE_GITHUB -import com.vanced.manager.network.util.BASE_MIRROR +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import com.vanced.manager.network.GithubService +import com.vanced.manager.network.util.GITHUB_API_BASE +import kotlinx.serialization.json.Json +import okhttp3.MediaType import okhttp3.OkHttpClient -import org.koin.core.qualifier.named import org.koin.dsl.module import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory +import retrofit2.create + +private val json = Json { + ignoreUnknownKeys = true +} val serviceModule = module { - fun provideMainService( + fun provideGithubService( okHttpClient: OkHttpClient - ) = Retrofit.Builder() - .baseUrl(BASE_GITHUB) - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())) - .client(okHttpClient) - .build() - .create(DataService::class.java) + ): GithubService { + return Retrofit.Builder() + .baseUrl(GITHUB_API_BASE) + .addConverterFactory(json.asConverterFactory(MediaType.get("application/json"))) + .client(okHttpClient) + .build() + .create() + } - fun provideMirrorService( - okHttpClient: OkHttpClient - ) = Retrofit.Builder() - .baseUrl(BASE_MIRROR) - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())) - .client(okHttpClient) - .build() - .create(DataService::class.java) - - single(named("main")) { provideMainService(get()) } - single(named("mirror")) { provideMirrorService(get()) } + single { provideGithubService(get()) } } \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/di/ViewModelModule.kt b/app/src/main/java/com/vanced/manager/di/ViewModelModule.kt index a7e40aca..8c411310 100644 --- a/app/src/main/java/com/vanced/manager/di/ViewModelModule.kt +++ b/app/src/main/java/com/vanced/manager/di/ViewModelModule.kt @@ -1,16 +1,14 @@ package com.vanced.manager.di import android.app.Application -import android.content.SharedPreferences import com.vanced.manager.core.downloader.impl.MicrogDownloader import com.vanced.manager.core.downloader.impl.MusicDownloader import com.vanced.manager.core.downloader.impl.VancedDownloader import com.vanced.manager.core.installer.impl.MicrogInstaller import com.vanced.manager.core.installer.impl.MusicInstaller import com.vanced.manager.core.installer.impl.VancedInstaller -import com.vanced.manager.repository.DataRepository -import com.vanced.manager.repository.MainRepository -import com.vanced.manager.repository.MirrorRepository +import com.vanced.manager.repository.AppRepository +import com.vanced.manager.repository.PreferenceRepository import com.vanced.manager.ui.viewmodel.ConfigurationViewModel import com.vanced.manager.ui.viewmodel.InstallViewModel import com.vanced.manager.ui.viewmodel.MainViewModel @@ -22,11 +20,16 @@ import org.koin.dsl.module val viewModelModule = module { fun provideMainViewModel( - mainRepository: MainRepository, - mirrorRepository: MirrorRepository, - preferences: SharedPreferences, + appRepository: AppRepository, + preferenceRepository: PreferenceRepository, app: Application, - ) = MainViewModel(mainRepository, mirrorRepository, preferences, app) + ): MainViewModel { + return MainViewModel( + appRepository = appRepository, + preferenceRepository = preferenceRepository, + app = app + ) + } fun provideInstallViewModel( vancedDownloader: VancedDownloader, @@ -42,12 +45,16 @@ val viewModelModule = module { return ConfigurationViewModel() } - fun provideSettingsViewModel(): SettingsViewModel { - return SettingsViewModel() + fun provideSettingsViewModel( + preferenceRepository: PreferenceRepository + ): SettingsViewModel { + return SettingsViewModel( + preferenceRepository = preferenceRepository + ) } - viewModel { provideMainViewModel(get(), get(), get(), androidApplication()) } + viewModel { provideMainViewModel(get(), get(), androidApplication()) } viewModel { provideInstallViewModel(get(), get(), get(), get(), get(), get()) } viewModel { provideConfigurationViewModel() } - viewModel { provideSettingsViewModel() } + viewModel { provideSettingsViewModel(get()) } } \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/domain/datasource/PackageInformationDataSource.kt b/app/src/main/java/com/vanced/manager/domain/datasource/PackageInformationDataSource.kt deleted file mode 100644 index f0d1ec16..00000000 --- a/app/src/main/java/com/vanced/manager/domain/datasource/PackageInformationDataSource.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.vanced.manager.domain.datasource - -import android.content.pm.PackageManager -import com.vanced.manager.domain.pkg.PkgManager -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -interface PackageInformationDataSource { - - suspend fun getVersionCode(packageName: String): Int? - - suspend fun getVersionName(packageName: String): String? -} - -class PackageInformationDataSourceImpl( - private val pkgManager: PkgManager -) : PackageInformationDataSource { - - override suspend fun getVersionCode(packageName: String): Int? = - withContext(Dispatchers.IO) { - try { - pkgManager.getVersionCode(packageName) - } catch (exception: PackageManager.NameNotFoundException) { - null - } - } - - override suspend fun getVersionName(packageName: String): String? = - withContext(Dispatchers.IO) { - try { - pkgManager.getVersionName(packageName) - } catch (exception: PackageManager.NameNotFoundException) { - null - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/domain/model/App.kt b/app/src/main/java/com/vanced/manager/domain/model/App.kt index 82db872e..0b5a7c06 100644 --- a/app/src/main/java/com/vanced/manager/domain/model/App.kt +++ b/app/src/main/java/com/vanced/manager/domain/model/App.kt @@ -1,18 +1,58 @@ package com.vanced.manager.domain.model +import androidx.annotation.DrawableRes +import com.vanced.manager.R + data class App( val name: String, - val remoteVersion: String, - val remoteVersionCode: Int, - val installedVersion: String?, - val installedVersionCode: Int?, - val iconUrl: String?, - val appStatus: AppStatus, - val packageName: String, + @DrawableRes val iconResId: Int, val changelog: String, - val url: String?, - val versions: List?, - val themes: List?, - val languages: List?, - val installationOptions: List? -) \ No newline at end of file + val remoteVersionCode: Int, + val remoteVersionName: String, + val installedVersionCode: Int?, + val installedVersionName: String?, + val packageName: String, + val launchActivity: String, + val state: AppState, + val app: AppType +) + +object AppData { + const val NAME_VANCED_YOUTUBE = "YouTube Vanced" + const val NAME_VANCED_YOUTUBE_MUSIC = "YouTube Vanced Music" + const val NAME_VANCED_MICROG = "Vanced microG" + const val NAME_VANCED_MANAGER = "Vanced Manager" + + const val ICON_VANCED_YOUTUBE = R.drawable.ic_vanced + const val ICON_VANCED_YOUTUBE_MUSIC = R.drawable.ic_music + const val ICON_VANCED_MICROG = R.drawable.ic_microg + const val ICON_VANCED_MANAGER = R.drawable.ic_manager + + const val PACKAGE_VANCED_YOUTUBE = "com.vanced.android.youtube" + const val PACKAGE_VANCED_YOUTUBE_MUSIC = "com.vanced.android.youtube.apps.music" + const val PACKAGE_VANCED_MICROG = "com.mgoogle.android.gms" + const val PACKAGE_VANCED_MANAGER = "com.vanced.manager" + + const val PACKAGE_ROOT_VANCED_YOUTUBE = "com.google.android.youtube" + const val PACKAGE_ROOT_VANCED_YOUTUBE_MUSIC = "com.google.android.youtube.apps.music" + + const val LAUNCH_ACTIVITY_VANCED_YOUTUBE = "com.google.android.youtube.HomeActivity" + const val LAUNCH_ACTIVITY_VANCED_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music.activities.MusicActivity" + const val LAUNCH_ACTIVITY_VANCED_MICROG = "org.microg.gms.ui.SettingsActivity" + const val LAUNCH_ACTIVITY_VANCED_MANAGER = "" +} + +enum class AppType { + VANCED_YOUTUBE, + VANCED_YOUTUBE_MUSIC, + VANCED_MICROG, + VANCED_MANAGER, +} + +enum class AppState { + NOT_INSTALLED, + INSTALLED, + NEEDS_UPDATE +} + + diff --git a/app/src/main/java/com/vanced/manager/domain/model/AppStatus.kt b/app/src/main/java/com/vanced/manager/domain/model/AppStatus.kt deleted file mode 100644 index e0ef6e97..00000000 --- a/app/src/main/java/com/vanced/manager/domain/model/AppStatus.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.vanced.manager.domain.model - -enum class AppStatus { - - Install, - Reinstall, - Update, - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/domain/model/Data.kt b/app/src/main/java/com/vanced/manager/domain/model/Data.kt deleted file mode 100644 index 89577d23..00000000 --- a/app/src/main/java/com/vanced/manager/domain/model/Data.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.vanced.manager.domain.model - -data class Data( - val manager: App, - val apps: List, -) diff --git a/app/src/main/java/com/vanced/manager/domain/pkg/PkgManager.kt b/app/src/main/java/com/vanced/manager/domain/pkg/PkgManager.kt deleted file mode 100644 index 885dceb3..00000000 --- a/app/src/main/java/com/vanced/manager/domain/pkg/PkgManager.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.vanced.manager.domain.pkg - -import android.annotation.SuppressLint -import android.content.pm.PackageManager -import android.os.Build - -interface PkgManager { - - @Throws(PackageManager.NameNotFoundException::class) - suspend fun getVersionCode(packageName: String): Int - - @Throws(PackageManager.NameNotFoundException::class) - suspend fun getVersionName(packageName: String): String -} - -class PkgManagerImpl( - private val packageManager: PackageManager -) : PkgManager { - - private companion object { - const val PACKAGE_FLAG_ALL_OFF = 0 - const val MAJOR_IGNORE = 0xFFFFFFFF - } - - @SuppressLint("WrongConstant") - @Suppress("DEPRECATION") - @Throws(PackageManager.NameNotFoundException::class) - override suspend fun getVersionCode( - packageName: String - ) = with(packageManager) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - getPackageInfo(packageName, PACKAGE_FLAG_ALL_OFF) - .longVersionCode - .and(MAJOR_IGNORE) - .toInt() - } else { - getPackageInfo(packageName, PACKAGE_FLAG_ALL_OFF) - .versionCode - } - } - - @SuppressLint("WrongConstant") - @Throws(PackageManager.NameNotFoundException::class) - override suspend fun getVersionName( - packageName: String - ): String = packageManager - .getPackageInfo(packageName, PACKAGE_FLAG_ALL_OFF) - .versionName -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/domain/util/EntityMapper.kt b/app/src/main/java/com/vanced/manager/domain/util/EntityMapper.kt deleted file mode 100644 index e7d847e6..00000000 --- a/app/src/main/java/com/vanced/manager/domain/util/EntityMapper.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.vanced.manager.domain.util - -interface EntityMapper { - - suspend fun mapToModel(entity: T): Model - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/DataService.kt b/app/src/main/java/com/vanced/manager/network/DataService.kt deleted file mode 100644 index a18e5038..00000000 --- a/app/src/main/java/com/vanced/manager/network/DataService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.vanced.manager.network - -import com.vanced.manager.network.model.DataDto -import retrofit2.http.GET - -interface DataService { - - @GET("latest.json") - suspend fun get(): DataDto - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/GithubService.kt b/app/src/main/java/com/vanced/manager/network/GithubService.kt new file mode 100644 index 00000000..6927d45e --- /dev/null +++ b/app/src/main/java/com/vanced/manager/network/GithubService.kt @@ -0,0 +1,22 @@ +package com.vanced.manager.network + +import com.vanced.manager.network.dto.GithubReleaseDto +import retrofit2.http.GET + +private const val REPOS_VANCED = "repos/YTVanced" + +interface GithubService { + + @GET("$REPOS_VANCED/Vanced/releases/latest") + suspend fun getVancedYoutubeRelease(): GithubReleaseDto + + @GET("$REPOS_VANCED/VancedMusic/releases/latest") + suspend fun getVancedYoutubeMusicRelease(): GithubReleaseDto + + @GET("$REPOS_VANCED/VancedMicrog/releases/latest") + suspend fun getVancedMicrogRelease(): GithubReleaseDto + + @GET("$REPOS_VANCED/VancedManager/releases/latest") + suspend fun getVancedManagerRelease(): GithubReleaseDto + +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/dto/GithubDto.kt b/app/src/main/java/com/vanced/manager/network/dto/GithubDto.kt new file mode 100644 index 00000000..c9ced164 --- /dev/null +++ b/app/src/main/java/com/vanced/manager/network/dto/GithubDto.kt @@ -0,0 +1,25 @@ +package com.vanced.manager.network.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GithubReleaseDto( + @SerialName("tag_name") + val tagName: String, + + @SerialName("body") + val body: String, + + @SerialName("assets") + val assets: List +) + +@Serializable +data class GithubReleaseAssetDto( + @SerialName("name") + val name: String, + + @SerialName("browser_download_url") + val browserDownloadUrl: String +) \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/model/AppDto.kt b/app/src/main/java/com/vanced/manager/network/model/AppDto.kt deleted file mode 100644 index d1161ca6..00000000 --- a/app/src/main/java/com/vanced/manager/network/model/AppDto.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.vanced.manager.network.model - -import com.google.gson.annotations.SerializedName - -data class AppDto( - @SerializedName("name") val name: String, - @SerializedName("version") val version: String, - @SerializedName("version_code") val versionCode: Int, - @SerializedName("changelog") val changelog: String, - @SerializedName("icon_url") val iconUrl: String, - @SerializedName("package_name") val packageName: String, - @SerializedName("url") val url: String? = null, - @SerializedName("versions") val versions: List? = null, - @SerializedName("themes") val themes: List? = null, - @SerializedName("langs") val languages: List? = null, -) diff --git a/app/src/main/java/com/vanced/manager/network/model/AppDtoMapper.kt b/app/src/main/java/com/vanced/manager/network/model/AppDtoMapper.kt deleted file mode 100644 index bf11e6ff..00000000 --- a/app/src/main/java/com/vanced/manager/network/model/AppDtoMapper.kt +++ /dev/null @@ -1,156 +0,0 @@ -package com.vanced.manager.network.model - -import android.content.Context -import com.vanced.manager.R -import com.vanced.manager.core.preferences.holder.musicVersionPref -import com.vanced.manager.core.preferences.holder.vancedLanguagesPref -import com.vanced.manager.core.preferences.holder.vancedThemePref -import com.vanced.manager.core.preferences.holder.vancedVersionPref -import com.vanced.manager.domain.datasource.PackageInformationDataSource -import com.vanced.manager.domain.model.App -import com.vanced.manager.domain.model.AppStatus -import com.vanced.manager.domain.model.InstallationOption -import com.vanced.manager.domain.model.InstallationOptionItem -import com.vanced.manager.domain.util.EntityMapper -import com.vanced.manager.network.util.MUSIC_NAME -import com.vanced.manager.network.util.VANCED_NAME -import java.util.* - -class AppDtoMapper( - private val pkgInfoDataSource: PackageInformationDataSource, - private val context: Context -) : EntityMapper { - - private val latestVersionRadioButton = - InstallationOptionItem( - displayText = { context.getString(R.string.app_version_dialog_option_latest) }, - key = "latest" - ) - - override suspend fun mapToModel( - entity: AppDto - ) = with(entity) { - val localVersionCode = pkgInfoDataSource.getVersionCode(packageName) - App( - name = name, - remoteVersion = version, - remoteVersionCode = versionCode, - installedVersion = pkgInfoDataSource.getVersionName(packageName), - installedVersionCode = localVersionCode, - appStatus = compareVersionCodes(versionCode, localVersionCode), - packageName = packageName, - iconUrl = iconUrl, - changelog = changelog, - url = url, - versions = versions, - themes = themes, - languages = languages, - installationOptions = getInstallationOptions(name, themes, versions, languages) - ) - } - - private fun compareVersionCodes( - remote: Int?, - local: Int? - ) = if (local != null && remote != null) { - when { - remote > local -> AppStatus.Update - remote <= local -> AppStatus.Reinstall - else -> AppStatus.Install - } - } else { - AppStatus.Install - } - - private fun getInstallationOptions( - appName: String, - appThemes: List?, - appVersions: List?, - appLanguages: List?, - ) : List? = when (appName) { - VANCED_NAME -> buildList { - if (appThemes != null) { - add( - InstallationOption.SingleSelect( - titleId = R.string.app_installation_options_theme, - getOption = { vancedThemePref }, - setOption = { - vancedThemePref = it - }, - items = appThemes.map { theme -> - InstallationOptionItem( - displayText = { - theme.replaceFirstChar { - it.titlecase(Locale.getDefault()) - } - }, - key = theme - ) - }, - ) - ) - } - if (appVersions != null) { - add( - InstallationOption.SingleSelect( - titleId = R.string.app_installation_options_version, - getOption = { vancedVersionPref }, - setOption = { - vancedVersionPref = it - }, - items = (appVersions.map { version -> - InstallationOptionItem( - displayText = { "v$version" }, - key = version - ) - } + latestVersionRadioButton).reversed(), - ) - ) - } - if (appLanguages != null) { - add( - InstallationOption.MultiSelect( - titleId = R.string.app_installation_options_language, - getOption = { vancedLanguagesPref }, - addOption = { - vancedLanguagesPref = vancedLanguagesPref + it - }, - removeOption = { - vancedLanguagesPref = vancedLanguagesPref - it - }, - items = appLanguages.map { language -> - InstallationOptionItem( - displayText = { - val locale = Locale(it) - locale.getDisplayName(locale) - }, - key = language - ) - }, - ) - ) - } - } - MUSIC_NAME -> buildList { - if (appVersions != null) { - add( - InstallationOption.SingleSelect( - titleId = R.string.app_installation_options_version, - getOption = { musicVersionPref }, - setOption = { - musicVersionPref = it - }, - items = (appVersions.map { version -> - InstallationOptionItem( - displayText = { "v$version" }, - key = version - ) - } + latestVersionRadioButton).reversed(), - ) - ) - } - - } - else -> null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/model/DataDto.kt b/app/src/main/java/com/vanced/manager/network/model/DataDto.kt deleted file mode 100644 index 36a3242f..00000000 --- a/app/src/main/java/com/vanced/manager/network/model/DataDto.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.vanced.manager.network.model - -import com.google.gson.annotations.SerializedName - -data class DataDto( - @SerializedName("manager") val manager: AppDto, - @SerializedName("apps") val apps: DataAppDto -) - -data class DataAppDto( - @SerializedName("nonroot") val nonroot: List, - @SerializedName("root") val root: List, -) \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/model/DataDtoMapper.kt b/app/src/main/java/com/vanced/manager/network/model/DataDtoMapper.kt deleted file mode 100644 index 479b8cc6..00000000 --- a/app/src/main/java/com/vanced/manager/network/model/DataDtoMapper.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.vanced.manager.network.model - -import com.vanced.manager.core.preferences.holder.managerVariantPref -import com.vanced.manager.domain.model.Data -import com.vanced.manager.domain.util.EntityMapper - -class DataDtoMapper( - private val appDtoMapper: AppDtoMapper -) : EntityMapper { - - override suspend fun mapToModel( - entity: DataDto - ) = with(entity) { - Data( - manager = appDtoMapper.mapToModel(manager), - apps = - if (managerVariantPref == "root") { - apps.root - } else { - apps.nonroot - }.map { appDto -> - appDtoMapper.mapToModel(appDto) - } - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/network/util/Constants.kt b/app/src/main/java/com/vanced/manager/network/util/Constants.kt index 71dafac8..bfffd1f7 100644 --- a/app/src/main/java/com/vanced/manager/network/util/Constants.kt +++ b/app/src/main/java/com/vanced/manager/network/util/Constants.kt @@ -1,8 +1,8 @@ package com.vanced.manager.network.util const val BASE = "https://api.vancedapp.com/api/v1/" -const val BASE_MIRROR = "https://x1nto.github.io/VancedFiles/api/v2/" //TODO -const val BASE_GITHUB = "https://x1nto.github.io/VancedFiles/api/v2/" + +const val GITHUB_API_BASE = "https://api.github.com/" const val VANCED_NAME = "YouTube Vanced" const val MUSIC_NAME = "YouTube Vanced Music" diff --git a/app/src/main/java/com/vanced/manager/repository/AppRepository.kt b/app/src/main/java/com/vanced/manager/repository/AppRepository.kt new file mode 100644 index 00000000..918a94ab --- /dev/null +++ b/app/src/main/java/com/vanced/manager/repository/AppRepository.kt @@ -0,0 +1,172 @@ +package com.vanced.manager.repository + +import com.vanced.manager.datasource.PkgInfoDatasource +import com.vanced.manager.domain.model.AppData +import com.vanced.manager.domain.model.AppState +import com.vanced.manager.domain.model.AppType +import com.vanced.manager.domain.model.App +import com.vanced.manager.network.GithubService +import com.vanced.manager.network.dto.GithubReleaseDto + +interface AppRepository { + + suspend fun getVancedYoutubeNonroot(): App + + suspend fun getVancedYoutubeRoot(): App + + suspend fun getVancedYoutubeMusicNonroot(): App + + suspend fun getVancedYoutubeMusicRoot(): App + + suspend fun getVancedMicrog(): App + + suspend fun getVancedManager(): App + +} + +class AppRepositoryImpl( + private val githubService: GithubService, + private val pkgInfoDatasource: PkgInfoDatasource, +) : AppRepository { + + override suspend fun getVancedYoutubeNonroot(): App { + val githubRelease = githubService.getVancedYoutubeRelease() + val remoteVersionCode = githubRelease.getVersionCode() + val remoteVersionName = githubRelease.getVersionName() + val installedVersionCode = pkgInfoDatasource.getVersionCode(AppData.PACKAGE_VANCED_YOUTUBE) + val installedVersionName = pkgInfoDatasource.getVersionName(AppData.PACKAGE_VANCED_YOUTUBE) + return App( + name = AppData.NAME_VANCED_YOUTUBE, + iconResId = AppData.ICON_VANCED_YOUTUBE, + changelog = githubRelease.body, + remoteVersionCode = remoteVersionCode, + remoteVersionName = remoteVersionName, + installedVersionCode = installedVersionCode, + installedVersionName = installedVersionName, + packageName = AppData.PACKAGE_VANCED_YOUTUBE, + launchActivity = AppData.LAUNCH_ACTIVITY_VANCED_YOUTUBE, + state = getNoonrotAppState(installedVersionCode, remoteVersionCode), + app = AppType.VANCED_YOUTUBE, + ) + } + + override suspend fun getVancedYoutubeRoot(): App { + val githubRelease = githubService.getVancedYoutubeRelease() + val remoteVersionCode = githubRelease.getVersionCode() + val remoteVersionName = githubRelease.getVersionName() + val installedVersionCode = pkgInfoDatasource.getVersionCode(AppData.PACKAGE_ROOT_VANCED_YOUTUBE) + val installedVersionName = pkgInfoDatasource.getVersionName(AppData.PACKAGE_ROOT_VANCED_YOUTUBE) + return App( + name = AppData.NAME_VANCED_YOUTUBE, + iconResId = AppData.ICON_VANCED_YOUTUBE, + changelog = githubRelease.body, + remoteVersionCode = remoteVersionCode, + remoteVersionName = remoteVersionName, + installedVersionCode = installedVersionCode, + installedVersionName = installedVersionName, + packageName = AppData.PACKAGE_VANCED_YOUTUBE, + launchActivity = AppData.LAUNCH_ACTIVITY_VANCED_YOUTUBE, + state = getNoonrotAppState(installedVersionCode, remoteVersionCode), + app = AppType.VANCED_YOUTUBE, + ) + } + + override suspend fun getVancedYoutubeMusicNonroot(): App { + val githubRelease = githubService.getVancedYoutubeMusicRelease() + val remoteVersionCode = githubRelease.getVersionCode() + val remoteVersionName = githubRelease.getVersionName() + val installedVersionCode = pkgInfoDatasource.getVersionCode(AppData.PACKAGE_VANCED_YOUTUBE_MUSIC) + val installedVersionName = pkgInfoDatasource.getVersionName(AppData.PACKAGE_VANCED_YOUTUBE_MUSIC) + return App( + name = AppData.NAME_VANCED_YOUTUBE_MUSIC, + iconResId = AppData.ICON_VANCED_YOUTUBE_MUSIC, + changelog = githubRelease.body, + remoteVersionCode = remoteVersionCode, + remoteVersionName = remoteVersionName, + installedVersionCode = installedVersionCode, + installedVersionName = installedVersionName, + packageName = AppData.PACKAGE_VANCED_YOUTUBE_MUSIC, + launchActivity = AppData.LAUNCH_ACTIVITY_VANCED_YOUTUBE_MUSIC, + state = getNoonrotAppState(installedVersionCode, remoteVersionCode), + app = AppType.VANCED_YOUTUBE_MUSIC, + ) + } + + override suspend fun getVancedYoutubeMusicRoot(): App { + val githubRelease = githubService.getVancedYoutubeMusicRelease() + val remoteVersionCode = githubRelease.getVersionCode() + val remoteVersionName = githubRelease.getVersionName() + val installedVersionCode = pkgInfoDatasource.getVersionCode(AppData.PACKAGE_ROOT_VANCED_YOUTUBE_MUSIC) + val installedVersionName = pkgInfoDatasource.getVersionName(AppData.PACKAGE_ROOT_VANCED_YOUTUBE_MUSIC) + return App( + name = AppData.NAME_VANCED_YOUTUBE_MUSIC, + iconResId = AppData.ICON_VANCED_YOUTUBE_MUSIC, + changelog = githubRelease.body, + remoteVersionCode = remoteVersionCode, + remoteVersionName = remoteVersionName, + installedVersionCode = installedVersionCode, + installedVersionName = installedVersionName, + packageName = AppData.PACKAGE_VANCED_YOUTUBE_MUSIC, + launchActivity = AppData.LAUNCH_ACTIVITY_VANCED_YOUTUBE_MUSIC, + state = getNoonrotAppState(installedVersionCode, remoteVersionCode), + app = AppType.VANCED_YOUTUBE_MUSIC, + ) + } + + override suspend fun getVancedMicrog(): App { + val githubRelease = githubService.getVancedMicrogRelease() + val remoteVersionCode = githubRelease.getVersionCode() + val remoteVersionName = githubRelease.getVersionName() + val installedVersionCode = pkgInfoDatasource.getVersionCode(AppData.PACKAGE_VANCED_MICROG) + val installedVersionName = pkgInfoDatasource.getVersionName(AppData.PACKAGE_VANCED_MICROG) + return App( + name = AppData.NAME_VANCED_MICROG, + iconResId = AppData.ICON_VANCED_MICROG, + changelog = githubRelease.body, + remoteVersionCode = remoteVersionCode, + remoteVersionName = remoteVersionName, + installedVersionCode = installedVersionCode, + installedVersionName = installedVersionName, + packageName = AppData.PACKAGE_VANCED_MICROG, + launchActivity = AppData.LAUNCH_ACTIVITY_VANCED_MICROG, + state = getNoonrotAppState(installedVersionCode, remoteVersionCode), + app = AppType.VANCED_MICROG, + ) + } + + override suspend fun getVancedManager(): App { + val githubRelease = githubService.getVancedManagerRelease() + val remoteVersionCode = githubRelease.getVersionCode() + val remoteVersionName = githubRelease.getVersionName() + val installedVersionCode = pkgInfoDatasource.getVersionCode(AppData.PACKAGE_VANCED_MANAGER) + val installedVersionName = pkgInfoDatasource.getVersionName(AppData.PACKAGE_VANCED_MANAGER) + return App( + name = AppData.NAME_VANCED_MANAGER, + iconResId = AppData.ICON_VANCED_MANAGER, + changelog = githubRelease.body, + remoteVersionCode = remoteVersionCode, + remoteVersionName = remoteVersionName, + installedVersionCode = installedVersionCode, + installedVersionName = installedVersionName, + packageName = AppData.PACKAGE_VANCED_MANAGER, + launchActivity = AppData.LAUNCH_ACTIVITY_VANCED_MANAGER, + state = getNoonrotAppState(installedVersionCode, remoteVersionCode), + app = AppType.VANCED_MANAGER, + ) + } + + private fun getNoonrotAppState( + installedVersionCode: Int?, + remoteVersionCode: Int + ): AppState { + return when { + installedVersionCode == null -> AppState.NOT_INSTALLED + installedVersionCode < remoteVersionCode -> AppState.NEEDS_UPDATE + installedVersionCode >= remoteVersionCode -> AppState.INSTALLED + else -> AppState.NOT_INSTALLED + } + } + + private fun GithubReleaseDto.getVersionCode() = tagName.substringAfter("-").toInt() + private fun GithubReleaseDto.getVersionName() = tagName.substringBefore("-") +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/repository/DataRepository.kt b/app/src/main/java/com/vanced/manager/repository/DataRepository.kt deleted file mode 100644 index 3879b0a8..00000000 --- a/app/src/main/java/com/vanced/manager/repository/DataRepository.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.vanced.manager.repository - -import com.vanced.manager.domain.model.Data - -interface DataRepository { - - suspend fun fetch(): Data - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/repository/MainRepository.kt b/app/src/main/java/com/vanced/manager/repository/MainRepository.kt deleted file mode 100644 index eab19bd7..00000000 --- a/app/src/main/java/com/vanced/manager/repository/MainRepository.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.vanced.manager.repository - -import com.vanced.manager.network.DataService -import com.vanced.manager.network.model.DataDtoMapper - -class MainRepository( - private val mainService: DataService, - private val mapper: DataDtoMapper -) : DataRepository { - - override suspend fun fetch() = - mapper.mapToModel(mainService.get()) - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/repository/MirrorRepository.kt b/app/src/main/java/com/vanced/manager/repository/MirrorRepository.kt deleted file mode 100644 index 5f0eb5ed..00000000 --- a/app/src/main/java/com/vanced/manager/repository/MirrorRepository.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.vanced.manager.repository - -import com.vanced.manager.network.DataService -import com.vanced.manager.network.model.DataDtoMapper - -class MirrorRepository( - private val mirrorService: DataService, - private val mapper: DataDtoMapper -) : DataRepository { - - override suspend fun fetch() = - mapper.mapToModel(mirrorService.get()) - -} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/repository/PreferenceRepository.kt b/app/src/main/java/com/vanced/manager/repository/PreferenceRepository.kt new file mode 100644 index 00000000..be9b71d7 --- /dev/null +++ b/app/src/main/java/com/vanced/manager/repository/PreferenceRepository.kt @@ -0,0 +1,77 @@ +package com.vanced.manager.repository + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.Composable +import com.vanced.manager.datasource.PreferenceData +import com.vanced.manager.datasource.PreferenceDatasource + +interface PreferenceRepository { + + var managerUseCustomTabs: Boolean + var managerMode: ManagerMode + var managerTheme: ManagerTheme + +} + +class PreferenceRepositoryImpl( + private val preferenceDatasource: PreferenceDatasource +) : PreferenceRepository { + + override var managerUseCustomTabs: Boolean + get() = preferenceDatasource.managerUseCustomTabs + set(value) { + preferenceDatasource.managerUseCustomTabs = value + } + + override var managerMode: ManagerMode + get() = ManagerMode.fromValue(preferenceDatasource.managerMode) + set(value) { + preferenceDatasource.managerMode = value.value + } + + override var managerTheme: ManagerTheme + get() = ManagerTheme.fromValue(preferenceDatasource.managerTheme) + set(value) { + preferenceDatasource.managerTheme = value.value + } + +} + + +enum class ManagerTheme(val value: String) { + LIGHT(PreferenceData.MANAGER_THEME_VALUE_LIGHT), + DARK(PreferenceData.MANAGER_THEME_VALUE_DARK), + SYSTEM_DEFAULT(PreferenceData.MANAGER_THEME_VALUE_SYSTEM_DEFAULT); + + @Composable + fun isDark() = when (this) { + LIGHT -> false + DARK -> true + SYSTEM_DEFAULT -> isSystemInDarkTheme() + } + + companion object { + fun fromValue(value: String?): ManagerTheme { + return values().find { + it.value == value + } ?: SYSTEM_DEFAULT + } + } +} + +enum class ManagerMode(val value: String) { + ROOT(PreferenceData.MANAGER_MODE_VALUE_ROOT), + NONROOT(PreferenceData.MANAGER_MODE_VALUE_NONROOT); + + val isRoot get() = this == ROOT + val isNonroot get() = this == NONROOT + + companion object { + fun fromValue(value: String?): ManagerMode { + return when (value) { + "root" -> ROOT + else -> NONROOT + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/ui/MainActivity.kt b/app/src/main/java/com/vanced/manager/ui/MainActivity.kt index fa427e38..a8882d52 100644 --- a/app/src/main/java/com/vanced/manager/ui/MainActivity.kt +++ b/app/src/main/java/com/vanced/manager/ui/MainActivity.kt @@ -73,12 +73,15 @@ class MainActivity : ComponentActivity() { when (val screen = backStack.last()) { is Screen.Home -> { HomeScreen( - viewModel = mainViewModel, + managerState = mainViewModel.appState, + onRefresh = { + mainViewModel.fetch() + }, onToolbarScreenSelected = { backStack.push(it) }, - onAppDownloadClick = { appName, appVersions, installationOptions -> - if (installationOptions != null) { + onAppDownloadClick = { app -> + /*if (installationOptions != null) { backStack.push( Screen.Configuration( appName, @@ -88,13 +91,13 @@ class MainActivity : ComponentActivity() { ) } else { backStack.push(Screen.Install(appName, appVersions)) - } + }*/ }, - onAppLaunchClick = { appName, packageName -> - mainViewModel.launchApp(appName, packageName) + onAppLaunchClick = { app -> + mainViewModel.launchApp(app.packageName, app.launchActivity) }, - onAppUninstallClick = { packageName -> - mainViewModel.uninstallApp(packageName) + onAppUninstallClick = { app -> + mainViewModel.uninstallApp(app.packageName) } ) } diff --git a/app/src/main/java/com/vanced/manager/ui/screen/HomeScreen.kt b/app/src/main/java/com/vanced/manager/ui/screen/HomeScreen.kt index e3959bb9..d97c6911 100644 --- a/app/src/main/java/com/vanced/manager/ui/screen/HomeScreen.kt +++ b/app/src/main/java/com/vanced/manager/ui/screen/HomeScreen.kt @@ -15,36 +15,30 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import coil.compose.rememberImagePainter -import coil.request.CachePolicy import com.google.accompanist.swiperefresh.rememberSwipeRefreshState import com.vanced.manager.R import com.vanced.manager.core.util.socialMedia import com.vanced.manager.core.util.sponsors import com.vanced.manager.domain.model.App -import com.vanced.manager.domain.model.InstallationOption import com.vanced.manager.ui.component.* import com.vanced.manager.ui.resource.managerString import com.vanced.manager.ui.util.Screen -import com.vanced.manager.ui.viewmodel.MainViewModel +import com.vanced.manager.ui.viewmodel.ManagerState import com.vanced.manager.ui.widget.AppCard import com.vanced.manager.ui.widget.AppCardPlaceholder import com.vanced.manager.ui.widget.LinkCard @Composable fun HomeScreen( - viewModel: MainViewModel, + managerState: ManagerState, + onRefresh: () -> Unit, onToolbarScreenSelected: (Screen) -> Unit, - onAppDownloadClick: ( - appName: String, - appVersions: List?, - installationOptions: List? - ) -> Unit, - onAppUninstallClick: (appPackage: String) -> Unit, - onAppLaunchClick: (appName: String, appPackage: String) -> Unit, + onAppDownloadClick: (App) -> Unit, + onAppUninstallClick: (App) -> Unit, + onAppLaunchClick: (App) -> Unit, ) { val refreshState = - rememberSwipeRefreshState(isRefreshing = viewModel.appState.isFetching) + rememberSwipeRefreshState(isRefreshing = managerState.isFetching) var menuExpanded by remember { mutableStateOf(false) } val dropdownScreens = remember { listOf(Screen.Settings, Screen.About) } @@ -68,24 +62,24 @@ fun HomeScreen( .fillMaxSize() .padding(paddingValues), swipeRefreshState = refreshState, - onRefresh = { viewModel.fetch() } + onRefresh = onRefresh ) { AnimatedContent( modifier = Modifier.fillMaxSize(), - targetState = viewModel.appState, + targetState = managerState, transitionSpec = { scaleIn(initialScale = 0.9f) + fadeIn() with scaleOut(targetScale = 0.9f) + fadeOut() } ) { animatedAppState -> when (animatedAppState) { - is StateFetching -> { + is ManagerState.Fetching -> { HomeScreenLoading( modifier = Modifier.fillMaxSize(), appsCount = animatedAppState.placeholderAppsCount ) } - is StateSuccess -> { + is ManagerState.Success -> { HomeScreenLoaded( modifier = Modifier.fillMaxSize(), apps = animatedAppState.apps, @@ -94,7 +88,7 @@ fun HomeScreen( onAppLaunchClick = onAppLaunchClick ) } - is StateError -> { + is ManagerState.Error -> { //TODO } } @@ -103,10 +97,6 @@ fun HomeScreen( } } -typealias StateFetching = MainViewModel.AppState.Fetching -typealias StateSuccess = MainViewModel.AppState.Success -typealias StateError = MainViewModel.AppState.Error - @Composable private fun HomeScreenTopBar( menuExpanded: Boolean, @@ -150,49 +140,34 @@ private fun HomeScreenTopBar( private fun HomeScreenLoaded( modifier: Modifier = Modifier, apps: List, - onAppDownloadClick: ( - appName: String, - appVersions: List?, - installationOptions: List? - ) -> Unit, - onAppUninstallClick: (appPackage: String) -> Unit, - onAppLaunchClick: (appName: String, appPackage: String) -> Unit, + onAppDownloadClick: (App) -> Unit, + onAppUninstallClick: (App) -> Unit, + onAppLaunchClick: (App) -> Unit, ) { HomeScreenBody(modifier = modifier) { managerCategory(categoryName = { managerString(R.string.home_category_apps) }) { items(apps) { app -> - val appIcon = rememberImagePainter(app.iconUrl) { - diskCachePolicy(CachePolicy.ENABLED) - } + val appIcon = painterResource(id = app.iconResId) var showAppInfoDialog by remember { mutableStateOf(false) } AppCard( - modifier = Modifier - .fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), appName = app.name, appIcon = appIcon, - appInstalledVersion = app.installedVersion, - appRemoteVersion = app.remoteVersion, + appInstalledVersion = app.installedVersionName, + appRemoteVersion = app.remoteVersionName, + appState = app.state, onAppDownloadClick = { - onAppDownloadClick( - app.name, - app.versions, - app.installationOptions - ) + onAppDownloadClick(app) }, onAppUninstallClick = { - onAppUninstallClick( - app.packageName - ) + onAppUninstallClick(app) }, onAppLaunchClick = { - onAppLaunchClick( - app.name, - app.packageName, - ) + onAppLaunchClick(app) }, onAppInfoClick = { showAppInfoDialog = true diff --git a/app/src/main/java/com/vanced/manager/ui/screen/SettingsScreen.kt b/app/src/main/java/com/vanced/manager/ui/screen/SettingsScreen.kt index 0a94efd5..9f0d081f 100644 --- a/app/src/main/java/com/vanced/manager/ui/screen/SettingsScreen.kt +++ b/app/src/main/java/com/vanced/manager/ui/screen/SettingsScreen.kt @@ -11,12 +11,11 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import com.vanced.manager.R -import com.vanced.manager.core.preferences.holder.managerThemePref -import com.vanced.manager.core.preferences.holder.managerVariantPref import com.vanced.manager.core.util.isMagiskInstalled +import com.vanced.manager.repository.ManagerMode +import com.vanced.manager.repository.ManagerTheme import com.vanced.manager.ui.component.* import com.vanced.manager.ui.resource.managerString -import com.vanced.manager.ui.theme.ManagerTheme import com.vanced.manager.ui.util.Screen import com.vanced.manager.ui.viewmodel.SettingsViewModel import org.koin.androidx.compose.viewModel @@ -60,13 +59,13 @@ fun SettingsScreen( preferenceDescription = stringResource(id = R.string.settings_preference_use_custom_tabs_summary), isChecked = viewModel.managerUseCustomTabs, onCheckedChange = { - viewModel.managerUseCustomTabs = it + viewModel.saveManagerUseCustomTabs(it) } ) } item { var showDialog by remember { mutableStateOf(false) } - var selectedMode by remember { mutableStateOf(EntryValue(viewModel.managerMode)) } + var selectedMode by remember { mutableStateOf(EntryValue(viewModel.managerMode.value)) } ManagerSingleSelectDialogPreference( preferenceTitle = managerString( stringId = R.string.settings_preference_variant_title @@ -83,7 +82,7 @@ fun SettingsScreen( }, onDismissRequest = { showDialog = false - selectedMode = EntryValue(managerVariantPref) + selectedMode = EntryValue(viewModel.managerMode.value) }, onEntrySelect = { if (it.value == "root" && !isMagiskInstalled) @@ -92,7 +91,7 @@ fun SettingsScreen( selectedMode = it }, onSave = { - viewModel.managerMode = selectedMode.value + viewModel.saveManagerMode(ManagerMode.fromValue(selectedMode.value)) showDialog = false } ) @@ -103,36 +102,38 @@ fun SettingsScreen( }) { item { var showDialog by remember { mutableStateOf(false) } - var selectedTheme by remember { mutableStateOf(EntryValue(managerThemePref)) } + var selectedTheme by remember { mutableStateOf(EntryValue(viewModel.managerTheme.value)) } ManagerSingleSelectDialogPreference( preferenceTitle = managerString(stringId = R.string.settings_preference_theme_title), preferenceDescription = managerString( - stringId = viewModel.getThemeStringIdByValue(selectedTheme.value) + stringId = viewModel.getThemeStringId( + ManagerTheme.fromValue(selectedTheme.value) + ) ), showDialog = showDialog, selected = selectedTheme, entries = mapOf( - EntryText(managerString(viewModel.getThemeStringIdByValue(SettingsViewModel.THEME_LIGHT_VALUE))) to - EntryValue(SettingsViewModel.THEME_LIGHT_VALUE), - EntryText(managerString(viewModel.getThemeStringIdByValue(SettingsViewModel.THEME_DARK_VALUE))) to - EntryValue(SettingsViewModel.THEME_DARK_VALUE), - EntryText(managerString(viewModel.getThemeStringIdByValue(SettingsViewModel.THEME_SYSTEM_DEFAULT_VALUE))) to - EntryValue(SettingsViewModel.THEME_SYSTEM_DEFAULT_VALUE), + EntryText(managerString(viewModel.getThemeStringId(ManagerTheme.LIGHT))) + to EntryValue(ManagerTheme.LIGHT.value), + EntryText(managerString(viewModel.getThemeStringId(ManagerTheme.DARK))) + to EntryValue(ManagerTheme.DARK.value), + EntryText(managerString(viewModel.getThemeStringId(ManagerTheme.SYSTEM_DEFAULT))) + to EntryValue(ManagerTheme.SYSTEM_DEFAULT.value), ), onClick = { showDialog = true }, onDismissRequest = { showDialog = false - selectedTheme = EntryValue(viewModel.managerTheme) + selectedTheme = EntryValue(viewModel.managerTheme.value) }, onEntrySelect = { selectedTheme = it }, onSave = { - viewModel.managerTheme = selectedTheme.value showDialog = false - onThemeChange(ManagerTheme.fromKey(selectedTheme.value)) + viewModel.saveManagerTheme(ManagerTheme.fromValue(selectedTheme.value)) + onThemeChange(ManagerTheme.fromValue(selectedTheme.value)) } ) } diff --git a/app/src/main/java/com/vanced/manager/ui/theme/Theme.kt b/app/src/main/java/com/vanced/manager/ui/theme/Theme.kt index 8eb0a3c2..683ba481 100644 --- a/app/src/main/java/com/vanced/manager/ui/theme/Theme.kt +++ b/app/src/main/java/com/vanced/manager/ui/theme/Theme.kt @@ -8,7 +8,6 @@ import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext -import com.vanced.manager.ui.viewmodel.SettingsViewModel const val defAccentColor = 0xFF0477E1 @@ -67,29 +66,6 @@ private val DarkThemeColors = darkColorScheme( inverseSurface = md_theme_dark_inverseSurface, ) -enum class ManagerTheme { - LIGHT, - DARK, - SYSTEM_DEFAULT; - - @Composable - fun isDark() = when (this) { - LIGHT -> false - DARK -> true - SYSTEM_DEFAULT -> isSystemInDarkTheme() - } - - companion object { - fun fromKey(key: String?): ManagerTheme { - return when (key) { - SettingsViewModel.THEME_DARK_VALUE -> DARK - SettingsViewModel.THEME_LIGHT_VALUE -> LIGHT - else -> SYSTEM_DEFAULT - } - } - } -} - @Composable inline fun apiDependantColorScheme( dynamic: () -> ColorScheme, diff --git a/app/src/main/java/com/vanced/manager/ui/viewmodel/MainViewModel.kt b/app/src/main/java/com/vanced/manager/ui/viewmodel/MainViewModel.kt index a028799e..8292a840 100644 --- a/app/src/main/java/com/vanced/manager/ui/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/vanced/manager/ui/viewmodel/MainViewModel.kt @@ -1,95 +1,84 @@ package com.vanced.manager.ui.viewmodel import android.app.Application -import android.content.ActivityNotFoundException import android.content.ComponentName import android.content.Intent -import android.content.SharedPreferences -import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.vanced.manager.core.installer.util.PM -import com.vanced.manager.core.preferences.holder.managerVariantPref import com.vanced.manager.domain.model.App -import com.vanced.manager.network.util.MICROG_NAME -import com.vanced.manager.network.util.MUSIC_NAME -import com.vanced.manager.network.util.VANCED_NAME -import com.vanced.manager.repository.MainRepository -import com.vanced.manager.repository.MirrorRepository -import com.vanced.manager.ui.theme.ManagerTheme +import com.vanced.manager.repository.* +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope +import retrofit2.HttpException class MainViewModel( - private val mainRepository: MainRepository, - private val mirrorRepository: MirrorRepository, - private val preferences: SharedPreferences, + private val appRepository: AppRepository, + private val preferenceRepository: PreferenceRepository, private val app: Application, ) : AndroidViewModel(app) { - private val isRoot - get() = managerVariantPref == "root" + var appMode by mutableStateOf(preferenceRepository.managerMode) + var appTheme by mutableStateOf(preferenceRepository.managerTheme) - private val appCount: Int - get() = if (isRoot) 2 else 3 + private val appCount + get() = when (appMode) { + ManagerMode.ROOT -> 2 + ManagerMode.NONROOT -> 3 + } - sealed class AppState { - data class Fetching(val placeholderAppsCount: Int) : AppState() - data class Success(val apps: List) : AppState() - data class Error(val error: String) : AppState() - - val isFetching get() = this is Fetching - val isSuccess get() = this is Success - val isError get() = this is Error - } - - var appState by mutableStateOf(AppState.Fetching(appCount)) + var appState by mutableStateOf(ManagerState.Fetching(appCount)) private set - var appTheme by mutableStateOf( - ManagerTheme.fromKey( - preferences.getString( - SettingsViewModel.MANAGER_THEME_KEY, - SettingsViewModel.THEME_SYSTEM_DEFAULT_VALUE - ) - ) - ) - fun fetch() { viewModelScope.launch { - appState = AppState.Fetching(appCount) + try { + supervisorScope { + appState = ManagerState.Fetching(appCount) - fetchData() + when (appMode) { + ManagerMode.ROOT -> { + appState = ManagerState.Success( + apps = listOf( + async { appRepository.getVancedYoutubeRoot() }, + async { appRepository.getVancedYoutubeMusicRoot() } + ).awaitAll() + ) + } + ManagerMode.NONROOT -> { + appState = ManagerState.Success( + apps = listOf( + async { appRepository.getVancedYoutubeNonroot() }, + async { appRepository.getVancedYoutubeMusicNonroot() }, + async { appRepository.getVancedMicrog() } + ).awaitAll() + ) + } + } + } + } catch (e: HttpException) { + appState = ManagerState.Error(e.message()) + } catch (e: Exception) { + appState = ManagerState.Error(e.toString()) + } } } fun launchApp( - appName: String, - appPackage: String, + packageName: String, + launchActivity: String ) { - val component = ComponentName( - /* pkg = */ appPackage, - /* cls = */ when (appName) { - VANCED_NAME -> "com.google.android.youtube.HomeActivity" - MUSIC_NAME -> "com.google.android.apps.youtube.music.activities.MusicActivity" - MICROG_NAME -> "org.microg.gms.ui.SettingsActivity" - else -> throw IllegalArgumentException("$appName is not a valid app") - } - ) - - try { - app.startActivity( - Intent().apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - setComponent(component) - } - ) - } catch (e: ActivityNotFoundException) { - Log.d(TAG, "Unable to launch $appName") - e.printStackTrace() + val component = ComponentName(packageName, launchActivity) + val intent = Intent().apply { + setComponent(component) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } + app.startActivity(intent) } //TODO implement root uninstallation @@ -99,28 +88,14 @@ class MainViewModel( PM.uninstallPackage(appPackage, app) } - private suspend fun fetchData( - fromMirror: Boolean = false - ) { - try { - val repository = if (fromMirror) mirrorRepository else mainRepository - with(repository.fetch()) { - appState = AppState.Success(apps) - } - } catch (e: Exception) { - if (!fromMirror) { - fetchData(true) - return - } +} - val error = "failed to fetch: \n${e.stackTraceToString()}" - appState = AppState.Error(error) - Log.d(TAG, error) - } - } - - companion object { - const val TAG = "MainViewModel" - } +sealed class ManagerState { + data class Fetching(val placeholderAppsCount: Int) : ManagerState() + data class Success(val apps: List) : ManagerState() + data class Error(val error: String) : ManagerState() + val isFetching get() = this is Fetching + val isSuccess get() = this is Success + val isError get() = this is Error } \ No newline at end of file diff --git a/app/src/main/java/com/vanced/manager/ui/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/vanced/manager/ui/viewmodel/SettingsViewModel.kt index 7623e996..807bb31a 100644 --- a/app/src/main/java/com/vanced/manager/ui/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/com/vanced/manager/ui/viewmodel/SettingsViewModel.kt @@ -1,29 +1,46 @@ package com.vanced.manager.ui.viewmodel +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import com.vanced.manager.R import com.vanced.manager.core.preferences.managerBooleanPreference import com.vanced.manager.core.preferences.managerStringPreference +import com.vanced.manager.repository.ManagerMode +import com.vanced.manager.repository.ManagerTheme +import com.vanced.manager.repository.PreferenceRepository -class SettingsViewModel : ViewModel() { +class SettingsViewModel( + private val preferenceRepository: PreferenceRepository +) : ViewModel() { - companion object { - const val MANAGER_THEME_KEY = "manager_theme" - const val MANAGER_MODE_KEY = "manager_mode" - - const val THEME_DARK_VALUE = "dark" - const val THEME_LIGHT_VALUE = "light" - const val THEME_SYSTEM_DEFAULT_VALUE = "system_default" + var managerUseCustomTabs by mutableStateOf(preferenceRepository.managerUseCustomTabs) + private set + var managerMode by mutableStateOf(preferenceRepository.managerMode) + private set + var managerTheme by mutableStateOf(preferenceRepository.managerTheme) + private set + + fun saveManagerUseCustomTabs(value: Boolean) { + managerUseCustomTabs = value + preferenceRepository.managerUseCustomTabs = value + } + + fun saveManagerMode(value: ManagerMode) { + managerMode = value + preferenceRepository.managerMode = value + } + + fun saveManagerTheme(value: ManagerTheme) { + managerTheme = value + preferenceRepository.managerTheme = value } - var managerUseCustomTabs by managerBooleanPreference(key = "manager_use_custom_tabs") - var managerMode by managerStringPreference(key = MANAGER_MODE_KEY, defaultValue = "nonroot") - var managerTheme by managerStringPreference(MANAGER_THEME_KEY, THEME_SYSTEM_DEFAULT_VALUE) - - fun getThemeStringIdByValue(value: String): Int { + fun getThemeStringId(value: ManagerTheme): Int { return when (value) { - THEME_DARK_VALUE -> R.string.settings_preference_theme_dark - THEME_LIGHT_VALUE -> R.string.settings_preference_theme_light + ManagerTheme.DARK -> R.string.settings_preference_theme_dark + ManagerTheme.LIGHT -> R.string.settings_preference_theme_light else -> R.string.settings_option_system_default } } diff --git a/app/src/main/java/com/vanced/manager/ui/widget/AppCard.kt b/app/src/main/java/com/vanced/manager/ui/widget/AppCard.kt index 93da10c2..63a79ecc 100644 --- a/app/src/main/java/com/vanced/manager/ui/widget/AppCard.kt +++ b/app/src/main/java/com/vanced/manager/ui/widget/AppCard.kt @@ -5,9 +5,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Info -import androidx.compose.material.icons.rounded.DeleteForever -import androidx.compose.material.icons.rounded.Download -import androidx.compose.material.icons.rounded.Launch +import androidx.compose.material.icons.rounded.* import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -15,13 +13,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import coil.compose.ImagePainter import com.google.accompanist.placeholder.PlaceholderHighlight import com.google.accompanist.placeholder.placeholder import com.google.accompanist.placeholder.shimmer import com.vanced.manager.R +import com.vanced.manager.domain.model.AppState import com.vanced.manager.ui.component.ManagerElevatedCard import com.vanced.manager.ui.component.ManagerListItem import com.vanced.manager.ui.component.ManagerText @@ -34,9 +33,10 @@ import com.vanced.manager.ui.util.DefaultContentPaddingVertical @Composable fun AppCard( appName: String, - appIcon: ImagePainter, + appIcon: Painter, appInstalledVersion: String?, appRemoteVersion: String?, + appState: AppState, onAppDownloadClick: () -> Unit, onAppUninstallClick: () -> Unit, onAppLaunchClick: () -> Unit, @@ -101,10 +101,27 @@ fun AppCard( } } IconButton(onClick = onAppDownloadClick) { - Icon( - imageVector = Icons.Rounded.Download, - contentDescription = "Install", - ) + when (appState) { + AppState.NOT_INSTALLED -> { + Icon( + imageVector = Icons.Rounded.GetApp, + contentDescription = "Install", + ) + } + AppState.INSTALLED -> { + Icon( + imageVector = Icons.Rounded.GetApp, + contentDescription = "Install", + ) + } + AppState.NEEDS_UPDATE -> { + Icon( + imageVector = Icons.Rounded.Update, + contentDescription = "Update", + ) + } + } + } } ) diff --git a/app/src/main/java/com/vanced/manager/ui/widget/LinkCard.kt b/app/src/main/java/com/vanced/manager/ui/widget/LinkCard.kt index 3af59e1b..7a97ff5a 100644 --- a/app/src/main/java/com/vanced/manager/ui/widget/LinkCard.kt +++ b/app/src/main/java/com/vanced/manager/ui/widget/LinkCard.kt @@ -1,6 +1,5 @@ package com.vanced.manager.ui.widget -import android.content.Intent import android.net.Uri import androidx.browser.customtabs.CustomTabsIntent import androidx.compose.foundation.layout.* @@ -13,11 +12,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import com.vanced.manager.core.preferences.holder.useCustomTabsPref import com.vanced.manager.ui.component.ManagerElevatedCard import com.vanced.manager.ui.component.ManagerText import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingVertical +import org.koin.androidx.compose.inject //TODO this composable should not handle opening links @Composable @@ -28,19 +27,14 @@ fun LinkCard( modifier: Modifier = Modifier ) { val context = LocalContext.current - val customTabs = remember { CustomTabsIntent.Builder().build() } + val customTabs: CustomTabsIntent by inject() val uri = remember { Uri.parse(url) } - val intent = remember { Intent(Intent.ACTION_VIEW, uri) } ManagerElevatedCard( modifier = modifier .height(100.dp) .widthIn(min = 100.dp), onClick = { - if (useCustomTabsPref) { - customTabs.launchUrl(context, uri) - } else { - context.startActivity(intent) - } + customTabs.launchUrl(context, uri) } ) { Box( diff --git a/build.gradle.kts b/build.gradle.kts index 480ec660..90bbc909 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,8 @@ buildscript { val kotlinVersion = "1.6.10" dependencies { classpath("com.android.tools.build:gradle:7.1.2") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + classpath(kotlin("gradle-plugin", version = kotlinVersion)) + classpath(kotlin("serialization", version = kotlinVersion)) } }