legacy: remove fragment-based screens and sheets
Drops every Fragment, DialogFragment and BottomSheet in view/ui plus the flavoured SplashFragment variants. All call sites now route through compose/ui equivalents and ComposeActivity.
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.splash
|
|
||||||
|
|
||||||
import com.aurora.extensions.hide
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class SplashFragment : BaseFlavouredSplashFragment() {
|
|
||||||
override fun attachActions() {
|
|
||||||
super.attachActions()
|
|
||||||
|
|
||||||
binding.btnAnonymous.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun resetActions() {
|
|
||||||
super.resetActions()
|
|
||||||
|
|
||||||
binding.btnAnonymous.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.account
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.webkit.CookieManager
|
|
||||||
import android.webkit.WebChromeClient
|
|
||||||
import android.webkit.WebSettings
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import com.aurora.gplayapi.helpers.AuthHelper
|
|
||||||
import com.aurora.store.AuroraApp
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.data.event.AuthEvent
|
|
||||||
import com.aurora.store.databinding.FragmentGoogleBinding
|
|
||||||
import com.aurora.store.util.AC2DMUtil
|
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
|
||||||
import com.aurora.store.viewmodel.auth.AuthViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class GoogleFragment : BaseFragment<FragmentGoogleBinding>() {
|
|
||||||
|
|
||||||
private val viewModel: AuthViewModel by activityViewModels()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val EMBEDDED_SETUP_URL = "https://accounts.google.com/EmbeddedSetup"
|
|
||||||
const val AUTH_TOKEN = "oauth_token"
|
|
||||||
private const val JS_SCRIPT =
|
|
||||||
"(function() { return document.getElementById('profileIdentifier').innerHTML; })();"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
val cookieManager = CookieManager.getInstance()
|
|
||||||
|
|
||||||
binding.webview.apply {
|
|
||||||
cookieManager.removeAllCookies(null)
|
|
||||||
cookieManager.acceptThirdPartyCookies(this)
|
|
||||||
cookieManager.setAcceptThirdPartyCookies(this, true)
|
|
||||||
|
|
||||||
webChromeClient = object : WebChromeClient() {
|
|
||||||
override fun onProgressChanged(view: WebView?, newProgress: Int) {
|
|
||||||
super.onProgressChanged(view, newProgress)
|
|
||||||
|
|
||||||
if (newProgress != 0) {
|
|
||||||
binding.progressBar.also {
|
|
||||||
it.isVisible = newProgress < 100
|
|
||||||
it.isIndeterminate = false
|
|
||||||
it.max = 100
|
|
||||||
it.progress = newProgress
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.progressBar.isIndeterminate = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageFinished(view: WebView, url: String) {
|
|
||||||
val cookies = CookieManager.getInstance().getCookie(url)
|
|
||||||
// cookies can be null if there is an error
|
|
||||||
if (cookies != null) {
|
|
||||||
val cookieMap = AC2DMUtil.parseCookieString(cookies)
|
|
||||||
if (cookieMap.isNotEmpty() && cookieMap[AUTH_TOKEN] != null) {
|
|
||||||
val oauthToken = cookieMap[AUTH_TOKEN]
|
|
||||||
evaluateJavascript(JS_SCRIPT) {
|
|
||||||
val email = it.replace("\"".toRegex(), "")
|
|
||||||
viewModel.buildAuthData(view.context, email, oauthToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.apply {
|
|
||||||
allowContentAccess = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
javaScriptEnabled = true
|
|
||||||
cacheMode = WebSettings.LOAD_DEFAULT
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) safeBrowsingEnabled = false
|
|
||||||
}
|
|
||||||
loadUrl(EMBEDDED_SETUP_URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
AuroraApp.events.authEvent.collect { event ->
|
|
||||||
if (event is AuthEvent.GoogleLogin) onEventReceived(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onEventReceived(event: AuthEvent.GoogleLogin) {
|
|
||||||
if (event.success) {
|
|
||||||
viewModel.buildGoogleAuthData(event.email, event.token, AuthHelper.Token.AAS)
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
requireContext(),
|
|
||||||
getString(R.string.toast_aas_token_failed),
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
findNavController().navigate(
|
|
||||||
GoogleFragmentDirections.actionGoogleFragmentToSplashFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.apps
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.store.MobileNavigationDirections
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.databinding.FragmentAppsGamesBinding
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
|
||||||
import com.aurora.store.view.ui.commons.CategoryFragment
|
|
||||||
import com.aurora.store.view.ui.commons.ForYouFragment
|
|
||||||
import com.aurora.store.view.ui.commons.TopChartContainerFragment
|
|
||||||
import com.aurora.store.viewmodel.apps.AppsContainerViewModel
|
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class AppsContainerFragment : BaseFragment<FragmentAppsGamesBinding>() {
|
|
||||||
|
|
||||||
private val viewModel: AppsContainerViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
// Adjust FAB margins for edgeToEdge display
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.searchFab) { _, windowInsets ->
|
|
||||||
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
|
||||||
binding.searchFab.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
|
||||||
bottomMargin = insets.bottom + resources.getDimensionPixelSize(R.dimen.margin_large)
|
|
||||||
}
|
|
||||||
WindowInsetsCompat.CONSUMED
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.apply {
|
|
||||||
title = getString(R.string.title_apps)
|
|
||||||
setOnMenuItemClickListener {
|
|
||||||
when (it.itemId) {
|
|
||||||
R.id.menu_download_manager -> {
|
|
||||||
requireContext().navigate(Screen.Downloads)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.menu_more -> {
|
|
||||||
findNavController().navigate(
|
|
||||||
MobileNavigationDirections.actionGlobalMoreDialogFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ViewPager
|
|
||||||
val isForYouEnabled = Preferences.getBoolean(
|
|
||||||
requireContext(),
|
|
||||||
Preferences.PREFERENCE_FOR_YOU
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.pager.adapter = ViewPagerAdapter(
|
|
||||||
childFragmentManager,
|
|
||||||
viewLifecycleOwner.lifecycle,
|
|
||||||
!viewModel.authProvider.isAnonymous,
|
|
||||||
isForYouEnabled
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.pager.isUserInputEnabled =
|
|
||||||
false // Disable viewpager scroll to avoid scroll conflicts
|
|
||||||
|
|
||||||
val tabTitles: MutableList<String> = mutableListOf<String>().apply {
|
|
||||||
if (isForYouEnabled) {
|
|
||||||
add(getString(R.string.tab_for_you))
|
|
||||||
}
|
|
||||||
|
|
||||||
add(getString(R.string.tab_top_charts))
|
|
||||||
add(getString(R.string.tab_categories))
|
|
||||||
}
|
|
||||||
|
|
||||||
TabLayoutMediator(
|
|
||||||
binding.tabLayout,
|
|
||||||
binding.pager,
|
|
||||||
true
|
|
||||||
) { tab: TabLayout.Tab, position: Int ->
|
|
||||||
tab.text = tabTitles[position]
|
|
||||||
}.attach()
|
|
||||||
|
|
||||||
binding.searchFab.setOnClickListener {
|
|
||||||
requireContext().navigate(Screen.Search)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
binding.pager.adapter = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ViewPagerAdapter(
|
|
||||||
fragment: FragmentManager,
|
|
||||||
lifecycle: Lifecycle,
|
|
||||||
private val isGoogleAccount: Boolean,
|
|
||||||
private val isForYouEnabled: Boolean
|
|
||||||
) :
|
|
||||||
FragmentStateAdapter(fragment, lifecycle) {
|
|
||||||
|
|
||||||
private val tabFragments: MutableList<Fragment> = mutableListOf<Fragment>().apply {
|
|
||||||
if (isForYouEnabled) {
|
|
||||||
add(ForYouFragment.newInstance(0))
|
|
||||||
}
|
|
||||||
add(TopChartContainerFragment.newInstance(0))
|
|
||||||
add(CategoryFragment.newInstance(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment = tabFragments[position]
|
|
||||||
|
|
||||||
override fun getItemCount(): Int = tabFragments.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.viewbinding.ViewBinding
|
|
||||||
import com.airbnb.epoxy.EpoxyRecyclerView
|
|
||||||
import com.aurora.extensions.TAG
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.gplayapi.data.models.Category
|
|
||||||
import com.aurora.gplayapi.data.models.StreamCluster
|
|
||||||
import com.aurora.store.MobileNavigationDirections
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.data.model.MinimalApp
|
|
||||||
import com.aurora.store.data.providers.PermissionProvider
|
|
||||||
import java.lang.reflect.ParameterizedType
|
|
||||||
|
|
||||||
abstract class BaseFragment<ViewBindingType : ViewBinding> : Fragment() {
|
|
||||||
|
|
||||||
lateinit var permissionProvider: PermissionProvider
|
|
||||||
|
|
||||||
protected open var viewBindingType: ViewBindingType? = null
|
|
||||||
protected val binding get() = viewBindingType!!
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
permissionProvider = PermissionProvider(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val type = (javaClass.genericSuperclass as ParameterizedType)
|
|
||||||
.actualTypeArguments[0] as Class<ViewBindingType>
|
|
||||||
val method = type.getMethod(
|
|
||||||
"inflate",
|
|
||||||
LayoutInflater::class.java,
|
|
||||||
ViewGroup::class.java,
|
|
||||||
Boolean::class.java
|
|
||||||
)
|
|
||||||
viewBindingType = method.invoke(null, inflater, container, false) as ViewBindingType
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
permissionProvider.unregister()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
cleanupRecyclerViews(findAllRecyclerViews(requireView()))
|
|
||||||
viewBindingType = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun openDetailsFragment(packageName: String) {
|
|
||||||
requireContext().navigate(
|
|
||||||
Screen.AppDetails(packageName)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun openCategoryBrowseFragment(category: Category) {
|
|
||||||
findNavController().navigate(
|
|
||||||
MobileNavigationDirections.actionGlobalCategoryBrowseFragment(
|
|
||||||
category.title,
|
|
||||||
category.browseUrl
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun openStreamBrowseFragment(browseUrl: String, title: String = "") {
|
|
||||||
if (browseUrl.lowercase().contains("expanded")) {
|
|
||||||
findNavController().navigate(
|
|
||||||
MobileNavigationDirections.actionGlobalExpandedStreamBrowseFragment(
|
|
||||||
title,
|
|
||||||
browseUrl
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else if (browseUrl.lowercase().contains("developer")) {
|
|
||||||
findNavController().navigate(
|
|
||||||
MobileNavigationDirections.actionGlobalDevProfileFragment(
|
|
||||||
browseUrl.substringAfter("developer-"),
|
|
||||||
title
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun openStreamBrowseFragment(streamCluster: StreamCluster) {
|
|
||||||
requireContext().navigate(Screen.StreamBrowse(streamCluster))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun openAppMenuSheet(app: MinimalApp) {
|
|
||||||
findNavController().navigate(MobileNavigationDirections.actionGlobalAppMenuSheet(app))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun openGMSWarningFragment() {
|
|
||||||
// TODO: FIX ME
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cleanupRecyclerViews(recyclerViews: List<EpoxyRecyclerView>) {
|
|
||||||
recyclerViews.forEach { recyclerView ->
|
|
||||||
runCatching {
|
|
||||||
recyclerView.adapter?.let {
|
|
||||||
recyclerView.swapAdapter(it, true)
|
|
||||||
}
|
|
||||||
}.onFailure {
|
|
||||||
Log.e(TAG, "Failed to cleanup RecyclerView", it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findAllRecyclerViews(view: View): List<EpoxyRecyclerView> {
|
|
||||||
val recyclerViews = mutableListOf<EpoxyRecyclerView>()
|
|
||||||
|
|
||||||
if (view is EpoxyRecyclerView) {
|
|
||||||
recyclerViews.add(view)
|
|
||||||
} else if (view is ViewGroup) {
|
|
||||||
for (i in 0 until view.childCount) {
|
|
||||||
recyclerViews.addAll(findAllRecyclerViews(view.getChildAt(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return recyclerViews
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.navigation.fragment.navArgs
|
|
||||||
import com.aurora.gplayapi.data.models.App
|
|
||||||
import com.aurora.gplayapi.data.models.StreamBundle
|
|
||||||
import com.aurora.gplayapi.data.models.StreamCluster
|
|
||||||
import com.aurora.store.data.model.ViewState
|
|
||||||
import com.aurora.store.data.model.ViewState.Loading.getDataAs
|
|
||||||
import com.aurora.store.databinding.FragmentGenericWithToolbarBinding
|
|
||||||
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
|
|
||||||
import com.aurora.store.view.epoxy.controller.CategoryCarouselController
|
|
||||||
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
|
||||||
import com.aurora.store.viewmodel.subcategory.CategoryStreamViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class CategoryBrowseFragment :
|
|
||||||
BaseFragment<FragmentGenericWithToolbarBinding>(),
|
|
||||||
GenericCarouselController.Callbacks {
|
|
||||||
private val args: CategoryBrowseFragmentArgs by navArgs()
|
|
||||||
private val viewModel: CategoryStreamViewModel by activityViewModels()
|
|
||||||
|
|
||||||
private var streamBundle: StreamBundle? = StreamBundle()
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
val genericCarouselController = CategoryCarouselController(this)
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.apply {
|
|
||||||
title = args.title
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecyclerView
|
|
||||||
binding.recycler.setController(genericCarouselController)
|
|
||||||
binding.recycler.addOnScrollListener(object : EndlessRecyclerOnScrollListener() {
|
|
||||||
override fun onLoadMore(currentPage: Int) {
|
|
||||||
viewModel.observe(args.browseUrl)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.getStreamBundle(args.browseUrl)
|
|
||||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
|
||||||
when (it) {
|
|
||||||
is ViewState.Loading -> {
|
|
||||||
genericCarouselController.setData(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Success<*> -> {
|
|
||||||
val stash = it.getDataAs<Map<String, StreamBundle>>()
|
|
||||||
streamBundle = stash[args.browseUrl]
|
|
||||||
|
|
||||||
genericCarouselController.setData(streamBundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHeaderClicked(streamCluster: StreamCluster) {
|
|
||||||
openStreamBrowseFragment(streamCluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClusterScrolled(streamCluster: StreamCluster) {
|
|
||||||
viewModel.observeCluster(args.browseUrl, streamCluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppClick(app: App) {
|
|
||||||
openDetailsFragment(app.packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppLongClick(app: App) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.gplayapi.data.models.Category
|
|
||||||
import com.aurora.store.CategoryStash
|
|
||||||
import com.aurora.store.data.model.ViewState
|
|
||||||
import com.aurora.store.data.model.ViewState.Empty.getDataAs
|
|
||||||
import com.aurora.store.databinding.FragmentGenericRecyclerBinding
|
|
||||||
import com.aurora.store.view.epoxy.views.CategoryViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
|
|
||||||
import com.aurora.store.viewmodel.category.CategoryViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class CategoryFragment : BaseFragment<FragmentGenericRecyclerBinding>() {
|
|
||||||
private val viewModel: CategoryViewModel by viewModels()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(pageType: Int): CategoryFragment = CategoryFragment().apply {
|
|
||||||
arguments = Bundle().apply {
|
|
||||||
putInt(Constants.PAGE_TYPE, pageType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
var pageType = 0
|
|
||||||
val bundle = arguments
|
|
||||||
if (bundle != null) {
|
|
||||||
pageType = bundle.getInt(Constants.PAGE_TYPE, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
when (pageType) {
|
|
||||||
0 -> viewModel.getCategoryList(Category.Type.APPLICATION)
|
|
||||||
1 -> viewModel.getCategoryList(Category.Type.GAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
val categoryType = when (pageType) {
|
|
||||||
1 -> Category.Type.GAME
|
|
||||||
else -> Category.Type.APPLICATION
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
|
||||||
when (it) {
|
|
||||||
is ViewState.Success<*> -> {
|
|
||||||
val stash = it.getDataAs<CategoryStash>()
|
|
||||||
updateController(stash[categoryType])
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
updateController(emptyList())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateController(categories: List<Category>?) {
|
|
||||||
binding.recycler.withModels {
|
|
||||||
if (categories == null) {
|
|
||||||
for (i in 1..10) {
|
|
||||||
add(
|
|
||||||
AppListViewShimmerModel_()
|
|
||||||
.id(i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setFilterDuplicates(true)
|
|
||||||
categories.forEach {
|
|
||||||
add(
|
|
||||||
CategoryViewModel_()
|
|
||||||
.id(it.title)
|
|
||||||
.category(it)
|
|
||||||
.click { _ -> openCategoryBrowseFragment(it) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.navigation.fragment.navArgs
|
|
||||||
import com.aurora.gplayapi.data.models.StreamCluster
|
|
||||||
import com.aurora.store.databinding.FragmentGenericWithToolbarBinding
|
|
||||||
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
|
|
||||||
import com.aurora.store.view.epoxy.views.AppProgressViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.app.AppListViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
|
|
||||||
import com.aurora.store.viewmodel.browse.ExpandedStreamBrowseViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class ExpandedStreamBrowseFragment : BaseFragment<FragmentGenericWithToolbarBinding>() {
|
|
||||||
private val args: ExpandedStreamBrowseFragmentArgs by navArgs()
|
|
||||||
private val viewModel: ExpandedStreamBrowseViewModel by viewModels()
|
|
||||||
|
|
||||||
private lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener
|
|
||||||
private lateinit var cluster: StreamCluster
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.apply {
|
|
||||||
title = args.title
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
|
||||||
if (!::cluster.isInitialized) attachRecycler()
|
|
||||||
cluster = it
|
|
||||||
|
|
||||||
updateController(cluster)
|
|
||||||
updateTitle(cluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.getInitialCluster(args.expandedStreamUrl)
|
|
||||||
updateController(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateTitle(streamCluster: StreamCluster) {
|
|
||||||
if (streamCluster.clusterTitle.isNotEmpty()) {
|
|
||||||
binding.toolbar.title = streamCluster.clusterTitle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun attachRecycler() {
|
|
||||||
endlessRecyclerOnScrollListener = object : EndlessRecyclerOnScrollListener() {
|
|
||||||
override fun onLoadMore(currentPage: Int) {
|
|
||||||
viewModel.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.recycler.addOnScrollListener(endlessRecyclerOnScrollListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateController(streamCluster: StreamCluster?) {
|
|
||||||
binding.recycler.withModels {
|
|
||||||
setFilterDuplicates(true)
|
|
||||||
if (streamCluster == null) {
|
|
||||||
for (i in 1..6) {
|
|
||||||
add(
|
|
||||||
AppListViewShimmerModel_()
|
|
||||||
.id(i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
streamCluster.clusterAppList.forEach {
|
|
||||||
add(
|
|
||||||
AppListViewModel_()
|
|
||||||
.id(it.packageName.hashCode())
|
|
||||||
.app(it)
|
|
||||||
.click { _ -> openDetailsFragment(it.packageName) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streamCluster.hasNext()) {
|
|
||||||
add(
|
|
||||||
AppProgressViewModel_()
|
|
||||||
.id("progress")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.gplayapi.data.models.App
|
|
||||||
import com.aurora.gplayapi.data.models.StreamBundle
|
|
||||||
import com.aurora.gplayapi.data.models.StreamCluster
|
|
||||||
import com.aurora.gplayapi.helpers.contracts.StreamContract.Category
|
|
||||||
import com.aurora.gplayapi.helpers.contracts.StreamContract.Type
|
|
||||||
import com.aurora.store.HomeStash
|
|
||||||
import com.aurora.store.data.model.ViewState
|
|
||||||
import com.aurora.store.data.model.ViewState.Loading.getDataAs
|
|
||||||
import com.aurora.store.databinding.FragmentForYouBinding
|
|
||||||
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
|
|
||||||
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
|
||||||
import com.aurora.store.viewmodel.homestream.StreamViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class ForYouFragment :
|
|
||||||
BaseFragment<FragmentForYouBinding>(),
|
|
||||||
GenericCarouselController.Callbacks {
|
|
||||||
private val viewModel: StreamViewModel by activityViewModels()
|
|
||||||
|
|
||||||
private var category: Category = Category.APPLICATION
|
|
||||||
private var streamBundle: StreamBundle? = StreamBundle()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(pageType: Int): ForYouFragment = ForYouFragment().apply {
|
|
||||||
arguments = Bundle().apply {
|
|
||||||
putInt(Constants.PAGE_TYPE, pageType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
val genericCarouselController = GenericCarouselController(this)
|
|
||||||
|
|
||||||
var pageType = 0
|
|
||||||
val bundle = arguments
|
|
||||||
if (bundle != null) {
|
|
||||||
pageType = bundle.getInt(Constants.PAGE_TYPE, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
category = if (pageType == 0) Category.APPLICATION else Category.GAME
|
|
||||||
|
|
||||||
binding.recycler.setController(genericCarouselController)
|
|
||||||
binding.recycler.addOnScrollListener(
|
|
||||||
object : EndlessRecyclerOnScrollListener(visibleThreshold = 4) {
|
|
||||||
override fun onLoadMore(currentPage: Int) {
|
|
||||||
viewModel.observe(category, Type.HOME)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
viewModel.getStreamBundle(category, Type.HOME)
|
|
||||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
|
||||||
when (it) {
|
|
||||||
is ViewState.Loading -> {
|
|
||||||
genericCarouselController.setData(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Success<*> -> {
|
|
||||||
val stash = it.getDataAs<HomeStash>()
|
|
||||||
streamBundle = stash[category]
|
|
||||||
|
|
||||||
genericCarouselController.setData(streamBundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHeaderClicked(streamCluster: StreamCluster) {
|
|
||||||
openStreamBrowseFragment(streamCluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClusterScrolled(streamCluster: StreamCluster) {
|
|
||||||
viewModel.observeCluster(category, streamCluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppClick(app: App) {
|
|
||||||
openDetailsFragment(app.packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppLongClick(app: App) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import com.jakewharton.processphoenix.ProcessPhoenix
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class ForceRestartDialog : DialogFragment() {
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
|
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
|
||||||
.setTitle(R.string.force_restart_title)
|
|
||||||
.setMessage(R.string.force_restart_summary)
|
|
||||||
.setPositiveButton(getString(R.string.action_restart)) { _, _ ->
|
|
||||||
ProcessPhoenix.triggerRebirth(requireContext())
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
dialog?.setCancelable(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,460 +0,0 @@
|
|||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.IdRes
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.requiredSize
|
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedButton
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
|
||||||
import androidx.compose.ui.platform.ComposeView
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.util.fastForEach
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import coil3.compose.AsyncImage
|
|
||||||
import coil3.request.ImageRequest
|
|
||||||
import coil3.request.crossfade
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.Constants.URL_TOS
|
|
||||||
import com.aurora.extensions.browse
|
|
||||||
import com.aurora.extensions.getStyledAttributeColor
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.extensions.setAppTheme
|
|
||||||
import com.aurora.store.MR
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.compose.theme.AuroraTheme
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.viewmodel.commons.MoreViewModel
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class MoreDialogFragment : DialogFragment() {
|
|
||||||
|
|
||||||
private val viewModel: MoreViewModel by viewModels()
|
|
||||||
|
|
||||||
private var primaryColor: Color = Color.White
|
|
||||||
private var onPrimaryColor: Color = Color.Black
|
|
||||||
private var secondaryColor: Color = Color.White
|
|
||||||
private var onSecondaryColor: Color = Color.Black
|
|
||||||
|
|
||||||
private abstract class Option(
|
|
||||||
@StringRes open val title: Int,
|
|
||||||
@DrawableRes open val icon: Int
|
|
||||||
)
|
|
||||||
|
|
||||||
private data class ViewOption(
|
|
||||||
override val title: Int,
|
|
||||||
override val icon: Int,
|
|
||||||
@IdRes val destinationID: Int
|
|
||||||
) : Option(title, icon)
|
|
||||||
|
|
||||||
private data class ComposeOption(
|
|
||||||
override val title: Int,
|
|
||||||
override val icon: Int,
|
|
||||||
val screen: Screen
|
|
||||||
) : Option(title, icon)
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
|
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
|
||||||
.setView(customDialogView(requireContext()))
|
|
||||||
.create()
|
|
||||||
|
|
||||||
private fun customDialogView(context: Context): ComposeView = ComposeView(context).apply {
|
|
||||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
|
||||||
setContent {
|
|
||||||
AuroraTheme {
|
|
||||||
primaryColor =
|
|
||||||
Color(requireContext().getStyledAttributeColor(MR.colorSurface))
|
|
||||||
onPrimaryColor =
|
|
||||||
Color(requireContext().getStyledAttributeColor(MR.colorOnSurface))
|
|
||||||
secondaryColor =
|
|
||||||
Color(requireContext().getStyledAttributeColor(MR.colorSecondaryContainer))
|
|
||||||
onSecondaryColor =
|
|
||||||
Color(
|
|
||||||
requireContext().getStyledAttributeColor(MR.colorOnSecondaryContainer)
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(color = primaryColor)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(10.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(
|
|
||||||
4.dp,
|
|
||||||
Alignment.CenterVertically
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
AppBar(onBackgroundColor = onPrimaryColor)
|
|
||||||
AccountHeader(
|
|
||||||
backgroundColor = secondaryColor,
|
|
||||||
onBackgroundColor = onSecondaryColor
|
|
||||||
)
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(
|
|
||||||
RoundedCornerShape(
|
|
||||||
topStart = 2.dp,
|
|
||||||
topEnd = 2.dp,
|
|
||||||
bottomStart = 25.dp,
|
|
||||||
bottomEnd = 25.dp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.background(color = secondaryColor)
|
|
||||||
) {
|
|
||||||
getOptions().fastForEach { option ->
|
|
||||||
OptionItem(
|
|
||||||
option = option,
|
|
||||||
tintColor = onPrimaryColor,
|
|
||||||
textColor = onSecondaryColor,
|
|
||||||
onClick = {
|
|
||||||
when (option) {
|
|
||||||
is ViewOption -> {
|
|
||||||
findNavController().navigate(option.destinationID)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ComposeOption -> context.navigate(option.screen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getExtraOptions().fastForEach { option ->
|
|
||||||
OptionItem(
|
|
||||||
option = option,
|
|
||||||
tintColor = onPrimaryColor,
|
|
||||||
textColor = onPrimaryColor,
|
|
||||||
onClick = {
|
|
||||||
when (option) {
|
|
||||||
is ViewOption -> {
|
|
||||||
findNavController().navigate(option.destinationID)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ComposeOption -> context.navigate(option.screen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Footer(onPrimaryColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AppBar(onBackgroundColor: Color) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(4.dp, 10.dp, 4.dp, 10.dp)
|
|
||||||
) {
|
|
||||||
ThreeStateIconButton(tint = onBackgroundColor)
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.wrapContentWidth(),
|
|
||||||
text = stringResource(id = R.string.app_name),
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
color = onBackgroundColor,
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = R.drawable.ic_cancel),
|
|
||||||
contentDescription = stringResource(id = R.string.action_cancel),
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
findNavController().navigateUp()
|
|
||||||
},
|
|
||||||
colorFilter = ColorFilter.tint(onBackgroundColor)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Footer(tintColor: Color) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterHorizontally)
|
|
||||||
) {
|
|
||||||
TextButton(onClick = { requireContext().browse(Constants.URL_POLICY) }) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.privacy_policy_title),
|
|
||||||
fontWeight = FontWeight.Light,
|
|
||||||
color = tintColor,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(text = "•", color = tintColor)
|
|
||||||
TextButton(onClick = { requireContext().browse(URL_TOS) }) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.menu_terms),
|
|
||||||
fontWeight = FontWeight.Light,
|
|
||||||
color = tintColor,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun AccountHeader(backgroundColor: Color, onBackgroundColor: Color = Color.White) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(
|
|
||||||
RoundedCornerShape(
|
|
||||||
topStart = 25.dp,
|
|
||||||
topEnd = 25.dp,
|
|
||||||
bottomStart = 2.dp,
|
|
||||||
bottomEnd = 2.dp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.background(color = backgroundColor)
|
|
||||||
.padding(20.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(15.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth(),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(15.dp, Alignment.Start)
|
|
||||||
) {
|
|
||||||
AsyncImage(
|
|
||||||
model = ImageRequest.Builder(LocalContext.current)
|
|
||||||
.data(
|
|
||||||
if (viewModel.authProvider.isAnonymous) {
|
|
||||||
R.mipmap.ic_launcher
|
|
||||||
} else {
|
|
||||||
viewModel.authProvider.authData?.userProfile?.artwork?.url
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.crossfade(true)
|
|
||||||
.build(),
|
|
||||||
contentDescription = stringResource(id = R.string.title_account_manager),
|
|
||||||
placeholder = painterResource(R.drawable.ic_account),
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
modifier = Modifier
|
|
||||||
.requiredSize(36.dp)
|
|
||||||
.clip(CircleShape)
|
|
||||||
)
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Top,
|
|
||||||
horizontalAlignment = Alignment.Start
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = if (viewModel.authProvider.isAnonymous) {
|
|
||||||
stringResource(R.string.account_anonymous)
|
|
||||||
} else {
|
|
||||||
viewModel.authProvider.authData?.userProfile?.name
|
|
||||||
?: stringResource(R.string.status_unavailable)
|
|
||||||
},
|
|
||||||
fontWeight = FontWeight.Normal,
|
|
||||||
color = onBackgroundColor,
|
|
||||||
fontSize = 15.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = if (viewModel.authProvider.isAnonymous) {
|
|
||||||
stringResource(R.string.account_anonymous_email)
|
|
||||||
} else {
|
|
||||||
viewModel.authProvider.authData?.userProfile?.email
|
|
||||||
?: stringResource(R.string.status_unavailable)
|
|
||||||
},
|
|
||||||
fontWeight = FontWeight.Light,
|
|
||||||
color = onBackgroundColor,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutlinedButton(
|
|
||||||
onClick = { requireContext().navigate(Screen.Accounts) },
|
|
||||||
shape = RoundedCornerShape(12.dp),
|
|
||||||
border = BorderStroke(
|
|
||||||
1.dp,
|
|
||||||
Color(
|
|
||||||
requireContext().getStyledAttributeColor(
|
|
||||||
androidx.appcompat.R.attr.colorControlHighlight
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.manage_account),
|
|
||||||
color = onBackgroundColor,
|
|
||||||
fontWeight = FontWeight.Normal,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun OptionItem(
|
|
||||||
option: Option,
|
|
||||||
tintColor: Color = Color.Blue,
|
|
||||||
textColor: Color = Color.Black,
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable { onClick() }
|
|
||||||
.padding(12.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start)
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = option.icon),
|
|
||||||
contentDescription = stringResource(id = option.title),
|
|
||||||
colorFilter = ColorFilter.tint(color = tintColor),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 10.dp)
|
|
||||||
.requiredSize(23.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
text = stringResource(id = option.title),
|
|
||||||
color = textColor,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ThreeStateIconButton(tint: Color = Color.White) {
|
|
||||||
var currentState by remember {
|
|
||||||
mutableStateOf(
|
|
||||||
Preferences.getInteger(
|
|
||||||
requireContext(),
|
|
||||||
Preferences.PREFERENCE_THEME_STYLE
|
|
||||||
).let {
|
|
||||||
State.entries.getOrNull(it)
|
|
||||||
} ?: State.Auto
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val iconRes = when (currentState) {
|
|
||||||
State.Light -> R.drawable.ic_light
|
|
||||||
State.Dark -> R.drawable.ic_dark
|
|
||||||
else -> R.drawable.ic_auto
|
|
||||||
}
|
|
||||||
|
|
||||||
Image(
|
|
||||||
painter = painterResource(id = iconRes),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
currentState = when (currentState) {
|
|
||||||
State.Light -> State.Dark
|
|
||||||
State.Dark -> State.Auto
|
|
||||||
State.Auto -> State.Light
|
|
||||||
}
|
|
||||||
|
|
||||||
Preferences.putInteger(
|
|
||||||
requireContext(),
|
|
||||||
Preferences.PREFERENCE_THEME_STYLE,
|
|
||||||
currentState.value
|
|
||||||
)
|
|
||||||
|
|
||||||
setAppTheme(currentState.value)
|
|
||||||
findNavController().navigateUp()
|
|
||||||
},
|
|
||||||
colorFilter = ColorFilter.tint(tint)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class State(val value: Int) {
|
|
||||||
Auto(0),
|
|
||||||
Light(1),
|
|
||||||
Dark(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getOptions(): List<Option> = listOf(
|
|
||||||
ComposeOption(
|
|
||||||
title = R.string.title_apps_games,
|
|
||||||
icon = R.drawable.ic_apps,
|
|
||||||
screen = Screen.Installed
|
|
||||||
),
|
|
||||||
ComposeOption(
|
|
||||||
title = R.string.title_blacklist_manager,
|
|
||||||
icon = R.drawable.ic_blacklist,
|
|
||||||
screen = Screen.Blacklist
|
|
||||||
),
|
|
||||||
ComposeOption(
|
|
||||||
title = R.string.title_favourites_manager,
|
|
||||||
icon = R.drawable.ic_favorite_unchecked,
|
|
||||||
screen = Screen.Favourite
|
|
||||||
),
|
|
||||||
ComposeOption(
|
|
||||||
title = R.string.title_spoof_manager,
|
|
||||||
icon = R.drawable.ic_spoof,
|
|
||||||
screen = Screen.Spoof
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getExtraOptions(): List<Option> = listOf(
|
|
||||||
ViewOption(
|
|
||||||
title = R.string.title_settings,
|
|
||||||
icon = R.drawable.ic_menu_settings,
|
|
||||||
destinationID = R.id.settingsFragment
|
|
||||||
),
|
|
||||||
ComposeOption(
|
|
||||||
title = R.string.title_about,
|
|
||||||
icon = R.drawable.ic_menu_about,
|
|
||||||
screen = Screen.About
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.databinding.FragmentTopChartBinding
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class TopChartContainerFragment : BaseFragment<FragmentTopChartBinding>() {
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(chartType: Int): TopChartContainerFragment =
|
|
||||||
TopChartContainerFragment().apply {
|
|
||||||
arguments = Bundle().apply {
|
|
||||||
putInt(Constants.TOP_CHART_TYPE, chartType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
var chartType = 0
|
|
||||||
val bundle = arguments
|
|
||||||
if (bundle != null) {
|
|
||||||
chartType = bundle.getInt(Constants.TOP_CHART_TYPE, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ViewPager
|
|
||||||
binding.pager.adapter =
|
|
||||||
ViewPagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle, chartType)
|
|
||||||
binding.topTabGroup.setOnCheckedStateChangeListener { _, checkedIds ->
|
|
||||||
when (checkedIds[0]) {
|
|
||||||
R.id.tab_top_free -> binding.pager.setCurrentItem(0, true)
|
|
||||||
R.id.tab_top_grossing -> binding.pager.setCurrentItem(1, true)
|
|
||||||
R.id.tab_trending -> binding.pager.setCurrentItem(2, true)
|
|
||||||
R.id.tab_top_paid -> binding.pager.setCurrentItem(3, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
|
||||||
override fun onPageSelected(position: Int) {
|
|
||||||
super.onPageSelected(position)
|
|
||||||
when (position) {
|
|
||||||
0 -> binding.topTabGroup.check(R.id.tab_top_free)
|
|
||||||
1 -> binding.topTabGroup.check(R.id.tab_top_grossing)
|
|
||||||
2 -> binding.topTabGroup.check(R.id.tab_trending)
|
|
||||||
3 -> binding.topTabGroup.check(R.id.tab_top_paid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
binding.pager.adapter = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ViewPagerAdapter(
|
|
||||||
fragment: FragmentManager,
|
|
||||||
lifecycle: Lifecycle,
|
|
||||||
chartType: Int
|
|
||||||
) :
|
|
||||||
FragmentStateAdapter(fragment, lifecycle) {
|
|
||||||
private val tabFragments: MutableList<TopChartFragment> = mutableListOf(
|
|
||||||
TopChartFragment.newInstance(chartType, 0),
|
|
||||||
TopChartFragment.newInstance(chartType, 1),
|
|
||||||
TopChartFragment.newInstance(chartType, 2),
|
|
||||||
TopChartFragment.newInstance(chartType, 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment = tabFragments[position]
|
|
||||||
|
|
||||||
override fun getItemCount(): Int = tabFragments.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.commons
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.gplayapi.data.models.StreamCluster
|
|
||||||
import com.aurora.gplayapi.helpers.contracts.TopChartsContract.Chart
|
|
||||||
import com.aurora.gplayapi.helpers.contracts.TopChartsContract.Type
|
|
||||||
import com.aurora.store.TopChartStash
|
|
||||||
import com.aurora.store.data.model.ViewState
|
|
||||||
import com.aurora.store.data.model.ViewState.Empty.getDataAs
|
|
||||||
import com.aurora.store.databinding.FragmentTopContainerBinding
|
|
||||||
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener
|
|
||||||
import com.aurora.store.view.epoxy.views.AppProgressViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.app.AppListViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
|
|
||||||
import com.aurora.store.viewmodel.topchart.TopChartViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class TopChartFragment : BaseFragment<FragmentTopContainerBinding>() {
|
|
||||||
|
|
||||||
private val viewModel: TopChartViewModel by activityViewModels()
|
|
||||||
|
|
||||||
private var streamCluster: StreamCluster? = StreamCluster()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(chartType: Int, chartCategory: Int): TopChartFragment =
|
|
||||||
TopChartFragment().apply {
|
|
||||||
arguments = Bundle().apply {
|
|
||||||
putInt(Constants.TOP_CHART_TYPE, chartType)
|
|
||||||
putInt(Constants.TOP_CHART_CATEGORY, chartCategory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
var type = 0
|
|
||||||
var category = 0
|
|
||||||
val bundle = arguments
|
|
||||||
|
|
||||||
if (bundle != null) {
|
|
||||||
type = bundle.getInt(Constants.TOP_CHART_TYPE, 0)
|
|
||||||
category = bundle.getInt(Constants.TOP_CHART_CATEGORY, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val chartType = when (type) {
|
|
||||||
1 -> Type.GAME
|
|
||||||
else -> Type.APPLICATION
|
|
||||||
}
|
|
||||||
|
|
||||||
val chartCategory = when (category) {
|
|
||||||
1 -> Chart.TOP_GROSSING
|
|
||||||
2 -> Chart.MOVERS_SHAKERS
|
|
||||||
3 -> Chart.TOP_SELLING_PAID
|
|
||||||
else -> Chart.TOP_SELLING_FREE
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.recycler.addOnScrollListener(object : EndlessRecyclerOnScrollListener() {
|
|
||||||
override fun onLoadMore(currentPage: Int) {
|
|
||||||
viewModel.nextCluster(chartType, chartCategory)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
updateController(null)
|
|
||||||
|
|
||||||
viewModel.getStreamCluster(chartType, chartCategory)
|
|
||||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
|
||||||
when (it) {
|
|
||||||
is ViewState.Loading, is ViewState.Error -> {
|
|
||||||
updateController(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Success<*> -> {
|
|
||||||
val stash = it.getDataAs<TopChartStash>()
|
|
||||||
streamCluster = stash[chartType]?.get(chartCategory)
|
|
||||||
|
|
||||||
updateController(streamCluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateController(streamCluster: StreamCluster?) {
|
|
||||||
binding.recycler.withModels {
|
|
||||||
setFilterDuplicates(true)
|
|
||||||
if (streamCluster == null) {
|
|
||||||
for (i in 1..6) {
|
|
||||||
add(
|
|
||||||
AppListViewShimmerModel_()
|
|
||||||
.id(i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
streamCluster.clusterAppList.forEach { app ->
|
|
||||||
add(
|
|
||||||
AppListViewModel_()
|
|
||||||
.id(app.id)
|
|
||||||
.app(app)
|
|
||||||
.click { _ -> openDetailsFragment(app.packageName) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streamCluster.hasNext()) {
|
|
||||||
add(
|
|
||||||
AppProgressViewModel_()
|
|
||||||
.id("progress")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.details
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.navigation.fragment.navArgs
|
|
||||||
import coil3.load
|
|
||||||
import com.aurora.gplayapi.data.models.App
|
|
||||||
import com.aurora.gplayapi.data.models.StreamCluster
|
|
||||||
import com.aurora.gplayapi.data.models.details.DevStream
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.data.model.ViewState
|
|
||||||
import com.aurora.store.databinding.FragmentDevProfileBinding
|
|
||||||
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
|
||||||
import com.aurora.store.viewmodel.details.DevProfileViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class DevProfileFragment :
|
|
||||||
BaseFragment<FragmentDevProfileBinding>(),
|
|
||||||
GenericCarouselController.Callbacks {
|
|
||||||
|
|
||||||
private val args: DevProfileFragmentArgs by navArgs()
|
|
||||||
private val viewModel: DevProfileViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.apply {
|
|
||||||
title =
|
|
||||||
if (args.title.isNullOrBlank()) {
|
|
||||||
getString(R.string.details_dev_profile)
|
|
||||||
} else {
|
|
||||||
args.title
|
|
||||||
}
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecyclerView
|
|
||||||
|
|
||||||
viewModel.liveData.observe(viewLifecycleOwner) {
|
|
||||||
when (it) {
|
|
||||||
is ViewState.Empty -> {
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Loading -> {
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Error -> {
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Status -> {
|
|
||||||
}
|
|
||||||
|
|
||||||
is ViewState.Success<*> -> {
|
|
||||||
(it.data as DevStream).apply {
|
|
||||||
binding.toolbar.title = title
|
|
||||||
binding.txtDevName.text = title
|
|
||||||
binding.txtDevDescription.text = description
|
|
||||||
binding.imgIcon.load(imgUrl)
|
|
||||||
binding.viewFlipper.displayedChild = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.viewFlipper.displayedChild = 1
|
|
||||||
viewModel.getStreamBundle(args.devId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHeaderClicked(streamCluster: StreamCluster) {
|
|
||||||
openStreamBrowseFragment(streamCluster.clusterBrowseUrl, streamCluster.clusterTitle)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClusterScrolled(streamCluster: StreamCluster) {
|
|
||||||
viewModel.observeCluster(streamCluster)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppClick(app: App) {
|
|
||||||
openDetailsFragment(app.packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppLongClick(app: App) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.games
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.store.MobileNavigationDirections
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.databinding.FragmentAppsGamesBinding
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
|
||||||
import com.aurora.store.view.ui.commons.CategoryFragment
|
|
||||||
import com.aurora.store.view.ui.commons.ForYouFragment
|
|
||||||
import com.aurora.store.view.ui.commons.TopChartContainerFragment
|
|
||||||
import com.aurora.store.viewmodel.games.GamesContainerViewModel
|
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class GamesContainerFragment : BaseFragment<FragmentAppsGamesBinding>() {
|
|
||||||
|
|
||||||
private val viewModel: GamesContainerViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
// Adjust FAB margins for edgeToEdge display
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.searchFab) { _, windowInsets ->
|
|
||||||
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
|
||||||
binding.searchFab.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
|
||||||
bottomMargin = insets.bottom + resources.getDimensionPixelSize(R.dimen.margin_large)
|
|
||||||
}
|
|
||||||
WindowInsetsCompat.CONSUMED
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.apply {
|
|
||||||
title = getString(R.string.title_games)
|
|
||||||
setOnMenuItemClickListener {
|
|
||||||
when (it.itemId) {
|
|
||||||
R.id.menu_download_manager -> {
|
|
||||||
requireContext().navigate(Screen.Downloads)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.menu_more -> {
|
|
||||||
findNavController().navigate(
|
|
||||||
MobileNavigationDirections.actionGlobalMoreDialogFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ViewPager
|
|
||||||
val isForYouEnabled = Preferences.getBoolean(
|
|
||||||
requireContext(),
|
|
||||||
Preferences.PREFERENCE_FOR_YOU
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.pager.adapter = ViewPagerAdapter(
|
|
||||||
childFragmentManager,
|
|
||||||
viewLifecycleOwner.lifecycle,
|
|
||||||
!viewModel.authProvider.isAnonymous,
|
|
||||||
isForYouEnabled
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.pager.isUserInputEnabled = false
|
|
||||||
|
|
||||||
val tabTitles: MutableList<String> = mutableListOf<String>().apply {
|
|
||||||
if (isForYouEnabled) {
|
|
||||||
add(getString(R.string.tab_for_you))
|
|
||||||
}
|
|
||||||
|
|
||||||
add(getString(R.string.tab_top_charts))
|
|
||||||
add(getString(R.string.tab_categories))
|
|
||||||
}
|
|
||||||
|
|
||||||
TabLayoutMediator(
|
|
||||||
binding.tabLayout,
|
|
||||||
binding.pager,
|
|
||||||
true
|
|
||||||
) { tab: TabLayout.Tab, position: Int ->
|
|
||||||
tab.text = tabTitles[position]
|
|
||||||
}.attach()
|
|
||||||
|
|
||||||
binding.searchFab.setOnClickListener {
|
|
||||||
requireContext().navigate(Screen.Search)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
binding.pager.adapter = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ViewPagerAdapter(
|
|
||||||
fragment: FragmentManager,
|
|
||||||
lifecycle: Lifecycle,
|
|
||||||
private val isGoogleAccount: Boolean,
|
|
||||||
private val isForYouEnabled: Boolean
|
|
||||||
) :
|
|
||||||
FragmentStateAdapter(fragment, lifecycle) {
|
|
||||||
private val tabFragments: MutableList<Fragment> = mutableListOf<Fragment>().apply {
|
|
||||||
if (isForYouEnabled) {
|
|
||||||
add(ForYouFragment.newInstance(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
add(TopChartContainerFragment.newInstance(1))
|
|
||||||
add(CategoryFragment.newInstance(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment = tabFragments[position]
|
|
||||||
|
|
||||||
override fun getItemCount(): Int = tabFragments.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package com.aurora.store.view.ui.preferences
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.preference.EditTextPreference
|
|
||||||
import androidx.preference.ListPreference
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import com.aurora.store.data.providers.PermissionProvider
|
|
||||||
import com.aurora.store.view.custom.preference.M3EditTextPreference
|
|
||||||
import com.aurora.store.view.custom.preference.M3ListPreference
|
|
||||||
|
|
||||||
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
|
|
||||||
|
|
||||||
lateinit var permissionProvider: PermissionProvider
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
permissionProvider = PermissionProvider(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
|
||||||
when (preference) {
|
|
||||||
is EditTextPreference -> {
|
|
||||||
val dialogFragment = M3EditTextPreference.newInstance(preference.getKey())
|
|
||||||
dialogFragment.setTargetFragment(this, 0)
|
|
||||||
dialogFragment.show(
|
|
||||||
parentFragmentManager,
|
|
||||||
M3EditTextPreference.PREFERENCE_DIALOG_FRAGMENT_TAG
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ListPreference -> {
|
|
||||||
val dialogFragment = M3ListPreference.newInstance(preference.getKey())
|
|
||||||
dialogFragment.setTargetFragment(this, 0)
|
|
||||||
dialogFragment.show(
|
|
||||||
parentFragmentManager,
|
|
||||||
M3ListPreference.PREFERENCE_DIALOG_FRAGMENT_TAG
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> super.onDisplayPreferenceDialog(preference)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
permissionProvider.unregister()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.preferences
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.data.model.PermissionType
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat() {
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.preferences_settings, rootKey)
|
|
||||||
|
|
||||||
findPreference<Preference>("pref_perms")?.setOnPreferenceClickListener {
|
|
||||||
requireContext().navigate(
|
|
||||||
Screen.PermissionRationale(requiredPermissions = PermissionType.entries.toSet())
|
|
||||||
)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
findPreference<Preference>("pref_install")?.setOnPreferenceClickListener {
|
|
||||||
findNavController().navigate(R.id.installationPreference)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
findPreference<Preference>("pref_ui")?.setOnPreferenceClickListener {
|
|
||||||
findNavController().navigate(R.id.UIPreference)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
findPreference<Preference>("pref_network")?.setOnPreferenceClickListener {
|
|
||||||
findNavController().navigate(R.id.networkPreference)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
findPreference<Preference>("pref_updates")?.setOnPreferenceClickListener {
|
|
||||||
findNavController().navigate(R.id.updatesPreference)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
view.findViewById<Toolbar>(R.id.toolbar)?.apply {
|
|
||||||
title = getString(R.string.title_settings)
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.preferences
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import com.aurora.extensions.isTAndAbove
|
|
||||||
import com.aurora.store.R
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class UIPreference : BasePreferenceFragment() {
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.preferences_ui, rootKey)
|
|
||||||
|
|
||||||
findPreference<Preference>("PREFERENCE_APP_LANGUAGE")?.apply {
|
|
||||||
if (isTAndAbove) {
|
|
||||||
summary = Locale.getDefault().displayName
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
startActivity(
|
|
||||||
Intent(Settings.ACTION_APP_LOCALE_SETTINGS).apply {
|
|
||||||
data = ("package:" + requireContext().packageName).toUri()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
view.findViewById<Toolbar>(R.id.toolbar)?.apply {
|
|
||||||
title = getString(R.string.pref_ui_title)
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.preferences.installation
|
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager
|
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.content.getSystemService
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.extensions.showDialog
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLATION_DEVICE_OWNER
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class InstallationPreference : PreferenceFragmentCompat() {
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.preferences_installation, rootKey)
|
|
||||||
|
|
||||||
findPreference<Preference>(PREFERENCE_INSTALLER_ID)?.apply {
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
requireContext().navigate(Screen.Installer)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<Preference>(PREFERENCE_INSTALLATION_DEVICE_OWNER)?.apply {
|
|
||||||
val packageName = context.packageName
|
|
||||||
val devicePolicyManager = context.getSystemService<DevicePolicyManager>()
|
|
||||||
|
|
||||||
isVisible = devicePolicyManager?.isDeviceOwnerApp(packageName) ?: false
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
context.showDialog(
|
|
||||||
context.getString(R.string.pref_clear_device_owner_title),
|
|
||||||
context.getString(R.string.pref_clear_device_owner_desc),
|
|
||||||
{ _: DialogInterface, _: Int ->
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
devicePolicyManager!!.clearDeviceOwnerApp(packageName)
|
|
||||||
activity?.recreate()
|
|
||||||
},
|
|
||||||
{ dialog: DialogInterface, _: Int -> dialog.dismiss() }
|
|
||||||
)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
view.findViewById<Toolbar>(R.id.toolbar)?.apply {
|
|
||||||
title = getString(R.string.title_installation)
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.preferences.network
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.extensions.runOnUiThread
|
|
||||||
import com.aurora.extensions.toast
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.util.PackageUtil
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_MICROG_AUTH
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_URL
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION
|
|
||||||
import com.aurora.store.util.save
|
|
||||||
import com.aurora.store.view.ui.preferences.BasePreferenceFragment
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class NetworkPreference : BasePreferenceFragment() {
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.preferences_network, rootKey)
|
|
||||||
|
|
||||||
findPreference<Preference>(Preferences.PREFERENCE_DISPENSER_URLS)?.apply {
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
requireContext().navigate(Screen.Dispenser)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<Preference>(PREFERENCE_PROXY_URL)?.setOnPreferenceClickListener { _ ->
|
|
||||||
findNavController().navigate(R.id.proxyURLDialog)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<Preference>(PREFERENCE_VENDING_VERSION)?.let {
|
|
||||||
it.setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
save(PREFERENCE_VENDING_VERSION, Integer.parseInt(newValue.toString()))
|
|
||||||
runOnUiThread {
|
|
||||||
requireContext().toast(R.string.insecure_anonymous_apply)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<SwitchPreferenceCompat>(PREFERENCE_MICROG_AUTH)?.isVisible =
|
|
||||||
PackageUtil.hasSupportedMicroGVariant(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
view.findViewById<Toolbar>(R.id.toolbar)?.apply {
|
|
||||||
title = getString(R.string.pref_network_title)
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
package com.aurora.store.view.ui.preferences.network
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.core.widget.doOnTextChanged
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import com.aurora.extensions.showKeyboard
|
|
||||||
import com.aurora.extensions.toast
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.util.CommonUtil
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_URL
|
|
||||||
import com.aurora.store.util.remove
|
|
||||||
import com.aurora.store.util.save
|
|
||||||
import com.aurora.store.viewmodel.preferences.ProxyURLViewModel
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class ProxyURLDialog : DialogFragment() {
|
|
||||||
|
|
||||||
private val viewModel: ProxyURLViewModel by viewModels()
|
|
||||||
|
|
||||||
private val currentProxyUrl: String
|
|
||||||
get() = Preferences.getString(requireContext(), PREFERENCE_PROXY_URL)
|
|
||||||
private val textInputLayout: TextInputLayout?
|
|
||||||
get() = dialog?.findViewById(R.id.textInputLayout)
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
val view = layoutInflater.inflate(R.layout.dialog_text_input_edit_text, null)
|
|
||||||
val alertDialog = MaterialAlertDialogBuilder(requireContext())
|
|
||||||
.setTitle(R.string.pref_network_proxy_url)
|
|
||||||
.setMessage(R.string.pref_network_proxy_url_message)
|
|
||||||
.setView(view)
|
|
||||||
.setPositiveButton(getString(R.string.set), null)
|
|
||||||
.setNeutralButton(getString(R.string.disable), null)
|
|
||||||
.setNegativeButton(getString(android.R.string.cancel)) { _, _ -> dialog?.dismiss() }
|
|
||||||
.create()
|
|
||||||
|
|
||||||
alertDialog.setOnShowListener {
|
|
||||||
val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
|
|
||||||
isEnabled = currentProxyUrl.isNotBlank()
|
|
||||||
setOnClickListener { saveProxyUrl() }
|
|
||||||
}
|
|
||||||
textInputLayout?.editText?.doOnTextChanged { text, _, _, _ ->
|
|
||||||
positiveButton.isEnabled = !text.isNullOrBlank()
|
|
||||||
}
|
|
||||||
|
|
||||||
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).apply {
|
|
||||||
isEnabled = currentProxyUrl.isNotBlank()
|
|
||||||
setOnClickListener { deleteProxyUrl() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return alertDialog
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
textInputLayout?.editText?.apply {
|
|
||||||
setText(currentProxyUrl)
|
|
||||||
showKeyboard()
|
|
||||||
}
|
|
||||||
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveProxyUrl() {
|
|
||||||
val url = textInputLayout?.editText?.text?.toString()?.trim()
|
|
||||||
if (url.isNullOrEmpty()) {
|
|
||||||
toast(R.string.toast_proxy_invalid)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val proxyInfo = CommonUtil.parseProxyUrl(url)
|
|
||||||
if (proxyInfo != null) {
|
|
||||||
save(PREFERENCE_PROXY_URL, url)
|
|
||||||
save(PREFERENCE_PROXY_INFO, viewModel.json.encodeToString(proxyInfo))
|
|
||||||
toast(R.string.toast_proxy_success)
|
|
||||||
findNavController().navigate(R.id.forceRestartDialog)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
toast(R.string.toast_proxy_failed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deleteProxyUrl() {
|
|
||||||
remove(PREFERENCE_PROXY_URL)
|
|
||||||
remove(PREFERENCE_PROXY_INFO)
|
|
||||||
toast(R.string.toast_proxy_disabled)
|
|
||||||
findNavController().navigate(R.id.forceRestartDialog)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.preferences.updates
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.preference.ListPreference
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.SeekBarPreference
|
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.data.model.PermissionType
|
|
||||||
import com.aurora.store.data.model.UpdateMode
|
|
||||||
import com.aurora.store.data.providers.PermissionProvider.Companion.isGranted
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS
|
|
||||||
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_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.save
|
|
||||||
import com.aurora.store.view.ui.preferences.BasePreferenceFragment
|
|
||||||
import com.aurora.store.viewmodel.all.UpdatesViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class UpdatesPreference : BasePreferenceFragment() {
|
|
||||||
|
|
||||||
private val viewModel: UpdatesViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.preferences_updates, rootKey)
|
|
||||||
|
|
||||||
val updatesEnabled = Preferences.getInteger(requireContext(), PREFERENCE_UPDATES_AUTO) != 0
|
|
||||||
|
|
||||||
findPreference<ListPreference>(PREFERENCE_UPDATES_AUTO)?.setOnPreferenceChangeListener {
|
|
||||||
_,
|
|
||||||
newValue
|
|
||||||
->
|
|
||||||
when (UpdateMode.entries[newValue.toString().toInt()]) {
|
|
||||||
UpdateMode.DISABLED -> {
|
|
||||||
handleAutoUpdateDependentPrefs(false)
|
|
||||||
viewModel.updateHelper.cancelAutomatedCheck()
|
|
||||||
requireContext().save(PREFERENCE_UPDATES_AUTO, 0)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateMode.CHECK_AND_NOTIFY -> {
|
|
||||||
if (isGranted(requireContext(), PermissionType.POST_NOTIFICATIONS)) {
|
|
||||||
handleAutoUpdateDependentPrefs(true)
|
|
||||||
viewModel.updateHelper.scheduleAutomatedCheck()
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
permissionProvider.request(PermissionType.POST_NOTIFICATIONS) {
|
|
||||||
if (it) {
|
|
||||||
handleAutoUpdateDependentPrefs(true)
|
|
||||||
requireContext().save(PREFERENCE_UPDATES_AUTO, 1)
|
|
||||||
viewModel.updateHelper.scheduleAutomatedCheck()
|
|
||||||
activity?.recreate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateMode.CHECK_AND_INSTALL -> {
|
|
||||||
if (isGranted(requireContext(), PermissionType.DOZE_WHITELIST)) {
|
|
||||||
handleAutoUpdateDependentPrefs(true)
|
|
||||||
viewModel.updateHelper.scheduleAutomatedCheck()
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
permissionProvider.request(PermissionType.DOZE_WHITELIST) {
|
|
||||||
if (it) {
|
|
||||||
handleAutoUpdateDependentPrefs(true)
|
|
||||||
requireContext().save(PREFERENCE_UPDATES_AUTO, 2)
|
|
||||||
viewModel.updateHelper.scheduleAutomatedCheck()
|
|
||||||
activity?.recreate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAutoUpdateDependentPrefs(updatesEnabled)
|
|
||||||
|
|
||||||
findPreference<SwitchPreferenceCompat>(PREFERENCE_FILTER_AURORA_ONLY)
|
|
||||||
?.setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
findPreference<SwitchPreferenceCompat>(PREFERENCE_FILTER_FDROID)?.isEnabled =
|
|
||||||
!newValue.toString().toBoolean()
|
|
||||||
viewModel.updateHelper.checkUpdatesNow()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<SwitchPreferenceCompat>(PREFERENCE_FILTER_FDROID)?.apply {
|
|
||||||
isEnabled = !Preferences.getBoolean(requireContext(), PREFERENCE_FILTER_AURORA_ONLY)
|
|
||||||
setOnPreferenceChangeListener { _, _ ->
|
|
||||||
viewModel.updateHelper.checkUpdatesNow()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<SwitchPreferenceCompat>(PREFERENCE_UPDATES_EXTENDED)
|
|
||||||
?.setOnPreferenceChangeListener { _, _ ->
|
|
||||||
viewModel.updateHelper.checkUpdatesNow()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
view.findViewById<Toolbar>(R.id.toolbar)?.apply {
|
|
||||||
title = getString(R.string.title_updates)
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleAutoUpdateDependentPrefs(enabled: Boolean) {
|
|
||||||
findPreference<Preference>(PREFERENCES_UPDATES_RESTRICTIONS)?.apply {
|
|
||||||
isEnabled = enabled
|
|
||||||
isVisible = enabled
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
findNavController().navigate(R.id.updatesRestrictionsDialog)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference<SeekBarPreference>(PREFERENCE_UPDATES_CHECK_INTERVAL)?.apply {
|
|
||||||
isEnabled = enabled
|
|
||||||
isVisible = enabled
|
|
||||||
setOnPreferenceChangeListener { _, _ ->
|
|
||||||
viewModel.updateHelper.updateAutomatedCheck()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2025 The Calyx Institute
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.preferences.updates
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_BATTERY
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_IDLE
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_METERED
|
|
||||||
import com.aurora.store.viewmodel.preferences.UpdatesRestrictionsViewModel
|
|
||||||
import com.google.android.material.checkbox.MaterialCheckBox
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class UpdatesRestrictionsDialog : DialogFragment() {
|
|
||||||
|
|
||||||
private val viewModel: UpdatesRestrictionsViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
val view = layoutInflater.inflate(R.layout.dialog_auto_updates_restrictions, null)
|
|
||||||
return MaterialAlertDialogBuilder(requireContext())
|
|
||||||
.setTitle(R.string.pref_updates_restrictions_title)
|
|
||||||
.setMessage(R.string.pref_updates_restrictions_desc)
|
|
||||||
.setView(view)
|
|
||||||
.setPositiveButton(getString(android.R.string.ok)) { _, _ -> dialog?.dismiss() }
|
|
||||||
.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
context?.let { setupRestrictions(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
viewModel.updateHelper.updateAutomatedCheck()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupRestrictions(context: Context) {
|
|
||||||
dialog?.findViewById<MaterialCheckBox>(R.id.checkboxMetered)?.apply {
|
|
||||||
isChecked =
|
|
||||||
Preferences.getBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_METERED, true)
|
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
Preferences.putBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_METERED, isChecked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog?.findViewById<MaterialCheckBox>(R.id.checkboxIdle)?.apply {
|
|
||||||
isChecked = Preferences.getBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_IDLE, true)
|
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
Preferences.putBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_IDLE, isChecked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog?.findViewById<MaterialCheckBox>(R.id.checkboxBattery)?.apply {
|
|
||||||
isChecked =
|
|
||||||
Preferences.getBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_BATTERY, true)
|
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
Preferences.putBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_BATTERY, isChecked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
* Copyright (C) 2022, The Calyx Institute
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.sheets
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.navigation.fragment.navArgs
|
|
||||||
import com.aurora.extensions.openInfo
|
|
||||||
import com.aurora.extensions.toast
|
|
||||||
import com.aurora.store.AuroraApp
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.data.event.BusEvent
|
|
||||||
import com.aurora.store.data.installer.AppInstaller
|
|
||||||
import com.aurora.store.databinding.SheetAppMenuBinding
|
|
||||||
import com.aurora.store.util.PackageUtil
|
|
||||||
import com.aurora.store.viewmodel.sheets.AppMenuViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class AppMenuSheet : BaseDialogSheet<SheetAppMenuBinding>() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TAG = "APP_MENU_SHEET"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val viewModel: AppMenuViewModel by viewModels()
|
|
||||||
private val args: AppMenuSheetArgs by navArgs()
|
|
||||||
|
|
||||||
private val exportMimeType = "application/zip"
|
|
||||||
|
|
||||||
private val requestDocumentCreation =
|
|
||||||
registerForActivityResult(ActivityResultContracts.CreateDocument(exportMimeType)) {
|
|
||||||
if (it != null) {
|
|
||||||
viewModel.copyInstalledApp(requireContext(), args.app, it)
|
|
||||||
} else {
|
|
||||||
toast(R.string.failed_apk_export)
|
|
||||||
}
|
|
||||||
dismissAllowingStateLoss()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
val isBlacklisted: Boolean = viewModel.blacklistProvider.isBlacklisted(args.app.packageName)
|
|
||||||
|
|
||||||
with(binding.navigationView) {
|
|
||||||
// Switch strings for Add/Remove Blacklist
|
|
||||||
val blackListMenu: MenuItem = menu.findItem(R.id.action_blacklist)
|
|
||||||
blackListMenu.setTitle(
|
|
||||||
if (isBlacklisted) {
|
|
||||||
R.string.action_whitelist
|
|
||||||
} else {
|
|
||||||
R.string.action_blacklist_add
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Show/Hide actions based on installed status
|
|
||||||
val installed = PackageUtil.isInstalled(requireContext(), args.app.packageName)
|
|
||||||
menu.findItem(R.id.action_uninstall).isVisible = installed
|
|
||||||
menu.findItem(R.id.action_local).isVisible = installed
|
|
||||||
|
|
||||||
setNavigationItemSelectedListener { item ->
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.action_blacklist -> {
|
|
||||||
if (isBlacklisted) {
|
|
||||||
viewModel.blacklistProvider.whitelist(args.app.packageName)
|
|
||||||
requireContext().toast(R.string.toast_apk_whitelisted)
|
|
||||||
} else {
|
|
||||||
viewModel.blacklistProvider.blacklist(args.app.packageName)
|
|
||||||
requireContext().toast(R.string.toast_apk_blacklisted)
|
|
||||||
}
|
|
||||||
|
|
||||||
dismissAllowingStateLoss()
|
|
||||||
AuroraApp.events.send(
|
|
||||||
BusEvent.Blacklisted(args.app.packageName)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_local -> {
|
|
||||||
requestDocumentCreation.launch("${args.app.packageName}.zip")
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_uninstall -> {
|
|
||||||
AppInstaller.uninstall(requireContext(), args.app.packageName)
|
|
||||||
dismissAllowingStateLoss()
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_info -> {
|
|
||||||
requireContext().openInfo(args.app.packageName)
|
|
||||||
dismissAllowingStateLoss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
* Copyright (C) 2022, The Calyx Institute
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.sheets
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.viewbinding.ViewBinding
|
|
||||||
import com.aurora.store.data.providers.PermissionProvider
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|
||||||
import java.lang.reflect.ParameterizedType
|
|
||||||
|
|
||||||
abstract class BaseDialogSheet<ViewBindingType : ViewBinding> : BottomSheetDialogFragment() {
|
|
||||||
|
|
||||||
private var _binding: ViewBindingType? = null
|
|
||||||
protected val binding get() = _binding!!
|
|
||||||
|
|
||||||
lateinit var permissionProvider: PermissionProvider
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
permissionProvider = PermissionProvider(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val type = (javaClass.genericSuperclass as ParameterizedType)
|
|
||||||
.actualTypeArguments[0] as Class<ViewBindingType>
|
|
||||||
|
|
||||||
val method = type.getMethod(
|
|
||||||
"inflate",
|
|
||||||
LayoutInflater::class.java,
|
|
||||||
ViewGroup::class.java,
|
|
||||||
Boolean::class.java
|
|
||||||
)
|
|
||||||
|
|
||||||
_binding = method.invoke(null, inflater, container, false) as ViewBindingType
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
permissionProvider.unregister()
|
|
||||||
_binding = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.sheets
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.view.View
|
|
||||||
import coil3.load
|
|
||||||
import coil3.request.transformations
|
|
||||||
import coil3.transform.CircleCropTransformation
|
|
||||||
import com.aurora.extensions.toast
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.databinding.SheetDeviceMiuiBinding
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class DeviceMiuiSheet : BaseDialogSheet<SheetDeviceMiuiBinding>() {
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
binding.imgIcon.load(R.drawable.ic_xiaomi_logo) {
|
|
||||||
transformations(CircleCropTransformation())
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.btnPrimary.setOnClickListener {
|
|
||||||
try {
|
|
||||||
startActivity(Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS))
|
|
||||||
} catch (_: Exception) {
|
|
||||||
toast(R.string.toast_developer_setting_failed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.btnSecondary.setOnClickListener {
|
|
||||||
dismissAllowingStateLoss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.sheets
|
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import com.aurora.extensions.TAG
|
|
||||||
import com.aurora.extensions.isQAndAbove
|
|
||||||
import com.aurora.store.databinding.SheetNetworkBinding
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class NetworkDialogSheet : BaseDialogSheet<SheetNetworkBinding>() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
const val TAG = "NetworkDialogSheet"
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(): NetworkDialogSheet = NetworkDialogSheet().apply {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
binding.btnAction.setOnClickListener {
|
|
||||||
if (isQAndAbove) {
|
|
||||||
startActivity(Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY))
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS))
|
|
||||||
} catch (exception: ActivityNotFoundException) {
|
|
||||||
Log.i(TAG, "Unable to launch wireless settings")
|
|
||||||
startActivity(Intent(Settings.ACTION_SETTINGS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
package com.aurora.store.view.ui.splash
|
|
||||||
|
|
||||||
import android.accounts.Account
|
|
||||||
import android.accounts.AccountManager
|
|
||||||
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.view.isVisible
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE
|
|
||||||
import com.aurora.extensions.TAG
|
|
||||||
import com.aurora.extensions.getPackageName
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.gplayapi.helpers.AuthHelper
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.data.model.AuthState
|
|
||||||
import com.aurora.store.databinding.FragmentSplashBinding
|
|
||||||
import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE
|
|
||||||
import com.aurora.store.util.CertUtil.GOOGLE_PLAY_AUTH_TOKEN_TYPE
|
|
||||||
import com.aurora.store.util.CertUtil.GOOGLE_PLAY_CERT
|
|
||||||
import com.aurora.store.util.PackageUtil
|
|
||||||
import com.aurora.store.util.Preferences
|
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB
|
|
||||||
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 kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
abstract class BaseFlavouredSplashFragment : BaseFragment<FragmentSplashBinding>() {
|
|
||||||
|
|
||||||
val viewModel: AuthViewModel by activityViewModels()
|
|
||||||
|
|
||||||
val canLoginWithMicroG: Boolean
|
|
||||||
get() = PackageUtil.hasSupportedMicroGVariant(requireContext()) &&
|
|
||||||
Preferences.getBoolean(requireContext(), PREFERENCE_MICROG_AUTH, true)
|
|
||||||
|
|
||||||
val startForAccount =
|
|
||||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
|
||||||
val accountName = it.data?.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
|
|
||||||
if (!accountName.isNullOrBlank()) {
|
|
||||||
requestAuthTokenForGoogle(accountName)
|
|
||||||
} else {
|
|
||||||
resetActions()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
viewBindingType = FragmentSplashBinding.inflate(inflater, container, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
if (!Preferences.getBoolean(requireContext(), PREFERENCE_INTRO)) {
|
|
||||||
requireContext().navigate(Screen.Onboarding)
|
|
||||||
activity?.finish()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.apply {
|
|
||||||
setOnMenuItemClickListener {
|
|
||||||
when (it.itemId) {
|
|
||||||
R.id.menu_blacklist_manager -> {
|
|
||||||
requireContext().navigate(Screen.Blacklist)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.menu_spoof_manager -> requireContext().navigate(Screen.Spoof)
|
|
||||||
|
|
||||||
R.id.menu_settings -> {
|
|
||||||
findNavController().navigate(R.id.settingsFragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.menu_about -> requireContext().navigate(Screen.About)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attachActions()
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
viewModel.authState.collectLatest {
|
|
||||||
when (it) {
|
|
||||||
AuthState.Init -> updateStatus(getString(R.string.session_init))
|
|
||||||
|
|
||||||
AuthState.Fetching -> {
|
|
||||||
updateStatus(getString(R.string.requesting_new_session))
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthState.Valid -> {
|
|
||||||
val packageName =
|
|
||||||
requireActivity().intent.getPackageName(requireArguments())
|
|
||||||
if (packageName.isNullOrBlank()) {
|
|
||||||
navigateToDefaultTab()
|
|
||||||
} else {
|
|
||||||
requireArguments().remove("packageName")
|
|
||||||
openDetailsFragment(packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthState.Available -> {
|
|
||||||
updateStatus(getString(R.string.session_verifying))
|
|
||||||
updateActionLayout(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthState.Unavailable -> {
|
|
||||||
updateStatus(getString(R.string.session_login))
|
|
||||||
updateActionLayout(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthState.SignedIn -> {
|
|
||||||
val packageName =
|
|
||||||
requireActivity().intent.getPackageName(requireArguments())
|
|
||||||
if (packageName.isNullOrBlank()) {
|
|
||||||
navigateToDefaultTab()
|
|
||||||
} else {
|
|
||||||
requireArguments().remove("packageName")
|
|
||||||
openDetailsFragment(packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthState.SignedOut -> {
|
|
||||||
updateStatus(getString(R.string.session_scrapped))
|
|
||||||
updateActionLayout(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthState.Verifying -> {
|
|
||||||
updateStatus(getString(R.string.verifying_new_session))
|
|
||||||
}
|
|
||||||
|
|
||||||
is AuthState.PendingAccountManager -> {
|
|
||||||
requestAuthTokenForGoogle(it.email, it.token)
|
|
||||||
}
|
|
||||||
|
|
||||||
is AuthState.Failed -> {
|
|
||||||
updateStatus(it.status)
|
|
||||||
updateActionLayout(true)
|
|
||||||
resetActions()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateStatus(string: String?) {
|
|
||||||
activity?.runOnUiThread { binding.txtStatus.text = string }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateActionLayout(isVisible: Boolean) {
|
|
||||||
binding.layoutAction.isVisible = isVisible
|
|
||||||
binding.toolbar.isVisible = isVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun navigateToDefaultTab() {
|
|
||||||
val defaultDestination =
|
|
||||||
Preferences.getInteger(requireContext(), PREFERENCE_DEFAULT_SELECTED_TAB)
|
|
||||||
val directions =
|
|
||||||
when (requireArguments().getInt("destinationId", defaultDestination)) {
|
|
||||||
R.id.updatesFragment -> {
|
|
||||||
requireArguments().remove("destinationId")
|
|
||||||
SplashFragmentDirections.actionSplashFragmentToUpdatesFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
1 -> SplashFragmentDirections.actionSplashFragmentToGamesContainerFragment()
|
|
||||||
|
|
||||||
2 -> SplashFragmentDirections.actionSplashFragmentToUpdatesFragment()
|
|
||||||
|
|
||||||
else -> SplashFragmentDirections.actionSplashFragmentToNavigationApps()
|
|
||||||
}
|
|
||||||
requireActivity().viewModelStore.clear() // Clear ViewModelStore to avoid bugs with logout
|
|
||||||
findNavController().navigate(directions)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requestAuthTokenForGoogle(accountName: String, oldToken: String? = null) {
|
|
||||||
try {
|
|
||||||
if (oldToken != null) {
|
|
||||||
// Invalidate the old token before requesting a new one
|
|
||||||
AccountManager.get(requireContext()).invalidateAuthToken(
|
|
||||||
GOOGLE_ACCOUNT_TYPE,
|
|
||||||
oldToken
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountManager.get(requireContext())
|
|
||||||
.getAuthToken(
|
|
||||||
Account(accountName, GOOGLE_ACCOUNT_TYPE),
|
|
||||||
GOOGLE_PLAY_AUTH_TOKEN_TYPE,
|
|
||||||
Bundle().apply {
|
|
||||||
putString("overridePackage", PACKAGE_NAME_PLAY_STORE)
|
|
||||||
putByteArray(
|
|
||||||
"overrideCertificate",
|
|
||||||
Base64.decode(GOOGLE_PLAY_CERT, Base64.DEFAULT)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
requireActivity(),
|
|
||||||
{
|
|
||||||
viewModel.buildGoogleAuthData(
|
|
||||||
accountName,
|
|
||||||
it.result.getString(AccountManager.KEY_AUTHTOKEN)!!,
|
|
||||||
AuthHelper.Token.AUTH
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Handler(Looper.getMainLooper())
|
|
||||||
)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.updates
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.extensions.browse
|
|
||||||
import com.aurora.extensions.navigate
|
|
||||||
import com.aurora.extensions.requiresObbDir
|
|
||||||
import com.aurora.store.MobileNavigationDirections
|
|
||||||
import com.aurora.store.R
|
|
||||||
import com.aurora.store.compose.navigation.Screen
|
|
||||||
import com.aurora.store.data.model.MinimalApp
|
|
||||||
import com.aurora.store.data.model.PermissionType
|
|
||||||
import com.aurora.store.data.providers.PermissionProvider.Companion.isGranted
|
|
||||||
import com.aurora.store.data.room.download.Download
|
|
||||||
import com.aurora.store.data.room.update.Update
|
|
||||||
import com.aurora.store.databinding.FragmentUpdatesBinding
|
|
||||||
import com.aurora.store.view.epoxy.views.UpdateHeaderViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.app.AppUpdateViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
|
|
||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
|
||||||
import com.aurora.store.viewmodel.all.UpdatesViewModel
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class UpdatesFragment : BaseFragment<FragmentUpdatesBinding>() {
|
|
||||||
|
|
||||||
private val viewModel: UpdatesViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
// Adjust FAB margins for edgeToEdge display
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.searchFab) { _, windowInsets ->
|
|
||||||
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
|
||||||
binding.searchFab.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
|
||||||
bottomMargin = insets.bottom + resources.getDimensionPixelSize(R.dimen.margin_large)
|
|
||||||
}
|
|
||||||
WindowInsetsCompat.CONSUMED
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolbar
|
|
||||||
binding.toolbar.setOnMenuItemClickListener {
|
|
||||||
when (it.itemId) {
|
|
||||||
R.id.menu_download_manager -> {
|
|
||||||
requireContext().navigate(Screen.Downloads)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.menu_more -> {
|
|
||||||
findNavController().navigate(
|
|
||||||
MobileNavigationDirections.actionGlobalMoreDialogFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
viewModel.updates
|
|
||||||
.combine(viewModel.downloadsList) { uList, dList ->
|
|
||||||
uList?.associateWith { a ->
|
|
||||||
dList.find {
|
|
||||||
it.packageName == a.packageName && it.versionCode == a.versionCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.collectLatest { map ->
|
|
||||||
updateController(map)
|
|
||||||
viewModel.updateAllEnqueued = map?.values?.all {
|
|
||||||
it?.isRunning == true
|
|
||||||
} ?: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
viewModel.fetchingUpdates.collect {
|
|
||||||
binding.swipeRefreshLayout.isRefreshing = it
|
|
||||||
if (it && viewModel.updates.value.isNullOrEmpty()) {
|
|
||||||
updateController(emptyMap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
|
||||||
viewModel.fetchUpdates()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.searchFab.setOnClickListener {
|
|
||||||
requireContext().navigate(Screen.Search)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateController(appList: Map<Update, Download?>?) {
|
|
||||||
binding.recycler.withModels {
|
|
||||||
setFilterDuplicates(true)
|
|
||||||
if (appList == null) {
|
|
||||||
for (i in 1..10) {
|
|
||||||
add(
|
|
||||||
AppListViewShimmerModel_()
|
|
||||||
.id(i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (appList.isEmpty()) {
|
|
||||||
add(
|
|
||||||
NoAppViewModel_()
|
|
||||||
.id("no_update")
|
|
||||||
.icon(R.drawable.ic_updates)
|
|
||||||
.message(R.string.details_no_updates)
|
|
||||||
.showAction(true)
|
|
||||||
.actionMessage(R.string.check_updates)
|
|
||||||
.actionCallback { _ -> viewModel.fetchUpdates() }
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
add(
|
|
||||||
UpdateHeaderViewModel_()
|
|
||||||
.id("header_all")
|
|
||||||
.title(
|
|
||||||
"${appList.size} " +
|
|
||||||
if (appList.size == 1) {
|
|
||||||
getString(R.string.update_available)
|
|
||||||
} else {
|
|
||||||
getString(R.string.updates_available)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.action(
|
|
||||||
if (viewModel.updateAllEnqueued) {
|
|
||||||
getString(R.string.action_cancel)
|
|
||||||
} else {
|
|
||||||
getString(R.string.action_update_all)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.click { _ ->
|
|
||||||
if (viewModel.updateAllEnqueued) {
|
|
||||||
cancelAll()
|
|
||||||
} else {
|
|
||||||
updateAll()
|
|
||||||
}
|
|
||||||
requestModelBuild()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
for ((update, download) in appList) {
|
|
||||||
add(
|
|
||||||
AppUpdateViewModel_()
|
|
||||||
.id(update.packageName)
|
|
||||||
.update(update)
|
|
||||||
.download(download)
|
|
||||||
.click { _ ->
|
|
||||||
if (update.packageName == requireContext().packageName) {
|
|
||||||
requireContext().browse(Constants.GITLAB_URL)
|
|
||||||
} else {
|
|
||||||
openDetailsFragment(update.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.longClick { _ ->
|
|
||||||
openAppMenuSheet(MinimalApp.fromUpdate(update))
|
|
||||||
false
|
|
||||||
}
|
|
||||||
.positiveAction { _ -> updateSingle(update) }
|
|
||||||
.negativeAction { _ -> cancelSingle(update) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateSingle(update: Update) {
|
|
||||||
if (update.fileList.requiresObbDir()) {
|
|
||||||
if (isGranted(requireContext(), PermissionType.STORAGE_MANAGER)) {
|
|
||||||
viewModel.download(update)
|
|
||||||
} else {
|
|
||||||
permissionProvider.request(PermissionType.STORAGE_MANAGER) {
|
|
||||||
if (it) viewModel.download(update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewModel.download(update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateAll() {
|
|
||||||
viewModel.updateAllEnqueued = true
|
|
||||||
if (viewModel.updates.value?.any { it.fileList.requiresObbDir() } == true) {
|
|
||||||
if (isGranted(requireContext(), PermissionType.STORAGE_MANAGER)) {
|
|
||||||
viewModel.downloadAll()
|
|
||||||
} else {
|
|
||||||
permissionProvider.request(PermissionType.STORAGE_MANAGER) {
|
|
||||||
if (it) viewModel.downloadAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewModel.downloadAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cancelSingle(update: Update) {
|
|
||||||
viewModel.cancelDownload(update.packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cancelAll() {
|
|
||||||
viewModel.cancelAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.splash
|
|
||||||
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class SplashFragment : BaseFlavouredSplashFragment()
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Aurora Store
|
|
||||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.aurora.store.view.ui.splash
|
|
||||||
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class SplashFragment : BaseFlavouredSplashFragment()
|
|
||||||
Reference in New Issue
Block a user