diff --git a/app/build.gradle b/app/build.gradle index 6ff2be0b2..fb327432f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -172,7 +172,7 @@ dependencies { implementation "com.github.topjohnwu.libsu:core:${versions.libsu}" //Love <3 - api("com.gitlab.AuroraOSS:gplayapi:-SNAPSHOT") + api("com.gitlab.AuroraOSS:gplayapi:d7ebd3855a") } Properties props = new Properties() diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3541cc4b3..bc0365138 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -143,6 +143,7 @@ + diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/BaseActivity.kt b/app/src/main/java/com/aurora/store/view/ui/commons/BaseActivity.kt index f74cb3fc6..76410ac11 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/BaseActivity.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/BaseActivity.kt @@ -37,6 +37,7 @@ import com.aurora.store.view.ui.account.GoogleActivity import com.aurora.store.view.ui.details.AppDetailsActivity import com.aurora.store.view.ui.details.DetailsMoreActivity import com.aurora.store.view.ui.details.DetailsReviewActivity +import com.aurora.store.view.ui.details.DevProfileActivity import com.aurora.store.view.ui.sheets.NetworkDialogSheet import com.google.gson.Gson import com.google.gson.GsonBuilder @@ -99,9 +100,15 @@ abstract class BaseActivity : AppCompatActivity(), NetworkProvider.NetworkListen } } - fun openStreamBrowseActivity(browseUrl: String) { - val intent = Intent(this, StreamBrowseActivity::class.java) + fun openStreamBrowseActivity(browseUrl: String, title: String = "") { + val intent = if (browseUrl.toLowerCase().contains("expanded")) + Intent(this, ExpandedStreamBrowseActivity::class.java) + else if (browseUrl.toLowerCase().contains("developer")) + Intent(this, DevProfileActivity::class.java) + else + Intent(this, StreamBrowseActivity::class.java) intent.putExtra(Constants.BROWSE_EXTRA, browseUrl) + intent.putExtra(Constants.STRING_EXTRA, title) startActivity( intent, ViewUtil.getEmptyActivityBundle(this) diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt index d8c414009..de92113f9 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt @@ -28,6 +28,7 @@ import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.Category import com.aurora.store.util.ViewUtil import com.aurora.store.view.ui.details.AppDetailsActivity +import com.aurora.store.view.ui.details.DevProfileActivity import com.google.gson.Gson import com.google.gson.GsonBuilder import java.lang.reflect.Modifier @@ -63,9 +64,16 @@ open class BaseFragment : Fragment() { } } - fun openStreamBrowseActivity(browseUrl: String) { - val intent = Intent(requireContext(), StreamBrowseActivity::class.java) + fun openStreamBrowseActivity(browseUrl: String, title: String = "") { + val intent = if (browseUrl.toLowerCase().contains("expanded")) + Intent(requireContext(), ExpandedStreamBrowseActivity::class.java) + else if (browseUrl.toLowerCase().contains("developer")) + Intent(requireContext(), DevProfileActivity::class.java) + else + Intent(requireContext(), StreamBrowseActivity::class.java) + intent.putExtra(Constants.BROWSE_EXTRA, browseUrl) + intent.putExtra(Constants.STRING_EXTRA, title) startActivity( intent, ViewUtil.getEmptyActivityBundle(requireContext()) diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseActivity.kt b/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseActivity.kt new file mode 100644 index 000000000..48550f9f6 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseActivity.kt @@ -0,0 +1,139 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.commons + +import android.os.Bundle +import androidx.lifecycle.ViewModelProvider +import com.aurora.Constants +import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.store.databinding.ActivityGenericRecyclerBinding +import com.aurora.store.util.extensions.close +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 + + +class ExpandedStreamBrowseActivity : BaseActivity() { + + lateinit var B: ActivityGenericRecyclerBinding + lateinit var VM: ExpandedStreamBrowseViewModel + + lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener + + lateinit var title: String + lateinit var cluster: StreamCluster + + override fun onConnected() { + hideNetworkConnectivitySheet() + } + + override fun onDisconnected() { + showNetworkConnectivitySheet() + } + + override fun onReconnected() { + + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + B = ActivityGenericRecyclerBinding.inflate(layoutInflater) + VM = ViewModelProvider(this).get(ExpandedStreamBrowseViewModel::class.java) + + setContentView(B.root) + + attachToolbar() + + VM.liveData.observe(this, { + if (!::cluster.isInitialized) + attachRecycler() + + cluster = it + + updateController(cluster) + updateTitle(cluster) + }) + + intent.apply { + getStringExtra(Constants.BROWSE_EXTRA)?.let { + VM.getInitialCluster(it) + } + getStringExtra(Constants.STRING_EXTRA)?.let { + B.layoutToolbarAction.txtTitle.text = it + } + } + + updateController(null) + } + + private fun updateTitle(streamCluster: StreamCluster) { + if (streamCluster.clusterTitle.isNotEmpty()) + B.layoutToolbarAction.txtTitle.text = streamCluster.clusterTitle + } + + private fun attachToolbar() { + B.layoutToolbarAction.imgActionPrimary.setOnClickListener { + close() + } + } + + private fun attachRecycler() { + endlessRecyclerOnScrollListener = object : EndlessRecyclerOnScrollListener() { + override fun onLoadMore(currentPage: Int) { + VM.next() + } + } + B.recycler.addOnScrollListener(endlessRecyclerOnScrollListener) + } + + private fun updateController(streamCluster: StreamCluster?) { + B.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 { _ -> openDetailsActivity(it) } + ) + } + + if (streamCluster.hasNext()) { + add( + AppProgressViewModel_() + .id("progress") + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt index f27390f39..2adbc0ce1 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt @@ -46,6 +46,7 @@ class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks { private lateinit var C: GenericCarouselController private lateinit var VM: BaseClusterViewModel + private lateinit var streamBundle: StreamBundle private lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener private var pageType = 0 @@ -110,11 +111,18 @@ class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks { } is ViewState.Success<*> -> { - updateController(it.data as StreamBundle) + if (!::streamBundle.isInitialized) + attachRecycler() + + streamBundle = it.data as StreamBundle + + updateController(streamBundle) } } }) + } + private fun attachRecycler() { endlessRecyclerOnScrollListener = object : EndlessRecyclerOnScrollListener() { override fun onLoadMore(currentPage: Int) { @@ -131,7 +139,7 @@ class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks { override fun onHeaderClicked(streamCluster: StreamCluster) { if (streamCluster.clusterBrowseUrl.isNotEmpty()) - openStreamBrowseActivity(streamCluster.clusterBrowseUrl) + openStreamBrowseActivity(streamCluster.clusterBrowseUrl, streamCluster.clusterTitle) else Toast.makeText(requireContext(), "Browse page unavailable", Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseActivity.kt b/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseActivity.kt index ec3bd8f3b..049403e1b 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseActivity.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/StreamBrowseActivity.kt @@ -26,8 +26,8 @@ import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.store.databinding.ActivityGenericRecyclerBinding import com.aurora.store.util.extensions.close import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener -import com.aurora.store.view.epoxy.views.app.AppListViewModel_ 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.StreamBrowseViewModel @@ -40,6 +40,7 @@ class StreamBrowseActivity : BaseActivity() { lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener lateinit var title: String + lateinit var cluster: StreamCluster override fun onConnected() { hideNetworkConnectivitySheet() @@ -63,11 +64,15 @@ class StreamBrowseActivity : BaseActivity() { setContentView(B.root) attachToolbar() - attachRecycler() VM.liveData.observe(this, { - updateController(it) - updateTitle(it) + if (!::cluster.isInitialized) + attachRecycler() + + cluster = it + + updateController(cluster) + updateTitle(cluster) }) intent.apply { diff --git a/app/src/main/java/com/aurora/store/view/ui/details/BaseDetailsActivity.kt b/app/src/main/java/com/aurora/store/view/ui/details/BaseDetailsActivity.kt index ae385c979..66081011f 100644 --- a/app/src/main/java/com/aurora/store/view/ui/details/BaseDetailsActivity.kt +++ b/app/src/main/java/com/aurora/store/view/ui/details/BaseDetailsActivity.kt @@ -294,7 +294,10 @@ abstract class BaseDetailsActivity : BaseActivity() { DetailsCarouselController(object : GenericCarouselController.Callbacks { override fun onHeaderClicked(streamCluster: StreamCluster) { if (streamCluster.clusterBrowseUrl.isNotEmpty()) - openStreamBrowseActivity(streamCluster.clusterBrowseUrl) + openStreamBrowseActivity( + streamCluster.clusterBrowseUrl, + streamCluster.clusterTitle + ) else toast("Browse page unavailable") } diff --git a/app/src/main/java/com/aurora/store/view/ui/details/DevProfileActivity.kt b/app/src/main/java/com/aurora/store/view/ui/details/DevProfileActivity.kt index 00eec1b12..f7ec2519c 100644 --- a/app/src/main/java/com/aurora/store/view/ui/details/DevProfileActivity.kt +++ b/app/src/main/java/com/aurora/store/view/ui/details/DevProfileActivity.kt @@ -22,6 +22,7 @@ package com.aurora.store.view.ui.details import android.content.Intent import android.os.Bundle import androidx.lifecycle.ViewModelProvider +import com.aurora.Constants import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.StreamCluster @@ -33,7 +34,6 @@ import com.aurora.store.databinding.ActivityDevProfileBinding import com.aurora.store.util.extensions.close import com.aurora.store.util.extensions.load import com.aurora.store.view.epoxy.controller.DeveloperCarouselController -import com.aurora.store.view.epoxy.controller.EarlyAccessCarouselController import com.aurora.store.view.epoxy.controller.GenericCarouselController import com.aurora.store.view.ui.commons.BaseActivity import com.aurora.store.viewmodel.details.DevProfileViewModel @@ -104,6 +104,13 @@ class DevProfileActivity : BaseActivity(), GenericCarouselController.Callbacks { } else { VM.getStreamBundle(devId) } + } else { + intent.getStringExtra(Constants.BROWSE_EXTRA)?.let { + VM.getStreamBundle(it.substringAfter("developer-")) + } + intent.getStringExtra(Constants.STRING_EXTRA)?.let { + B.layoutToolbarAction.txtTitle.text = it + } } } else { close() @@ -134,7 +141,7 @@ class DevProfileActivity : BaseActivity(), GenericCarouselController.Callbacks { } override fun onHeaderClicked(streamCluster: StreamCluster) { - openStreamBrowseActivity(streamCluster.clusterBrowseUrl) + openStreamBrowseActivity(streamCluster.clusterBrowseUrl, streamCluster.clusterTitle) } override fun onClusterScrolled(streamCluster: StreamCluster) { diff --git a/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt new file mode 100644 index 000000000..e3a022fe6 --- /dev/null +++ b/app/src/main/java/com/aurora/store/viewmodel/browse/ExpandedStreamBrowseViewModel.kt @@ -0,0 +1,95 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.viewmodel.browse + +import android.app.Application +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.helpers.ExpandedBrowseHelper +import com.aurora.store.data.RequestState +import com.aurora.store.data.network.HttpClient +import com.aurora.store.data.providers.AuthProvider +import com.aurora.store.util.Log +import com.aurora.store.viewmodel.BaseAndroidViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope + +class ExpandedStreamBrowseViewModel(application: Application) : BaseAndroidViewModel(application) { + + private val authData: AuthData = AuthProvider.with(application).getAuthData() + private val streamHelper: ExpandedBrowseHelper = ExpandedBrowseHelper(authData) + .using(HttpClient.getPreferredClient()) + + val liveData: MutableLiveData = MutableLiveData() + var streamCluster: StreamCluster = StreamCluster() + + override fun observe() { + requestState = RequestState.Init + } + + fun getInitialCluster(expandedStreamUrl: String) { + viewModelScope.launch(Dispatchers.IO) { + supervisorScope { + try { + val browseResponse = streamHelper.getBrowseStreamResponse(expandedStreamUrl) + if (browseResponse.hasBrowseTab()) { + streamCluster = + streamHelper.getExpandedBrowseClusters(browseResponse.browseTab.listUrl) + liveData.postValue(streamCluster) + } else { + requestState = RequestState.Complete + } + } catch (e: Exception) { + requestState = RequestState.Pending + } + } + } + } + + fun next() { + Log.e("NEXT CALED") + viewModelScope.launch(Dispatchers.IO) { + supervisorScope { + try { + val newCluster = streamHelper.getExpandedBrowseClusters( + streamCluster.clusterNextPageUrl + ) + + streamCluster.apply { + clusterAppList.addAll(newCluster.clusterAppList) + clusterNextPageUrl = newCluster.clusterNextPageUrl + } + + liveData.postValue(streamCluster) + + if (!streamCluster.hasNext()) { + Log.i("End of Bundle") + requestState = RequestState.Complete + } + } catch (e: Exception) { + requestState = RequestState.Pending + } + } + } + } +}