Add ExpandedStreamBrowse page

This commit is contained in:
Rahul Kumar Patel
2021-02-20 20:39:39 +05:30
parent 833bbb554f
commit 0471e52b65
10 changed files with 287 additions and 14 deletions

View File

@@ -172,7 +172,7 @@ dependencies {
implementation "com.github.topjohnwu.libsu:core:${versions.libsu}" implementation "com.github.topjohnwu.libsu:core:${versions.libsu}"
//Love <3 //Love <3
api("com.gitlab.AuroraOSS:gplayapi:-SNAPSHOT") api("com.gitlab.AuroraOSS:gplayapi:d7ebd3855a")
} }
Properties props = new Properties() Properties props = new Properties()

View File

@@ -143,6 +143,7 @@
<activity android:name=".view.ui.commons.BlacklistActivity" /> <activity android:name=".view.ui.commons.BlacklistActivity" />
<activity android:name=".view.ui.preferences.SettingsActivity" /> <activity android:name=".view.ui.preferences.SettingsActivity" />
<activity android:name=".view.ui.about.AboutActivity" /> <activity android:name=".view.ui.about.AboutActivity" />
<activity android:name=".view.ui.commons.ExpandedStreamBrowseActivity" />
<service android:name=".data.service.NotificationService" /> <service android:name=".data.service.NotificationService" />
<service android:name=".data.installer.InstallerService" /> <service android:name=".data.installer.InstallerService" />

View File

