From 6fa3be22dd691b10a52e3520d91288d29edb5ce5 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Fri, 23 May 2025 12:01:47 +0530 Subject: [PATCH 01/11] Add flavours --- app/build.gradle.kts | 16 +++ .../view/ui/onboarding/OnboardingFragment.kt | 83 ++++++++++++ .../store/view/ui/splash/SplashFragment.kt | 69 ++++++++++ .../main/java/com/aurora/extensions/Intent.kt | 20 +++ .../java/com/aurora/store/util/Preferences.kt | 14 +- .../store/view/ui/commons/BaseFragment.kt | 2 +- .../view/ui/onboarding/AppLinksFragment.kt | 15 --- ....kt => BaseFlavouredOnboardingFragment.kt} | 122 ++++++------------ ...ment.kt => BaseFlavouredSplashFragment.kt} | 101 ++++----------- .../main/res/layout/fragment_app_links.xml | 47 ------- .../view/ui/onboarding/OnboardingFragment.kt | 84 ++++++++++++ .../store/view/ui/splash/SplashFragment.kt | 75 +++++++++++ 12 files changed, 425 insertions(+), 223 deletions(-) create mode 100644 app/src/huawei/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt create mode 100644 app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt delete mode 100644 app/src/main/java/com/aurora/store/view/ui/onboarding/AppLinksFragment.kt rename app/src/main/java/com/aurora/store/view/ui/onboarding/{OnboardingFragment.kt => BaseFlavouredOnboardingFragment.kt} (57%) rename app/src/main/java/com/aurora/store/view/ui/splash/{SplashFragment.kt => BaseFlavouredSplashFragment.kt} (76%) delete mode 100644 app/src/main/res/layout/fragment_app_links.xml create mode 100644 app/src/vanilla/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt create mode 100644 app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a052bffdd..832585b49 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -58,6 +58,8 @@ android { testInstrumentationRunnerArguments["disableAnalytics"] = "true" buildConfigField("String", "EXODUS_API_KEY", "\"bbe6ebae4ad45a9cbacb17d69739799b8df2c7ae\"") + + missingDimensionStrategy("device", "vanilla") } signingConfigs { @@ -108,12 +110,26 @@ android { } } + flavorDimensions += "device" + + productFlavors { + create("vanilla"){ + dimension = "device" + } + + create("huawei") { + dimension = "device" + versionNameSuffix = "-hw" + } + } + buildFeatures { buildConfig = true viewBinding = true aidl = true compose = true } + kotlinOptions { jvmTarget = JavaVersion.VERSION_21.toString() } diff --git a/app/src/huawei/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt b/app/src/huawei/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt new file mode 100644 index 000000000..d2119f027 --- /dev/null +++ b/app/src/huawei/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt @@ -0,0 +1,83 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.onboarding + +import androidx.fragment.app.Fragment +import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE +import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB +import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS +import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY +import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID +import com.aurora.store.util.Preferences.PREFERENCE_FOR_YOU +import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID +import com.aurora.store.util.Preferences.PREFERENCE_SIMILAR +import com.aurora.store.util.Preferences.PREFERENCE_THEME_STYLE +import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL +import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED +import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION +import com.aurora.store.util.save +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class OnboardingFragment : BaseFlavouredOnboardingFragment() { + + override fun loadDefaultPreferences() { + /*Filters*/ + save(PREFERENCE_FILTER_AURORA_ONLY, false) + save(PREFERENCE_FILTER_FDROID, true) + + /*Network*/ + save(PREFERENCE_DISPENSER_URLS, setOf()) + save(PREFERENCE_VENDING_VERSION, 0) + + /*Customization*/ + save(PREFERENCE_THEME_STYLE, 0) + save(PREFERENCE_DEFAULT_SELECTED_TAB, 0) + save(PREFERENCE_FOR_YOU, true) + save(PREFERENCE_SIMILAR, true) + + /*Installer*/ + save(PREFERENCE_AUTO_DELETE, true) + save(PREFERENCE_INSTALLER_ID, 0) + + /*Updates*/ + save(PREFERENCE_UPDATES_EXTENDED, false) + save(PREFERENCE_UPDATES_CHECK_INTERVAL, 3) + } + + override fun onboardingPages(): List { + return listOf( + WelcomeFragment(), + PermissionsFragment.newInstance() + ) + } + + override fun setupAutoUpdates() { + super.setupAutoUpdates() + + // Remove super & implement variant logic here + } + + override fun finishOnboarding() { + super.finishOnboarding() + + // Remove super & implement variant logic here + } +} diff --git a/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt new file mode 100644 index 000000000..7eae959cc --- /dev/null +++ b/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -0,0 +1,69 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.splash + +import android.accounts.AccountManager +import android.util.Log +import androidx.navigation.fragment.findNavController +import com.aurora.extensions.hide +import com.aurora.store.R +import com.aurora.store.data.model.AuthState +import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class SplashFragment : BaseFlavouredSplashFragment() { + + private val TAG = SplashFragment::class.java.simpleName + + override fun attachActions() { + binding.btnAnonymous.hide() + + binding.btnGoogle.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnGoogle.updateProgress(true) + if (canLoginWithMicroG) { + Log.i(TAG, "Found supported microG, trying to request credentials") + val accountIntent = AccountManager.newChooseAccountIntent( + null, + null, + arrayOf(GOOGLE_ACCOUNT_TYPE), + null, + null, + null, + null + ) + startForAccount.launch(accountIntent) + } else { + findNavController().navigate(R.id.googleFragment) + } + } + } + } + + override fun resetActions() { + binding.btnAnonymous.hide() + + binding.btnGoogle.apply { + updateProgress(false) + isEnabled = true + } + } +} diff --git a/app/src/main/java/com/aurora/extensions/Intent.kt b/app/src/main/java/com/aurora/extensions/Intent.kt index c270615ab..e9b159401 100644 --- a/app/src/main/java/com/aurora/extensions/Intent.kt +++ b/app/src/main/java/com/aurora/extensions/Intent.kt @@ -21,6 +21,7 @@ package com.aurora.extensions import android.content.Context import android.content.Intent +import android.net.UrlQuerySanitizer import android.os.Bundle inline fun Context.newIntent(): Intent = @@ -40,3 +41,22 @@ inline fun Context.newIntent(flags: Int, extras: Bundle): intent.putExtras(extras) return intent } + +fun Intent.getPackageName(fallbackBundle: Bundle? = null): String? { + return when (action) { + Intent.ACTION_VIEW -> { + data?.getQueryParameter("id") + } + Intent.ACTION_SEND -> { + val clipData = getStringExtra(Intent.EXTRA_TEXT).orEmpty() + UrlQuerySanitizer(clipData).getValue("id") + } + Intent.ACTION_SHOW_APP_INFO -> { + extras?.getString(Intent.EXTRA_PACKAGE_NAME) + } + else -> { + extras?.getString("packageName") ?: fallbackBundle?.getString("packageName") + } + } +} + diff --git a/app/src/main/java/com/aurora/store/util/Preferences.kt b/app/src/main/java/com/aurora/store/util/Preferences.kt index 393de4c2c..326dd27a2 100644 --- a/app/src/main/java/com/aurora/store/util/Preferences.kt +++ b/app/src/main/java/com/aurora/store/util/Preferences.kt @@ -24,6 +24,7 @@ import android.content.SharedPreferences import androidx.core.content.edit import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager +import com.aurora.store.BuildConfig object Preferences { @@ -65,10 +66,17 @@ object Preferences { private var prefs: SharedPreferences? = null fun getPrefs(context: Context): SharedPreferences { - if (prefs == null) { - prefs = PreferenceManager.getDefaultSharedPreferences(context) + return when (BuildConfig.FLAVOR) { + "vanilla" -> { + prefs ?: PreferenceManager.getDefaultSharedPreferences(context).also { prefs = it } + } + + else -> { + val prefName = "${context.packageName}_${BuildConfig.FLAVOR}_preferences" + prefs ?: context.getSharedPreferences(prefName, Context.MODE_PRIVATE) + .also { prefs = it } + } } - return prefs!! } fun remove(context: Context, key: String) { diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt index 75725406f..08bb684d1 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt @@ -42,7 +42,7 @@ abstract class BaseFragment : Fragment() { lateinit var permissionProvider: PermissionProvider - private var _binding: ViewBindingType? = null + protected open var _binding: ViewBindingType? = null protected val binding get() = _binding!! override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/aurora/store/view/ui/onboarding/AppLinksFragment.kt b/app/src/main/java/com/aurora/store/view/ui/onboarding/AppLinksFragment.kt deleted file mode 100644 index 13bbc6cf8..000000000 --- a/app/src/main/java/com/aurora/store/view/ui/onboarding/AppLinksFragment.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.aurora.store.view.ui.onboarding - -import android.os.Bundle -import android.view.View -import com.aurora.store.databinding.FragmentAppLinksBinding -import com.aurora.store.view.ui.commons.BaseFragment -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class AppLinksFragment : BaseFragment() { - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - } -} diff --git a/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt b/app/src/main/java/com/aurora/store/view/ui/onboarding/BaseFlavouredOnboardingFragment.kt similarity index 57% rename from app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt rename to app/src/main/java/com/aurora/store/view/ui/onboarding/BaseFlavouredOnboardingFragment.kt index db797ba60..00a7b6f4a 100644 --- a/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/onboarding/BaseFlavouredOnboardingFragment.kt @@ -1,26 +1,9 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - package com.aurora.store.view.ui.onboarding import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.fragment.app.Fragment @@ -29,59 +12,36 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback -import com.aurora.Constants import com.aurora.extensions.areNotificationsEnabled import com.aurora.extensions.isIgnoringBatteryOptimizations import com.aurora.store.R import com.aurora.store.data.model.UpdateMode import com.aurora.store.data.work.CacheWorker import com.aurora.store.databinding.FragmentOnboardingBinding -import com.aurora.store.util.CertUtil import com.aurora.store.util.PackageUtil import com.aurora.store.util.Preferences -import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT -import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB -import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS -import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY -import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID -import com.aurora.store.util.Preferences.PREFERENCE_FOR_YOU -import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID import com.aurora.store.util.Preferences.PREFERENCE_INTRO -import com.aurora.store.util.Preferences.PREFERENCE_SIMILAR -import com.aurora.store.util.Preferences.PREFERENCE_THEME_STYLE import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO -import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL -import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED -import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION import com.aurora.store.util.save import com.aurora.store.view.ui.commons.BaseFragment import com.aurora.store.viewmodel.onboarding.OnboardingViewModel import com.google.android.material.tabs.TabLayoutMediator import com.jakewharton.processphoenix.ProcessPhoenix -import dagger.hilt.android.AndroidEntryPoint -@AndroidEntryPoint -class OnboardingFragment : BaseFragment() { +abstract class BaseFlavouredOnboardingFragment : BaseFragment() { - private val viewModel: OnboardingViewModel by viewModels() + val viewModel: OnboardingViewModel by viewModels() - private var lastPosition = 0 + var lastPosition = 0 - internal class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : - FragmentStateAdapter(fragmentManager, lifecycle) { - override fun createFragment(position: Int): Fragment { - when (position) { - 0 -> return WelcomeFragment() - 1 -> return PermissionsFragment.newInstance() - 2 -> return AppLinksFragment() - } - return Fragment() - } - - override fun getItemCount(): Int { - return 2 - } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentOnboardingBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -95,6 +55,7 @@ class OnboardingFragment : BaseFragment() { } val isDefaultPrefLoaded = Preferences.getBoolean(requireContext(), PREFERENCE_DEFAULT) + if (!isDefaultPrefLoaded) { save(PREFERENCE_DEFAULT, true) loadDefaultPreferences() @@ -105,7 +66,11 @@ class OnboardingFragment : BaseFragment() { // ViewPager2 binding.viewpager2.apply { - adapter = PagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) + adapter = PagerAdapter( + childFragmentManager, + viewLifecycleOwner.lifecycle, + onboardingPages() + ) isUserInputEnabled = false setCurrentItem(0, true) registerOnPageChangeCallback(object : OnPageChangeCallback() { @@ -149,7 +114,11 @@ class OnboardingFragment : BaseFragment() { } } - private fun finishOnboarding() { + abstract fun loadDefaultPreferences() + + abstract fun onboardingPages(): List + + open fun finishOnboarding() { setupAutoUpdates() CacheWorker.scheduleAutomatedCacheCleanup(requireContext()) Preferences.putBooleanNow(requireContext(), PREFERENCE_INTRO, true) @@ -158,40 +127,29 @@ class OnboardingFragment : BaseFragment() { ProcessPhoenix.triggerRebirth(context) } - private fun loadDefaultPreferences() { - /*Filters*/ - save(PREFERENCE_FILTER_AURORA_ONLY, false) - save(PREFERENCE_FILTER_FDROID, true) - - /*Network*/ - // TODO: Gather feedback and drop setting default dispenser for all builds - if (!CertUtil.isAppGalleryApp(requireContext(), requireContext().packageName)) { - save(PREFERENCE_DISPENSER_URLS, setOf(Constants.URL_DISPENSER)) - } - save(PREFERENCE_VENDING_VERSION, 0) - - /*Customization*/ - save(PREFERENCE_THEME_STYLE, 0) - save(PREFERENCE_DEFAULT_SELECTED_TAB, 0) - save(PREFERENCE_FOR_YOU, true) - save(PREFERENCE_SIMILAR, false) - - /*Installer*/ - save(PREFERENCE_AUTO_DELETE, true) - save(PREFERENCE_INSTALLER_ID, 0) - - /*Updates*/ - save(PREFERENCE_UPDATES_EXTENDED, false) - save(PREFERENCE_UPDATES_CHECK_INTERVAL, 3) - } - - private fun setupAutoUpdates() { + open fun setupAutoUpdates() { val updateMode = when { requireContext().isIgnoringBatteryOptimizations() -> UpdateMode.CHECK_AND_INSTALL requireContext().areNotificationsEnabled() -> UpdateMode.CHECK_AND_NOTIFY else -> UpdateMode.DISABLED } + save(PREFERENCE_UPDATES_AUTO, updateMode.ordinal) + viewModel.updateHelper.scheduleAutomatedCheck() } + + internal class PagerAdapter( + fragmentManager: FragmentManager, + lifecycle: Lifecycle, + var items: List + ) : FragmentStateAdapter(fragmentManager, lifecycle) { + override fun createFragment(position: Int): Fragment { + return items[position] + } + + override fun getItemCount(): Int { + return items.size + } + } } diff --git a/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt similarity index 76% rename from app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt rename to app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt index d69cbe170..f777bcf4d 100644 --- a/app/src/main/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt @@ -1,45 +1,25 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - package com.aurora.store.view.ui.splash import android.accounts.Account import android.accounts.AccountManager -import android.content.Intent -import android.net.UrlQuerySanitizer import android.os.Bundle import android.os.Handler import android.os.Looper import android.util.Base64 import android.util.Log +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import com.aurora.extensions.getPackageName import com.aurora.extensions.hide import com.aurora.extensions.isMAndAbove -import com.aurora.extensions.isNAndAbove import com.aurora.extensions.navigate -import com.aurora.extensions.show import com.aurora.gplayapi.helpers.AuthHelper import com.aurora.store.R import com.aurora.store.compose.navigation.Screen @@ -56,22 +36,20 @@ import com.aurora.store.util.Preferences.PREFERENCE_INTRO import com.aurora.store.util.Preferences.PREFERENCE_MICROG_AUTH import com.aurora.store.view.ui.commons.BaseFragment import com.aurora.store.viewmodel.auth.AuthViewModel -import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -@AndroidEntryPoint -class SplashFragment : BaseFragment() { +abstract class BaseFlavouredSplashFragment : BaseFragment() { private val TAG = SplashFragment::class.java.simpleName - private val viewModel: AuthViewModel by activityViewModels() + val viewModel: AuthViewModel by activityViewModels() - private val canLoginWithMicroG: Boolean + val canLoginWithMicroG: Boolean get() = isMAndAbove && PackageUtil.hasSupportedMicroG(requireContext()) && Preferences.getBoolean(requireContext(), PREFERENCE_MICROG_AUTH, true) - private val startForAccount = + val startForAccount = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { val accountName = it.data?.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) if (!accountName.isNullOrBlank()) { @@ -81,6 +59,15 @@ class SplashFragment : BaseFragment() { } } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentSplashBinding.inflate(inflater, container, false) + return binding.root + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -116,7 +103,7 @@ class SplashFragment : BaseFragment() { attachActions() // Show anonymous logins if we have dispenser URL - binding.btnAnonymous.isVisible = !viewModel.authProvider.dispenserURL.isNullOrBlank() + binding.btnAnonymous.isVisible = false viewLifecycleOwner.lifecycleScope.launch { viewModel.authState.collectLatest { @@ -128,7 +115,8 @@ class SplashFragment : BaseFragment() { } AuthState.Valid -> { - val packageName = getPackageName(requireActivity().intent) + val packageName = + requireActivity().intent.getPackageName(requireArguments()) if (packageName.isNullOrBlank()) { navigateToDefaultTab() } else { @@ -152,7 +140,8 @@ class SplashFragment : BaseFragment() { } AuthState.SignedIn -> { - val packageName = getPackageName(requireActivity().intent) + val packageName = + requireActivity().intent.getPackageName(requireArguments()) if (packageName.isNullOrBlank()) { navigateToDefaultTab() } else { @@ -193,22 +182,12 @@ class SplashFragment : BaseFragment() { } private fun updateActionLayout(isVisible: Boolean) { - if (isVisible) { - binding.layoutAction.show() - binding.toolbar.visibility = View.VISIBLE - } else { - binding.layoutAction.hide() - binding.toolbar.visibility = View.GONE - } + binding.layoutAction.isVisible = isVisible + binding.toolbar.isVisible = isVisible } - private fun attachActions() { - binding.btnAnonymous.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnAnonymous.updateProgress(true) - viewModel.buildAnonymousAuthData() - } - } + open fun attachActions() { + binding.btnAnonymous.hide() binding.btnGoogle.addOnClickListener { if (viewModel.authState.value != AuthState.Fetching) { @@ -232,16 +211,11 @@ class SplashFragment : BaseFragment() { } } - private fun resetActions() { + open fun resetActions() { binding.btnGoogle.apply { updateProgress(false) isEnabled = true } - - binding.btnAnonymous.apply { - updateProgress(false) - isEnabled = true - } } private fun navigateToDefaultTab() { @@ -262,29 +236,6 @@ class SplashFragment : BaseFragment() { findNavController().navigate(directions) } - private fun getPackageName(intent: Intent): String? { - return when { - intent.action == Intent.ACTION_VIEW -> { - intent.data!!.getQueryParameter("id") - } - - intent.action == Intent.ACTION_SEND -> { - val clipData = intent.getStringExtra(Intent.EXTRA_TEXT) ?: "" - UrlQuerySanitizer(clipData).getValue("id") - } - - isNAndAbove && intent.action == Intent.ACTION_SHOW_APP_INFO -> { - intent.extras?.getString(Intent.EXTRA_PACKAGE_NAME) - } - - intent.extras != null -> { - intent.extras?.getString("packageName") - } - - else -> requireArguments().getString("packageName") - } - } - private fun requestAuthTokenForGoogle(accountName: String, oldToken: String? = null) { try { if (oldToken != null) { diff --git a/app/src/main/res/layout/fragment_app_links.xml b/app/src/main/res/layout/fragment_app_links.xml deleted file mode 100644 index 6d8e1e1e3..000000000 --- a/app/src/main/res/layout/fragment_app_links.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - diff --git a/app/src/vanilla/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt b/app/src/vanilla/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt new file mode 100644 index 000000000..cadc94c05 --- /dev/null +++ b/app/src/vanilla/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt @@ -0,0 +1,84 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.onboarding + +import androidx.fragment.app.Fragment +import com.aurora.Constants +import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE +import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB +import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS +import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY +import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID +import com.aurora.store.util.Preferences.PREFERENCE_FOR_YOU +import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID +import com.aurora.store.util.Preferences.PREFERENCE_SIMILAR +import com.aurora.store.util.Preferences.PREFERENCE_THEME_STYLE +import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL +import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED +import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION +import com.aurora.store.util.save +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class OnboardingFragment : BaseFlavouredOnboardingFragment() { + + override fun loadDefaultPreferences() { + /*Filters*/ + save(PREFERENCE_FILTER_AURORA_ONLY, false) + save(PREFERENCE_FILTER_FDROID, true) + + /*Network*/ + save(PREFERENCE_DISPENSER_URLS, setOf(Constants.URL_DISPENSER)) + save(PREFERENCE_VENDING_VERSION, 0) + + /*Customization*/ + save(PREFERENCE_THEME_STYLE, 0) + save(PREFERENCE_DEFAULT_SELECTED_TAB, 0) + save(PREFERENCE_FOR_YOU, true) + save(PREFERENCE_SIMILAR, false) + + /*Installer*/ + save(PREFERENCE_AUTO_DELETE, true) + save(PREFERENCE_INSTALLER_ID, 0) + + /*Updates*/ + save(PREFERENCE_UPDATES_EXTENDED, false) + save(PREFERENCE_UPDATES_CHECK_INTERVAL, 3) + } + + override fun onboardingPages(): List { + return listOf( + WelcomeFragment(), + PermissionsFragment.newInstance() + ) + } + + override fun setupAutoUpdates() { + super.setupAutoUpdates() + + // Remove super & implement variant logic here + } + + override fun finishOnboarding() { + super.finishOnboarding() + + // Remove super & implement variant logic here + } +} diff --git a/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt new file mode 100644 index 000000000..1ed8acc72 --- /dev/null +++ b/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -0,0 +1,75 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.splash + +import android.accounts.AccountManager +import android.util.Log +import androidx.navigation.fragment.findNavController +import com.aurora.store.R +import com.aurora.store.data.model.AuthState +import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class SplashFragment : BaseFlavouredSplashFragment() { + private val TAG = SplashFragment::class.java.simpleName + + override fun attachActions() { + binding.btnAnonymous.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnAnonymous.updateProgress(true) + viewModel.buildAnonymousAuthData() + } + } + + binding.btnGoogle.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnGoogle.updateProgress(true) + if (canLoginWithMicroG) { + Log.i(TAG, "Found supported microG, trying to request credentials") + val accountIntent = AccountManager.newChooseAccountIntent( + null, + null, + arrayOf(GOOGLE_ACCOUNT_TYPE), + null, + null, + null, + null + ) + startForAccount.launch(accountIntent) + } else { + findNavController().navigate(R.id.googleFragment) + } + } + } + } + + override fun resetActions() { + binding.btnGoogle.apply { + updateProgress(false) + isEnabled = true + } + + binding.btnAnonymous.apply { + updateProgress(false) + isEnabled = true + } + } +} From 196749333f2e7af7f4eaf8bc28685725bbeafe37 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 24 May 2025 01:51:42 +0530 Subject: [PATCH 02/11] Splash: do not force hide anonymous login --- .../aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt b/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt index f777bcf4d..97a9202e2 100644 --- a/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt @@ -102,9 +102,6 @@ abstract class BaseFlavouredSplashFragment : BaseFragment attachActions() - // Show anonymous logins if we have dispenser URL - binding.btnAnonymous.isVisible = false - viewLifecycleOwner.lifecycleScope.launch { viewModel.authState.collectLatest { when (it) { From ce119461f160e477e92339a86cff82c0a208dca2 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 24 May 2025 14:42:45 +0530 Subject: [PATCH 03/11] add new preload variant --- app/build.gradle.kts | 17 +++- app/lint.xml | 1 + app/src/huawei/AndroidManifest.xml | 7 ++ app/src/preload/AndroidManifest.xml | 7 ++ .../view/ui/onboarding/OnboardingFragment.kt | 84 +++++++++++++++++++ .../store/view/ui/splash/SplashFragment.kt | 75 +++++++++++++++++ 6 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 app/src/huawei/AndroidManifest.xml create mode 100644 app/src/preload/AndroidManifest.xml create mode 100644 app/src/preload/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt create mode 100644 app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 832585b49..710c2bc41 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -113,7 +113,7 @@ android { flavorDimensions += "device" productFlavors { - create("vanilla"){ + create("vanilla") { dimension = "device" } @@ -121,6 +121,12 @@ android { dimension = "device" versionNameSuffix = "-hw" } + + // This flavor is only for preloaded devices / users who push the app to system + create("preload") { + dimension = "device" + versionNameSuffix = "-preload" + } } buildFeatures { @@ -153,6 +159,15 @@ android { } } +androidComponents { + beforeVariants(selector().all()) { variant -> + val flavour = variant.flavorName + if ((flavour == "huawei" || flavour == "preload") && variant.buildType == "nightly") { + variant.enable = false + } + } +} + ksp { arg("room.schemaLocation", "$projectDir/schemas") } diff --git a/app/lint.xml b/app/lint.xml index 171a4f24a..b4a690a2b 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -1,6 +1,7 @@ + diff --git a/app/src/huawei/AndroidManifest.xml b/app/src/huawei/AndroidManifest.xml new file mode 100644 index 000000000..ea1a0693d --- /dev/null +++ b/app/src/huawei/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/preload/AndroidManifest.xml b/app/src/preload/AndroidManifest.xml new file mode 100644 index 000000000..ea1a0693d --- /dev/null +++ b/app/src/preload/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/preload/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt b/app/src/preload/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt new file mode 100644 index 000000000..cadc94c05 --- /dev/null +++ b/app/src/preload/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt @@ -0,0 +1,84 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.onboarding + +import androidx.fragment.app.Fragment +import com.aurora.Constants +import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE +import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB +import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS +import com.aurora.store.util.Preferences.PREFERENCE_FILTER_AURORA_ONLY +import com.aurora.store.util.Preferences.PREFERENCE_FILTER_FDROID +import com.aurora.store.util.Preferences.PREFERENCE_FOR_YOU +import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID +import com.aurora.store.util.Preferences.PREFERENCE_SIMILAR +import com.aurora.store.util.Preferences.PREFERENCE_THEME_STYLE +import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL +import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED +import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION +import com.aurora.store.util.save +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class OnboardingFragment : BaseFlavouredOnboardingFragment() { + + override fun loadDefaultPreferences() { + /*Filters*/ + save(PREFERENCE_FILTER_AURORA_ONLY, false) + save(PREFERENCE_FILTER_FDROID, true) + + /*Network*/ + save(PREFERENCE_DISPENSER_URLS, setOf(Constants.URL_DISPENSER)) + save(PREFERENCE_VENDING_VERSION, 0) + + /*Customization*/ + save(PREFERENCE_THEME_STYLE, 0) + save(PREFERENCE_DEFAULT_SELECTED_TAB, 0) + save(PREFERENCE_FOR_YOU, true) + save(PREFERENCE_SIMILAR, false) + + /*Installer*/ + save(PREFERENCE_AUTO_DELETE, true) + save(PREFERENCE_INSTALLER_ID, 0) + + /*Updates*/ + save(PREFERENCE_UPDATES_EXTENDED, false) + save(PREFERENCE_UPDATES_CHECK_INTERVAL, 3) + } + + override fun onboardingPages(): List { + return listOf( + WelcomeFragment(), + PermissionsFragment.newInstance() + ) + } + + override fun setupAutoUpdates() { + super.setupAutoUpdates() + + // Remove super & implement variant logic here + } + + override fun finishOnboarding() { + super.finishOnboarding() + + // Remove super & implement variant logic here + } +} diff --git a/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt new file mode 100644 index 000000000..1ed8acc72 --- /dev/null +++ b/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -0,0 +1,75 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.splash + +import android.accounts.AccountManager +import android.util.Log +import androidx.navigation.fragment.findNavController +import com.aurora.store.R +import com.aurora.store.data.model.AuthState +import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class SplashFragment : BaseFlavouredSplashFragment() { + private val TAG = SplashFragment::class.java.simpleName + + override fun attachActions() { + binding.btnAnonymous.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnAnonymous.updateProgress(true) + viewModel.buildAnonymousAuthData() + } + } + + binding.btnGoogle.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnGoogle.updateProgress(true) + if (canLoginWithMicroG) { + Log.i(TAG, "Found supported microG, trying to request credentials") + val accountIntent = AccountManager.newChooseAccountIntent( + null, + null, + arrayOf(GOOGLE_ACCOUNT_TYPE), + null, + null, + null, + null + ) + startForAccount.launch(accountIntent) + } else { + findNavController().navigate(R.id.googleFragment) + } + } + } + } + + override fun resetActions() { + binding.btnGoogle.apply { + updateProgress(false) + isEnabled = true + } + + binding.btnAnonymous.apply { + updateProgress(false) + isEnabled = true + } + } +} From 8ddad653f90ad798f19b99c460a56f07c87700be Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 24 May 2025 15:15:57 +0530 Subject: [PATCH 04/11] cleanup splash fragment duplicacy --- .../store/view/ui/splash/SplashFragment.kt | 39 +--------- .../ui/splash/BaseFlavouredSplashFragment.kt | 77 +++++++++++-------- .../store/view/ui/splash/SplashFragment.kt | 52 +------------ .../store/view/ui/splash/SplashFragment.kt | 52 +------------ 4 files changed, 49 insertions(+), 171 deletions(-) diff --git a/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt index 7eae959cc..2b5f789be 100644 --- a/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -19,51 +19,20 @@ package com.aurora.store.view.ui.splash -import android.accounts.AccountManager -import android.util.Log -import androidx.navigation.fragment.findNavController import com.aurora.extensions.hide -import com.aurora.store.R -import com.aurora.store.data.model.AuthState -import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class SplashFragment : BaseFlavouredSplashFragment() { - - private val TAG = SplashFragment::class.java.simpleName - override fun attachActions() { - binding.btnAnonymous.hide() + super.attachActions() - binding.btnGoogle.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnGoogle.updateProgress(true) - if (canLoginWithMicroG) { - Log.i(TAG, "Found supported microG, trying to request credentials") - val accountIntent = AccountManager.newChooseAccountIntent( - null, - null, - arrayOf(GOOGLE_ACCOUNT_TYPE), - null, - null, - null, - null - ) - startForAccount.launch(accountIntent) - } else { - findNavController().navigate(R.id.googleFragment) - } - } - } + binding.btnAnonymous.hide() } override fun resetActions() { - binding.btnAnonymous.hide() + super.resetActions() - binding.btnGoogle.apply { - updateProgress(false) - isEnabled = true - } + binding.btnAnonymous.hide() } } diff --git a/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt b/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt index 97a9202e2..a8adb7ad0 100644 --- a/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/splash/BaseFlavouredSplashFragment.kt @@ -17,7 +17,6 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.aurora.extensions.getPackageName -import com.aurora.extensions.hide import com.aurora.extensions.isMAndAbove import com.aurora.extensions.navigate import com.aurora.gplayapi.helpers.AuthHelper @@ -41,7 +40,7 @@ import kotlinx.coroutines.launch abstract class BaseFlavouredSplashFragment : BaseFragment() { - private val TAG = SplashFragment::class.java.simpleName + private val TAG = BaseFlavouredSplashFragment::class.java.simpleName val viewModel: AuthViewModel by activityViewModels() @@ -183,38 +182,6 @@ abstract class BaseFlavouredSplashFragment : BaseFragment binding.toolbar.isVisible = isVisible } - open fun attachActions() { - binding.btnAnonymous.hide() - - binding.btnGoogle.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnGoogle.updateProgress(true) - if (canLoginWithMicroG) { - Log.i(TAG, "Found supported microG, trying to request credentials") - val accountIntent = AccountManager.newChooseAccountIntent( - null, - null, - arrayOf(GOOGLE_ACCOUNT_TYPE), - null, - null, - null, - null - ) - startForAccount.launch(accountIntent) - } else { - findNavController().navigate(R.id.googleFragment) - } - } - } - } - - open fun resetActions() { - binding.btnGoogle.apply { - updateProgress(false) - isEnabled = true - } - } - private fun navigateToDefaultTab() { val defaultDestination = Preferences.getInteger(requireContext(), PREFERENCE_DEFAULT_SELECTED_TAB) @@ -265,4 +232,46 @@ abstract class BaseFlavouredSplashFragment : BaseFragment Log.e(TAG, "Failed to get authToken for Google login") } } + + open fun attachActions() { + binding.btnAnonymous.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnAnonymous.updateProgress(true) + viewModel.buildAnonymousAuthData() + } + } + + binding.btnGoogle.addOnClickListener { + if (viewModel.authState.value != AuthState.Fetching) { + binding.btnGoogle.updateProgress(true) + if (canLoginWithMicroG) { + Log.i(TAG, "Found supported microG, trying to request credentials") + val accountIntent = AccountManager.newChooseAccountIntent( + null, + null, + arrayOf(GOOGLE_ACCOUNT_TYPE), + null, + null, + null, + null + ) + startForAccount.launch(accountIntent) + } else { + findNavController().navigate(R.id.googleFragment) + } + } + } + } + + open fun resetActions() { + binding.btnGoogle.apply { + updateProgress(false) + isEnabled = true + } + + binding.btnAnonymous.apply { + updateProgress(false) + isEnabled = true + } + } } diff --git a/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt index 1ed8acc72..d965d10e4 100644 --- a/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -19,57 +19,7 @@ package com.aurora.store.view.ui.splash -import android.accounts.AccountManager -import android.util.Log -import androidx.navigation.fragment.findNavController -import com.aurora.store.R -import com.aurora.store.data.model.AuthState -import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class SplashFragment : BaseFlavouredSplashFragment() { - private val TAG = SplashFragment::class.java.simpleName - - override fun attachActions() { - binding.btnAnonymous.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnAnonymous.updateProgress(true) - viewModel.buildAnonymousAuthData() - } - } - - binding.btnGoogle.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnGoogle.updateProgress(true) - if (canLoginWithMicroG) { - Log.i(TAG, "Found supported microG, trying to request credentials") - val accountIntent = AccountManager.newChooseAccountIntent( - null, - null, - arrayOf(GOOGLE_ACCOUNT_TYPE), - null, - null, - null, - null - ) - startForAccount.launch(accountIntent) - } else { - findNavController().navigate(R.id.googleFragment) - } - } - } - } - - override fun resetActions() { - binding.btnGoogle.apply { - updateProgress(false) - isEnabled = true - } - - binding.btnAnonymous.apply { - updateProgress(false) - isEnabled = true - } - } -} +class SplashFragment : BaseFlavouredSplashFragment() diff --git a/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt index 1ed8acc72..d965d10e4 100644 --- a/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt @@ -19,57 +19,7 @@ package com.aurora.store.view.ui.splash -import android.accounts.AccountManager -import android.util.Log -import androidx.navigation.fragment.findNavController -import com.aurora.store.R -import com.aurora.store.data.model.AuthState -import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class SplashFragment : BaseFlavouredSplashFragment() { - private val TAG = SplashFragment::class.java.simpleName - - override fun attachActions() { - binding.btnAnonymous.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnAnonymous.updateProgress(true) - viewModel.buildAnonymousAuthData() - } - } - - binding.btnGoogle.addOnClickListener { - if (viewModel.authState.value != AuthState.Fetching) { - binding.btnGoogle.updateProgress(true) - if (canLoginWithMicroG) { - Log.i(TAG, "Found supported microG, trying to request credentials") - val accountIntent = AccountManager.newChooseAccountIntent( - null, - null, - arrayOf(GOOGLE_ACCOUNT_TYPE), - null, - null, - null, - null - ) - startForAccount.launch(accountIntent) - } else { - findNavController().navigate(R.id.googleFragment) - } - } - } - } - - override fun resetActions() { - binding.btnGoogle.apply { - updateProgress(false) - isEnabled = true - } - - binding.btnAnonymous.apply { - updateProgress(false) - isEnabled = true - } - } -} +class SplashFragment : BaseFlavouredSplashFragment() From 149c26035d017c492a9800cad875855cbffb15c2 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 24 May 2025 15:39:08 +0530 Subject: [PATCH 05/11] update .gitignore --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6452a1e7a..1687bfbd8 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,10 @@ gradle-app.setting *.zip app/release/* -app/beta/* -app/alpha/* app/nightly/* +app/vanilla/* +app/huawei/* +app/preload/* #Exclude signing configurations & keystore From a352229b868420b616cc23caba197a47397c0257 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 24 May 2025 15:48:07 +0530 Subject: [PATCH 06/11] TopCharts: Do not overwrite entire map --- .../com/aurora/store/viewmodel/topchart/TopChartViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt index 4fc52da0d..2f0afecb0 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/topchart/TopChartViewModel.kt @@ -91,7 +91,7 @@ class TopChartViewModel @Inject constructor( clusterAppList = streamCluster.clusterAppList + newCluster.clusterAppList ) - stash[type] = mutableMapOf(chart to mergedCluster) + stash[type]?.set(chart, mergedCluster) } private fun targetCluster( From 31ffa2e3d9e55e1392a4afaa5b89c65abc7de763 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Sat, 24 May 2025 19:03:51 +0530 Subject: [PATCH 07/11] Fix app stream & cluster state issues --- .../view/ui/commons/StreamBrowseFragment.kt | 4 +- .../viewmodel/browse/StreamBrowseViewModel.kt | 29 +++---- .../details/DetailsClusterViewModel.kt | 6 +- .../viewmodel/details/DevProfileViewModel.kt | 6 +- .../viewmodel/homestream/StreamViewModel.kt | 86 ++++++++++--------- .../store/viewmodel/review/ReviewViewModel.kt | 35 ++++---- .../subcategory/CategoryStreamViewModel.kt | 6 +- 7 files changed, 86 insertions(+), 86 deletions(-) diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseFragment.kt index 2c0f0c8f6..816add47f 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseFragment.kt @@ -58,9 +58,9 @@ class StreamBrowseFragment : BaseFragment() { } }) - viewModel.initCluster(streamCluster) + viewModel.seedCluster(streamCluster) viewModel.liveData.observe(viewLifecycleOwner) { - updateController(streamCluster) + updateController(it) } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt index 2915d638a..a832b3292 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt @@ -28,7 +28,6 @@ import com.aurora.gplayapi.helpers.web.WebStreamHelper import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope import javax.inject.Inject @HiltViewModel @@ -42,31 +41,27 @@ class StreamBrowseViewModel @Inject constructor( private lateinit var streamCluster: StreamCluster - fun initCluster(cluster: StreamCluster) { + fun seedCluster(cluster: StreamCluster) { streamCluster = cluster liveData.postValue(streamCluster) } fun nextCluster() { viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - try { - if (streamCluster.hasNext()) { - val nextCluster = streamHelper.nextStreamCluster( - streamCluster.clusterNextPageUrl - ) + try { + if (streamCluster.hasNext()) { + val next = streamHelper.nextStreamCluster(streamCluster.clusterNextPageUrl) - streamCluster = streamCluster.copy( - clusterNextPageUrl = nextCluster.clusterNextPageUrl, - clusterAppList = streamCluster.clusterAppList + nextCluster.clusterAppList - ) + streamCluster = streamCluster.copy( + clusterNextPageUrl = next.clusterNextPageUrl, + clusterAppList = streamCluster.clusterAppList + next.clusterAppList + ) - liveData.postValue(streamCluster) - } else { - Log.i(TAG, "End of Cluster") - } - } catch (_: Exception) { + liveData.postValue(streamCluster) + } else { + Log.i(TAG, "End of Cluster") } + } catch (_: Exception) { } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt index a069e1aab..d2a14e28d 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/details/DetailsClusterViewModel.kt @@ -107,9 +107,9 @@ class DetailsClusterViewModel @Inject constructor( clusterNextPageUrl = newCluster.clusterNextPageUrl, clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList ) - val newStreamClusters = bundle.streamClusters.toMutableMap().also { - it.remove(clusterID) - it[clusterID] = mergedCluster + + val newStreamClusters = bundle.streamClusters.toMutableMap().apply { + this[clusterID] = mergedCluster } stash.put(url, bundle.copy(streamClusters = newStreamClusters)) diff --git a/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt index 28da92cea..2825fb8c7 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/details/DevProfileViewModel.kt @@ -90,9 +90,9 @@ class DevProfileViewModel @Inject constructor( clusterNextPageUrl = newCluster.clusterNextPageUrl, clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList ) - val newStreamClusters = streamBundle.streamClusters.toMutableMap().also { - it.remove(newCluster.id) - it[newCluster.id] = mergedCluster + + val newStreamClusters = streamBundle.streamClusters.toMutableMap().apply { + this[newCluster.id] = mergedCluster } streamBundle = streamBundle.copy(streamClusters = newStreamClusters) diff --git a/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt index 4e28d0676..7ea8bbf9b 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt @@ -32,7 +32,8 @@ import com.aurora.store.data.model.ViewState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @HiltViewModel @@ -44,11 +45,14 @@ class StreamViewModel @Inject constructor( val liveData: MutableLiveData = MutableLiveData() - private var stash: HomeStash = mutableMapOf() + private val stash: HomeStash = mutableMapOf() private val streamContract: StreamContract get() = webStreamHelper + // Mutex to protect stash access for thread safety + private val stashMutex = Mutex() + fun getStreamBundle(category: StreamContract.Category, type: StreamContract.Type) { liveData.postValue(ViewState.Loading) observe(category, type) @@ -56,16 +60,18 @@ class StreamViewModel @Inject constructor( fun observe(category: StreamContract.Category, type: StreamContract.Type) { viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - val bundle = targetBundle(category) - if (bundle.hasCluster()) { - liveData.postValue(ViewState.Success(stash)) - } + try { + stashMutex.withLock { + val bundle = targetBundle(category) + + // Post existing data if any clusters exist + if (bundle.hasCluster()) { + liveData.postValue(ViewState.Success(stash.toMap())) + } - try { if (!bundle.hasCluster() || bundle.hasNext()) { - //Fetch new stream bundle + // Fetch new stream bundle val newBundle = if (bundle.hasCluster()) { streamContract.nextStreamBundle( category, @@ -75,41 +81,43 @@ class StreamViewModel @Inject constructor( streamContract.fetch(type, category) } - //Update old bundle + // Update old bundle val mergedBundle = bundle.copy( streamClusters = bundle.streamClusters + newBundle.streamClusters, streamNextPageUrl = newBundle.streamNextPageUrl ) stash[category] = mergedBundle - //Post updated to UI - liveData.postValue(ViewState.Success(stash)) + // Post updated to UI + liveData.postValue(ViewState.Success(stash.toMap())) } else { Log.i(TAG, "End of Bundle") } - } catch (e: Exception) { - liveData.postValue(ViewState.Error(e.message)) } + } catch (e: Exception) { + liveData.postValue(ViewState.Error(e.message)) } } } fun observeCluster(category: StreamContract.Category, streamCluster: StreamCluster) { viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - try { - if (streamCluster.hasNext()) { - val newCluster = streamContract.nextStreamCluster( - streamCluster.clusterNextPageUrl - ) + try { + if (streamCluster.hasNext()) { + val newCluster = streamContract.nextStreamCluster( + streamCluster.clusterNextPageUrl + ) + + stashMutex.withLock { updateCluster(category, streamCluster.id, newCluster) - liveData.postValue(ViewState.Success(stash)) - } else { - Log.i(TAG, "End of cluster") } - } catch (e: Exception) { - liveData.postValue(ViewState.Error(e.message)) + + liveData.postValue(ViewState.Success(stash.toMap())) + } else { + Log.i(TAG, "End of cluster ${streamCluster.id}") } + } catch (e: Exception) { + liveData.postValue(ViewState.Error(e.message)) } } } @@ -119,26 +127,22 @@ class StreamViewModel @Inject constructor( clusterID: Int, newCluster: StreamCluster ) { - val bundle = targetBundle(category) - bundle.streamClusters[clusterID]?.let { oldCluster -> - val mergedCluster = oldCluster.copy( - clusterNextPageUrl = newCluster.clusterNextPageUrl, - clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList - ) - val newStreamClusters = bundle.streamClusters.toMutableMap().also { - it.remove(clusterID) - it[clusterID] = mergedCluster - } + val bundle = stash[category] ?: return + val oldCluster = bundle.streamClusters[clusterID] ?: return - stash.put(category, bundle.copy(streamClusters = newStreamClusters)) + val mergedCluster = oldCluster.copy( + clusterNextPageUrl = newCluster.clusterNextPageUrl, + clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList + ) + + val updatedClusters = bundle.streamClusters.toMutableMap().apply { + this[clusterID] = mergedCluster } + + stash[category] = bundle.copy(streamClusters = updatedClusters) } private fun targetBundle(category: StreamContract.Category): StreamBundle { - val streamBundle = stash.getOrPut(category) { - StreamBundle() - } - - return streamBundle + return stash.getOrPut(category) { StreamBundle() } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt index 9cc4a7d5c..140f4a402 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/review/ReviewViewModel.kt @@ -19,6 +19,7 @@ package com.aurora.store.viewmodel.review +import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -28,13 +29,13 @@ import com.aurora.gplayapi.helpers.ReviewsHelper import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope import javax.inject.Inject @HiltViewModel class ReviewViewModel @Inject constructor( private val reviewsHelper: ReviewsHelper ) : ViewModel() { + val TAG = javaClass.simpleName val liveData: MutableLiveData = MutableLiveData() @@ -42,29 +43,29 @@ class ReviewViewModel @Inject constructor( fun fetchReview(packageName: String, filter: Review.Filter) { viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - try { - reviewsCluster = reviewsHelper.getReviews(packageName, filter) - liveData.postValue(reviewsCluster) - } catch (_: Exception) { - } + try { + reviewsCluster = reviewsHelper.getReviews(packageName, filter) + liveData.postValue(reviewsCluster) + } catch (e: Exception) { + Log.e(TAG, "Failed to fetch reviews", e) } } } fun next(nextReviewPageUrl: String) { viewModelScope.launch(Dispatchers.IO) { - supervisorScope { - try { - val nextReviewCluster = reviewsHelper.next(nextReviewPageUrl) - reviewsCluster = reviewsCluster.copy( - nextPageUrl = nextReviewCluster.nextPageUrl, - reviewList = nextReviewCluster.reviewList + nextReviewCluster.reviewList - ) + try { + val currentCluster = reviewsCluster + val nextReviewCluster = reviewsHelper.next(nextReviewPageUrl) - liveData.postValue(reviewsCluster) - } catch (_: Exception) { - } + reviewsCluster = currentCluster.copy( + nextPageUrl = nextReviewCluster.nextPageUrl, + reviewList = currentCluster.reviewList + nextReviewCluster.reviewList + ) + + liveData.postValue(reviewsCluster) + } catch (e: Exception) { + Log.e(TAG, "Failed to fetch next reviews $nextReviewPageUrl", e) } } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/subcategory/CategoryStreamViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/subcategory/CategoryStreamViewModel.kt index cc1af5ca9..4c80088c4 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/subcategory/CategoryStreamViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/subcategory/CategoryStreamViewModel.kt @@ -121,9 +121,9 @@ class CategoryStreamViewModel @Inject constructor( clusterNextPageUrl = newCluster.clusterNextPageUrl, clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList ) - val newStreamClusters = bundle.streamClusters.toMutableMap().also { - it.remove(clusterID) - it[clusterID] = mergedCluster + + val newStreamClusters = bundle.streamClusters.toMutableMap().apply { + this[clusterID] = mergedCluster } stash.put(browseUrl, bundle.copy(streamClusters = newStreamClusters)) From a505f6f644cf00c90638023f955d99ad526e85e4 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Tue, 27 May 2025 17:47:43 +0530 Subject: [PATCH 08/11] gplayapi:3.5.3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 968be725a..5c0b88328 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ composeBom = "2025.05.01" core = "1.16.0" epoxy = "5.1.4" espresso = "3.6.1" -gplayapi = "3.5.2" +gplayapi = "3.5.3" hiddenapibypass = "6.1" hilt = "2.56.2" hiltWork = "1.2.0" From d91d988e0e73debbb3199b45e314334030cd1a34 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Tue, 27 May 2025 18:06:29 +0530 Subject: [PATCH 09/11] Fix infinite cluster load animation --- .../viewmodel/browse/StreamBrowseViewModel.kt | 8 ++++++++ .../viewmodel/homestream/StreamViewModel.kt | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt index a832b3292..a5237728e 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt @@ -60,9 +60,17 @@ class StreamBrowseViewModel @Inject constructor( liveData.postValue(streamCluster) } else { Log.i(TAG, "End of Cluster") + postClusterEnd() } } catch (_: Exception) { } } } + + fun postClusterEnd() { + streamCluster = streamCluster.copy( + clusterNextPageUrl = "" + ) + liveData.postValue(streamCluster) + } } diff --git a/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt index 7ea8bbf9b..64201ea9e 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/homestream/StreamViewModel.kt @@ -114,7 +114,11 @@ class StreamViewModel @Inject constructor( liveData.postValue(ViewState.Success(stash.toMap())) } else { - Log.i(TAG, "End of cluster ${streamCluster.id}") + stashMutex.withLock { + postClusterEnd(category, streamCluster.id) + } + + liveData.postValue(ViewState.Success(stash.toMap())) } } catch (e: Exception) { liveData.postValue(ViewState.Error(e.message)) @@ -142,6 +146,18 @@ class StreamViewModel @Inject constructor( stash[category] = bundle.copy(streamClusters = updatedClusters) } + private fun postClusterEnd(category: StreamContract.Category, clusterID: Int) { + val bundle = stash[category] ?: return + val oldCluster = bundle.streamClusters[clusterID] ?: return + + val updatedCluster = oldCluster.copy(clusterNextPageUrl = "") + val updatedClusters = bundle.streamClusters.toMutableMap().apply { + this[clusterID] = updatedCluster + } + + stash[category] = bundle.copy(streamClusters = updatedClusters) + } + private fun targetBundle(category: StreamContract.Category): StreamBundle { return stash.getOrPut(category) { StreamBundle() } } From 0d05c7ad08cbbb29c043e91804c022b8afd9a481 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Tue, 27 May 2025 18:18:15 +0530 Subject: [PATCH 10/11] fix locale serialization issue --- .../data/serializers/LocaleSerializer.kt | 56 ------------------- .../data/serializers/PropertiesSerializer.kt | 32 ----------- .../com/aurora/store/module/CommonModule.kt | 4 +- 3 files changed, 2 insertions(+), 90 deletions(-) delete mode 100644 app/src/main/java/com/aurora/store/data/serializers/LocaleSerializer.kt delete mode 100644 app/src/main/java/com/aurora/store/data/serializers/PropertiesSerializer.kt diff --git a/app/src/main/java/com/aurora/store/data/serializers/LocaleSerializer.kt b/app/src/main/java/com/aurora/store/data/serializers/LocaleSerializer.kt deleted file mode 100644 index e05f7c1bf..000000000 --- a/app/src/main/java/com/aurora/store/data/serializers/LocaleSerializer.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.data.serializers - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.descriptors.element -import kotlinx.serialization.encoding.CompositeDecoder -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.encoding.decodeStructure -import kotlinx.serialization.encoding.encodeStructure -import java.util.Locale - -/** - * Serializer for [Locale] for working with Kotlin's Serialization library - */ -object LocaleSerializer : KSerializer { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Locale") { - element("language") - element("region") - } - - override fun serialize(encoder: Encoder, value: Locale) { - return encoder.encodeStructure(descriptor) { - encodeStringElement(descriptor, 0, value.language) - encodeStringElement(descriptor, 1, value.country) - } - } - - override fun deserialize(decoder: Decoder): Locale { - return decoder.decodeStructure(descriptor) { - var language: String? = null - var region: String? = null - - while (true) { - when (val index = decodeElementIndex(descriptor)) { - 0 -> language = decodeStringElement(descriptor, 0) - 1 -> region = decodeStringElement(descriptor, 1) - CompositeDecoder.DECODE_DONE -> break - else -> error("Unexpected index: $index") - } - } - - require(!language.isNullOrBlank() && !region.isNullOrBlank()) - Locale.Builder() - .setLanguage(language) - .setRegion(region) - .build() - } - } -} diff --git a/app/src/main/java/com/aurora/store/data/serializers/PropertiesSerializer.kt b/app/src/main/java/com/aurora/store/data/serializers/PropertiesSerializer.kt deleted file mode 100644 index c92906e2c..000000000 --- a/app/src/main/java/com/aurora/store/data/serializers/PropertiesSerializer.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.data.serializers - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import java.util.Properties - -/** - * Serializer for [Properties] for working with Kotlin's Serialization library - */ -object PropertiesSerializer : KSerializer { - override val descriptor: SerialDescriptor = - MapSerializer(String.serializer(), String.serializer()).descriptor - - override fun serialize(encoder: Encoder, value: Properties) { - val map = value.stringPropertyNames().associateWith { value.getProperty(it) } - MapSerializer(String.serializer(), String.serializer()).serialize(encoder, map) - } - - override fun deserialize(decoder: Decoder): Properties { - val map = MapSerializer(String.serializer(), String.serializer()).deserialize(decoder) - return Properties().apply { putAll(map) } - } -} diff --git a/app/src/main/java/com/aurora/store/module/CommonModule.kt b/app/src/main/java/com/aurora/store/module/CommonModule.kt index 34730000c..ede459367 100644 --- a/app/src/main/java/com/aurora/store/module/CommonModule.kt +++ b/app/src/main/java/com/aurora/store/module/CommonModule.kt @@ -1,7 +1,7 @@ package com.aurora.store.module -import com.aurora.store.data.serializers.LocaleSerializer -import com.aurora.store.data.serializers.PropertiesSerializer +import com.aurora.gplayapi.data.serializers.LocaleSerializer +import com.aurora.gplayapi.data.serializers.PropertiesSerializer import dagger.Module import dagger.Provides import dagger.hilt.InstallIn From e88e4a29a9b3381128607be67cbde15347362963 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Wed, 28 May 2025 12:08:19 +0530 Subject: [PATCH 11/11] remove hard coded strings TODO: Do not use regex on gplapi to extract mi android version, use actual string instead. --- .../view/epoxy/views/details/InfoView.kt | 21 +++++++++---------- .../view/ui/details/DetailsMoreFragment.kt | 2 +- app/src/main/res/values/strings.xml | 4 ++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt index 13fa11e2d..71ba132e0 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt @@ -21,13 +21,14 @@ package com.aurora.store.view.epoxy.views.details import android.content.Context import android.util.AttributeSet +import androidx.core.content.ContextCompat import com.airbnb.epoxy.ModelProp import com.airbnb.epoxy.ModelView import com.airbnb.epoxy.OnViewRecycled +import com.aurora.store.R import com.aurora.store.databinding.ViewInfoBinding import com.aurora.store.view.epoxy.views.BaseModel import com.aurora.store.view.epoxy.views.BaseView -import java.util.Locale @ModelView( autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, @@ -41,16 +42,14 @@ class InfoView @JvmOverloads constructor( @ModelProp(options = [ModelProp.Option.IgnoreRequireHashCode]) fun badge(info: Map.Entry) { - binding.txtTitle.text = info.key - .replace("_", " ") - .lowercase(Locale.getDefault()) - .replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase(Locale.getDefault()) - } else { - it.toString() - } - } + binding.txtTitle.text = when (info.key) { + "DOWNLOAD" -> ContextCompat.getString(context, R.string.app_info_downloads) + "UPDATED_ON" -> ContextCompat.getString(context, R.string.app_info_updated_on) + "REQUIRES" -> ContextCompat.getString(context, R.string.app_info_min_android) + "TARGET" -> ContextCompat.getString(context, R.string.app_info_target_android) + else -> info.key + } + binding.txtSubtitle.text = info.value } diff --git a/app/src/main/java/com/aurora/store/view/ui/details/DetailsMoreFragment.kt b/app/src/main/java/com/aurora/store/view/ui/details/DetailsMoreFragment.kt index b59d350e6..0651214c7 100644 --- a/app/src/main/java/com/aurora/store/view/ui/details/DetailsMoreFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/details/DetailsMoreFragment.kt @@ -164,7 +164,7 @@ class DetailsMoreFragment : BaseFragment() { add( InfoViewModel_() .id(UUID.randomUUID().toString()) - .badge(mapOf("targets" to "API ${app.targetSdk}").entries.first()) + .badge(mapOf("TARGET" to "${app.targetSdk}").entries.first()) ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f0a7e1d6d..54747d80b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -357,6 +357,10 @@ Android Market was an online store offering software applications designed for Android devices, retired in 2017. Failed to export APKs No apps available + "Downloads" + "Last updated" + "Minimum Android Version" + "Target API Level" Session based installer for bundled/split APKs