Improve dev profile page
This commit is contained in:
@@ -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:101c69ecde")
|
api("com.gitlab.AuroraOSS:gplayapi:-SNAPSHOT")
|
||||||
}
|
}
|
||||||
|
|
||||||
Properties props = new Properties()
|
Properties props = new Properties()
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.epoxy.controller
|
||||||
|
|
||||||
|
import com.aurora.gplayapi.data.models.StreamBundle
|
||||||
|
import com.aurora.gplayapi.data.models.StreamCluster
|
||||||
|
import com.aurora.store.view.epoxy.groups.CarouselShimmerGroup
|
||||||
|
import com.aurora.store.view.epoxy.groups.DeveloperModelGroup
|
||||||
|
|
||||||
|
open class DeveloperCarouselController(private val callbacks: Callbacks) :
|
||||||
|
GenericCarouselController(callbacks) {
|
||||||
|
|
||||||
|
override fun applyFilter(streamBundle: StreamCluster): Boolean {
|
||||||
|
return streamBundle.clusterTitle.isNotBlank() //Filter noisy cluster
|
||||||
|
&& streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildModels(streamBundle: StreamBundle?) {
|
||||||
|
setFilterDuplicates(true)
|
||||||
|
if (streamBundle == null) {
|
||||||
|
for (i in 1..2) {
|
||||||
|
add(
|
||||||
|
CarouselShimmerGroup()
|
||||||
|
.id(i)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
streamBundle
|
||||||
|
.streamClusters
|
||||||
|
.values
|
||||||
|
.filter { applyFilter(it) }
|
||||||
|
.forEach { streamCluster ->
|
||||||
|
add(DeveloperModelGroup(streamCluster, callbacks))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* 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.epoxy.groups
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
|
import com.airbnb.epoxy.EpoxyModelGroup
|
||||||
|
import com.aurora.gplayapi.data.models.StreamCluster
|
||||||
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.util.Log
|
||||||
|
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
||||||
|
import com.aurora.store.view.epoxy.views.AppProgressViewModel_
|
||||||
|
import com.aurora.store.view.epoxy.views.HeaderViewModel_
|
||||||
|
import com.aurora.store.view.epoxy.views.app.AppListViewModel_
|
||||||
|
import com.aurora.store.view.epoxy.views.app.AppViewModel_
|
||||||
|
import com.aurora.store.view.epoxy.views.details.ScreenshotViewModel_
|
||||||
|
|
||||||
|
class DeveloperModelGroup(
|
||||||
|
streamCluster: StreamCluster,
|
||||||
|
callbacks: GenericCarouselController.Callbacks
|
||||||
|
) :
|
||||||
|
EpoxyModelGroup(
|
||||||
|
R.layout.model_developer_carousel_group, buildModels(
|
||||||
|
streamCluster,
|
||||||
|
callbacks
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private fun buildModels(
|
||||||
|
streamCluster: StreamCluster,
|
||||||
|
callbacks: GenericCarouselController.Callbacks
|
||||||
|
): List<EpoxyModel<*>> {
|
||||||
|
val models = ArrayList<EpoxyModel<*>>()
|
||||||
|
val clusterViewModels = mutableListOf<EpoxyModel<*>>()
|
||||||
|
val screenshotsViewModels = mutableListOf<EpoxyModel<*>>()
|
||||||
|
|
||||||
|
val idPrefix = streamCluster.id
|
||||||
|
|
||||||
|
models.add(
|
||||||
|
HeaderViewModel_()
|
||||||
|
.id("${idPrefix}_header")
|
||||||
|
.title(streamCluster.clusterTitle)
|
||||||
|
.browseUrl(streamCluster.clusterBrowseUrl)
|
||||||
|
.click { _ ->
|
||||||
|
callbacks.onHeaderClicked(streamCluster)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (streamCluster.clusterAppList.size == 1) {
|
||||||
|
val app = streamCluster.clusterAppList[0]
|
||||||
|
|
||||||
|
for (artwork in app.screenshots) {
|
||||||
|
screenshotsViewModels.add(
|
||||||
|
ScreenshotViewModel_()
|
||||||
|
.id(artwork.url)
|
||||||
|
.artwork(artwork)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterViewModels.add(
|
||||||
|
AppListViewModel_()
|
||||||
|
.id(app.id)
|
||||||
|
.app(app)
|
||||||
|
.click { _ ->
|
||||||
|
callbacks.onAppClick(app)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
for (app in streamCluster.clusterAppList) {
|
||||||
|
clusterViewModels.add(
|
||||||
|
AppViewModel_()
|
||||||
|
.id(app.id)
|
||||||
|
.app(app)
|
||||||
|
.click { _ ->
|
||||||
|
callbacks.onAppClick(app)
|
||||||
|
}
|
||||||
|
.longClick { _ ->
|
||||||
|
callbacks.onAppLongClick(app)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
.onBind { _, _, position ->
|
||||||
|
val itemCount = clusterViewModels.count()
|
||||||
|
if (itemCount >= 2) {
|
||||||
|
if (position == clusterViewModels.count() - 2) {
|
||||||
|
callbacks.onClusterScrolled(streamCluster)
|
||||||
|
Log.i("Cluster %s Scrolled", streamCluster.clusterTitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screenshotsViewModels.isNotEmpty()) {
|
||||||
|
models.add(
|
||||||
|
CarouselHorizontalModel_()
|
||||||
|
.id("${idPrefix}_screenshots")
|
||||||
|
.models(screenshotsViewModels)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
models.add(
|
||||||
|
CarouselHorizontalModel_()
|
||||||
|
.id("${idPrefix}_cluster")
|
||||||
|
.models(clusterViewModels)
|
||||||
|
)
|
||||||
|
|
||||||
|
return models
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,29 +21,28 @@ package com.aurora.store.view.ui.details
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.airbnb.epoxy.EpoxyModel
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
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.details.DevStream
|
import com.aurora.gplayapi.data.models.details.DevStream
|
||||||
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.ViewState
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
import com.aurora.store.databinding.ActivityDevProfileBinding
|
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.util.extensions.toast
|
import com.aurora.store.view.epoxy.controller.DeveloperCarouselController
|
||||||
import com.aurora.store.view.epoxy.groups.CarouselHorizontalModel_
|
import com.aurora.store.view.epoxy.controller.EarlyAccessCarouselController
|
||||||
import com.aurora.store.view.epoxy.views.app.AppListViewModel_
|
import com.aurora.store.view.epoxy.controller.GenericCarouselController
|
||||||
import com.aurora.store.view.epoxy.views.app.AppViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.HeaderViewModel_
|
|
||||||
import com.aurora.store.view.epoxy.views.details.ScreenshotViewModel_
|
|
||||||
import com.aurora.store.view.ui.commons.BaseActivity
|
import com.aurora.store.view.ui.commons.BaseActivity
|
||||||
import nl.komponents.kovenant.task
|
import com.aurora.store.viewmodel.details.DevProfileViewModel
|
||||||
import nl.komponents.kovenant.ui.failUi
|
|
||||||
import nl.komponents.kovenant.ui.successUi
|
|
||||||
|
|
||||||
class DevProfileActivity : BaseActivity() {
|
class DevProfileActivity : BaseActivity(), GenericCarouselController.Callbacks {
|
||||||
|
|
||||||
private lateinit var B: ActivityDevProfileBinding
|
private lateinit var B: ActivityDevProfileBinding
|
||||||
|
private lateinit var VM: DevProfileViewModel
|
||||||
|
private lateinit var C: DeveloperCarouselController
|
||||||
private lateinit var authData: AuthData
|
private lateinit var authData: AuthData
|
||||||
|
|
||||||
override fun onConnected() {
|
override fun onConnected() {
|
||||||
@@ -60,11 +59,35 @@ class DevProfileActivity : BaseActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
B = ActivityDevProfileBinding.inflate(layoutInflater)
|
B = ActivityDevProfileBinding.inflate(layoutInflater)
|
||||||
|
C = DeveloperCarouselController(this)
|
||||||
|
VM = ViewModelProvider(this).get(DevProfileViewModel::class.java)
|
||||||
|
|
||||||
authData = AuthProvider.with(this).getAuthData()
|
authData = AuthProvider.with(this).getAuthData()
|
||||||
|
|
||||||
setContentView(B.root)
|
setContentView(B.root)
|
||||||
|
|
||||||
attachToolbar()
|
attachToolbar()
|
||||||
|
attachRecycler()
|
||||||
|
|
||||||
|
VM.liveData.observe(this, {
|
||||||
|
when (it) {
|
||||||
|
is ViewState.Empty -> {
|
||||||
|
}
|
||||||
|
is ViewState.Loading -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
is ViewState.Error -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
is ViewState.Status -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
is ViewState.Success<*> -> {
|
||||||
|
updateInfo(it.data as DevStream)
|
||||||
|
updateController(it.data as DevStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
B.viewFlipper.displayedChild = 1
|
B.viewFlipper.displayedChild = 1
|
||||||
|
|
||||||
@@ -79,7 +102,7 @@ class DevProfileActivity : BaseActivity() {
|
|||||||
if (devId.isNullOrEmpty()) {
|
if (devId.isNullOrEmpty()) {
|
||||||
close()
|
close()
|
||||||
} else {
|
} else {
|
||||||
fetchDevProfile(devId)
|
VM.getStreamBundle(devId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -94,86 +117,35 @@ class DevProfileActivity : BaseActivity() {
|
|||||||
B.layoutToolbarAction.txtTitle.text = getString(R.string.details_dev_profile)
|
B.layoutToolbarAction.txtTitle.text = getString(R.string.details_dev_profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun attachRecycler() {
|
||||||
|
B.recycler.setController(C)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateInfo(devStream: DevStream) {
|
private fun updateInfo(devStream: DevStream) {
|
||||||
B.layoutToolbarAction.txtTitle.text = devStream.title
|
B.layoutToolbarAction.txtTitle.text = devStream.title
|
||||||
B.txtDevName.text = devStream.title
|
B.txtDevName.text = devStream.title
|
||||||
B.txtDevDescription.text = devStream.description
|
B.txtDevDescription.text = devStream.description
|
||||||
B.imgIcon.load(devStream.imgUrl)
|
B.imgIcon.load(devStream.imgUrl)
|
||||||
|
B.viewFlipper.displayedChild = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateController(devStream: DevStream) {
|
private fun updateController(devStream: DevStream) {
|
||||||
B.recycler
|
C.setData(devStream.streamBundle)
|
||||||
.withModels {
|
|
||||||
setFilterDuplicates(true)
|
|
||||||
|
|
||||||
for (entry in devStream.appListMap) {
|
|
||||||
val clusterViewModels = mutableListOf<EpoxyModel<*>>()
|
|
||||||
val screenshotsViewModels = mutableListOf<EpoxyModel<*>>()
|
|
||||||
|
|
||||||
if (entry.value.size == 1) {
|
|
||||||
val app = entry.value[0]
|
|
||||||
for (artwork in app.screenshots) {
|
|
||||||
screenshotsViewModels.add(
|
|
||||||
ScreenshotViewModel_()
|
|
||||||
.id(artwork.url)
|
|
||||||
.artwork(artwork)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterViewModels.add(
|
|
||||||
AppListViewModel_()
|
|
||||||
.id(app.id)
|
|
||||||
.app(app)
|
|
||||||
.click { _ ->
|
|
||||||
openDetailsActivity(app)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
for (app in entry.value) {
|
|
||||||
clusterViewModels.add(
|
|
||||||
AppViewModel_()
|
|
||||||
.id(app.id)
|
|
||||||
.app(app)
|
|
||||||
.click { _ ->
|
|
||||||
openDetailsActivity(app)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add(
|
|
||||||
HeaderViewModel_()
|
|
||||||
.id(entry.key)
|
|
||||||
.title(entry.key)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (screenshotsViewModels.isNotEmpty()) {
|
|
||||||
add(
|
|
||||||
CarouselHorizontalModel_()
|
|
||||||
.id("${entry.key}_screenshots")
|
|
||||||
.models(screenshotsViewModels)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
add(
|
|
||||||
CarouselHorizontalModel_()
|
|
||||||
.id("${entry.key}_cluster")
|
|
||||||
.models(clusterViewModels)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchDevProfile(devId: String) {
|
override fun onHeaderClicked(streamCluster: StreamCluster) {
|
||||||
task {
|
openStreamBrowseActivity(streamCluster.clusterBrowseUrl)
|
||||||
AppDetailsHelper(authData).getDeveloperStream(devId)
|
}
|
||||||
} successUi {
|
|
||||||
B.viewFlipper.displayedChild = 0
|
override fun onClusterScrolled(streamCluster: StreamCluster) {
|
||||||
updateInfo(it)
|
VM.observeCluster(streamCluster)
|
||||||
updateController(it)
|
}
|
||||||
} failUi {
|
|
||||||
toast("Dev profile unavailable")
|
override fun onAppClick(app: App) {
|
||||||
close()
|
openDetailsActivity(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAppLongClick(app: App) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.details
|
||||||
|
|
||||||
|
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.StreamBundle
|
||||||
|
import com.aurora.gplayapi.data.models.StreamCluster
|
||||||
|
import com.aurora.gplayapi.data.models.details.DevStream
|
||||||
|
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
||||||
|
import com.aurora.gplayapi.helpers.StreamHelper
|
||||||
|
import com.aurora.store.data.RequestState
|
||||||
|
import com.aurora.store.data.ViewState
|
||||||
|
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 DevProfileViewModel(application: Application) : BaseAndroidViewModel(application) {
|
||||||
|
|
||||||
|
private var authData: AuthData = AuthProvider.with(application).getAuthData()
|
||||||
|
private var appDetailsHelper = AppDetailsHelper(authData).using(HttpClient.getPreferredClient())
|
||||||
|
private var streamHelper = StreamHelper(authData)
|
||||||
|
|
||||||
|
val liveData: MutableLiveData<ViewState> = MutableLiveData()
|
||||||
|
var devStream:DevStream = DevStream()
|
||||||
|
var streamBundle: StreamBundle = StreamBundle()
|
||||||
|
|
||||||
|
lateinit var type: StreamHelper.Type
|
||||||
|
lateinit var category: StreamHelper.Category
|
||||||
|
|
||||||
|
override fun observe() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStreamBundle(
|
||||||
|
devId: String
|
||||||
|
) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
supervisorScope {
|
||||||
|
try {
|
||||||
|
devStream = appDetailsHelper.getDeveloperStream(devId)
|
||||||
|
streamBundle = devStream.streamBundle
|
||||||
|
liveData.postValue(ViewState.Success(devStream))
|
||||||
|
requestState = RequestState.Complete
|
||||||
|
} catch (e: Exception) {
|
||||||
|
requestState = RequestState.Pending
|
||||||
|
liveData.postValue(ViewState.Error(e.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun observeCluster(streamCluster: StreamCluster) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
supervisorScope {
|
||||||
|
try {
|
||||||
|
if (streamCluster.hasNext()) {
|
||||||
|
val newCluster = streamHelper.getNextStreamCluster(streamCluster.clusterNextPageUrl)
|
||||||
|
updateCluster(newCluster)
|
||||||
|
devStream.streamBundle = streamBundle
|
||||||
|
liveData.postValue(ViewState.Success(devStream))
|
||||||
|
} else {
|
||||||
|
Log.i("End of cluster")
|
||||||
|
streamCluster.clusterNextPageUrl = String()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
liveData.postValue(ViewState.Error(e.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCluster(newCluster: StreamCluster) {
|
||||||
|
streamBundle.streamClusters[newCluster.id]?.apply {
|
||||||
|
clusterAppList.addAll(newCluster.clusterAppList)
|
||||||
|
clusterNextPageUrl = newCluster.clusterNextPageUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/src/main/res/layout/model_developer_carousel_group.xml
Normal file
40
app/src/main/res/layout/model_developer_carousel_group.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ 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/>.
|
||||||
|
~
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ViewStub
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inflatedId="@+id/header_view" />
|
||||||
|
|
||||||
|
<ViewStub
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inflatedId="@+id/recycler_view_01" />
|
||||||
|
|
||||||
|
<ViewStub
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inflatedId="@+id/recycler_view_02" />
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user