@@ -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.AppDetailsActivity
import com.aurora.store.view.ui.details.DetailsMoreActivity import com.aurora.store.view.ui.details.DetailsMoreActivity
import com.aurora.store.view.ui.details.DetailsReviewActivity 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.aurora.store.view.ui.sheets.NetworkDialogSheet
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
@@ -99,9 +100,15 @@ abstract class BaseActivity : AppCompatActivity(), NetworkProvider.NetworkListen
} }
} }
fun openStreamBrowseActivity(browseUrl: String) { fun openStreamBrowseActivity(browseUrl: String, title: String = "") {
val intent = Intent(this, StreamBrowseActivity::class.java) 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.BROWSE_EXTRA, browseUrl)
intent.putExtra(Constants.STRING_EXTRA, title)
startActivity( startActivity(
intent, intent,
ViewUtil.getEmptyActivityBundle(this) ViewUtil.getEmptyActivityBundle(this)

View File

@@ -28,6 +28,7 @@ import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.Category
import com.aurora.store.util.ViewUtil import com.aurora.store.util.ViewUtil
import com.aurora.store.view.ui.details.AppDetailsActivity 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.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
@@ -63,9 +64,16 @@ open class BaseFragment : Fragment() {
} }
} }
fun openStreamBrowseActivity(browseUrl: String) { fun openStreamBrowseActivity(browseUrl: String, title: String = "") {
val intent = Intent(requireContext(), StreamBrowseActivity::class.java) 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.BROWSE_EXTRA, browseUrl)
intent.putExtra(Constants.STRING_EXTRA, title)
startActivity( startActivity(
intent, intent,
ViewUtil.getEmptyActivityBundle(requireContext()) ViewUtil.getEmptyActivityBundle(requireContext())

View File

@@ -0,0 +1,139 @@
/*
* 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 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")
)
}
}
}
}
}

View File

@@ -46,6 +46,7 @@ class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks {
private lateinit var C: GenericCarouselController private lateinit var C: GenericCarouselController
private lateinit var VM: BaseClusterViewModel private lateinit var VM: BaseClusterViewModel
private lateinit var streamBundle: StreamBundle
private lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener private lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener
private var pageType = 0 private var pageType = 0
@@ -110,11 +111,18 @@ class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks {
} }
is ViewState.Success<*> -> { is ViewState.Success<*> -> {
updateController(it.data as StreamBundle) if (!::streamBundle.isInitialized)
attachRecycler()
streamBundle = it.data as StreamBundle
updateController(streamBundle)
} }
} }
}) })
}
private fun attachRecycler() {
endlessRecyclerOnScrollListener = endlessRecyclerOnScrollListener =
object : EndlessRecyclerOnScrollListener() { object : EndlessRecyclerOnScrollListener() {
override fun onLoadMore(currentPage: Int) { override fun onLoadMore(currentPage: Int) {
@@ -131,7 +139,7 @@ class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks {
override fun onHeaderClicked(streamCluster: StreamCluster) { override fun onHeaderClicked(streamCluster: StreamCluster) {
if (streamCluster.clusterBrowseUrl.isNotEmpty()) if (streamCluster.clusterBrowseUrl.isNotEmpty())
openStreamBrowseActivity(streamCluster.clusterBrowseUrl) openStreamBrowseActivity(streamCluster.clusterBrowseUrl, streamCluster.clusterTitle)
else else
Toast.makeText(requireContext(), "Browse page unavailable", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Browse page unavailable", Toast.LENGTH_SHORT).show()
} }

View File

@@ -26,8 +26,8 @@ import com.aurora.gplayapi.data.models.StreamCluster
import com.aurora.store.databinding.ActivityGenericRecyclerBinding import com.aurora.store.databinding.ActivityGenericRecyclerBinding
import com.aurora.store.util.extensions.close import com.aurora.store.util.extensions.close
import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener 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.AppProgressViewModel_
import com.aurora.store.view.epoxy.views.app.AppListViewModel_
import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_ import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_
import com.aurora.store.viewmodel.browse.StreamBrowseViewModel import com.aurora.store.viewmodel.browse.StreamBrowseViewModel
@@ -40,6 +40,7 @@ class StreamBrowseActivity : BaseActivity() {
lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener lateinit var endlessRecyclerOnScrollListener: EndlessRecyclerOnScrollListener
lateinit var title: String lateinit var title: String
lateinit var cluster: StreamCluster
override fun onConnected() { override fun onConnected() {
hideNetworkConnectivitySheet() hideNetworkConnectivitySheet()
@@ -63,11 +64,15 @@ class StreamBrowseActivity : BaseActivity() {
setContentView(B.root) setContentView(B.root)
attachToolbar() attachToolbar()
attachRecycler()
VM.liveData.observe(this, { VM.liveData.observe(this, {
updateController(it) if (!::cluster.isInitialized)
updateTitle(it) attachRecycler()
cluster = it
updateController(cluster)
updateTitle(cluster)
}) })
intent.apply { intent.apply {

View File

@@ -294,7 +294,10 @@ abstract class BaseDetailsActivity : BaseActivity() {
DetailsCarouselController(object : GenericCarouselController.Callbacks { DetailsCarouselController(object : GenericCarouselController.Callbacks {
override fun onHeaderClicked(streamCluster: StreamCluster) { override fun onHeaderClicked(streamCluster: StreamCluster) {
if (streamCluster.clusterBrowseUrl.isNotEmpty()) if (streamCluster.clusterBrowseUrl.isNotEmpty())
openStreamBrowseActivity(streamCluster.clusterBrowseUrl) openStreamBrowseActivity(
streamCluster.clusterBrowseUrl,
streamCluster.clusterTitle
)
else else
toast("Browse page unavailable") toast("Browse page unavailable")
} }

View File

@@ -22,6 +22,7 @@ package com.aurora.store.view.ui.details
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.aurora.Constants
import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.StreamCluster 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.close
import com.aurora.store.util.extensions.load import com.aurora.store.util.extensions.load
import com.aurora.store.view.epoxy.controller.DeveloperCarouselController 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.epoxy.controller.GenericCarouselController
import com.aurora.store.view.ui.commons.BaseActivity import com.aurora.store.view.ui.commons.BaseActivity
import com.aurora.store.viewmodel.details.DevProfileViewModel import com.aurora.store.viewmodel.details.DevProfileViewModel
@@ -104,6 +104,13 @@ class DevProfileActivity : BaseActivity(), GenericCarouselController.Callbacks {
} else { } else {
VM.getStreamBundle(devId) 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 { } else {
close() close()
@@ -134,7 +141,7 @@ class DevProfileActivity : BaseActivity(), GenericCarouselController.Callbacks {
} }
override fun onHeaderClicked(streamCluster: StreamCluster) { override fun onHeaderClicked(streamCluster: StreamCluster) {
openStreamBrowseActivity(streamCluster.clusterBrowseUrl) openStreamBrowseActivity(streamCluster.clusterBrowseUrl, streamCluster.clusterTitle)
} }
override fun onClusterScrolled(streamCluster: StreamCluster) { override fun onClusterScrolled(streamCluster: StreamCluster) {

View File

@@ -0,0 +1,95 @@
/*
* 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.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<StreamCluster> = 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
}
}
}
}
}