viewmodel: details: Relocate and rename viewmodels

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-09-17 11:14:41 +05:30
parent 36bc7a868a
commit e45999b9bc
9 changed files with 36 additions and 163 deletions

View File

@@ -34,16 +34,16 @@ import com.aurora.store.compose.composables.details.ExodusComposable
import com.aurora.store.compose.preview.AppPreviewProvider import com.aurora.store.compose.preview.AppPreviewProvider
import com.aurora.store.data.model.ExodusTracker import com.aurora.store.data.model.ExodusTracker
import com.aurora.store.viewmodel.details.AppDetailsViewModel import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.details.DetailsExodusViewModel import com.aurora.store.viewmodel.details.ExodusViewModel
@Composable @Composable
fun ExodusScreen( fun ExodusScreen(
packageName: String, packageName: String,
onNavigateUp: () -> Unit, onNavigateUp: () -> Unit,
appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName),
detailsExodusViewModel: DetailsExodusViewModel = hiltViewModel( exodusViewModel: ExodusViewModel = hiltViewModel(
key = "$packageName/exodus", key = "$packageName/exodus",
creationCallback = { factory: DetailsExodusViewModel.Factory -> creationCallback = { factory: ExodusViewModel.Factory ->
factory.create(appDetailsViewModel.exodusReport.value!!) factory.create(appDetailsViewModel.exodusReport.value!!)
} }
), ),
@@ -51,7 +51,7 @@ fun ExodusScreen(
) { ) {
val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
val exodusReport by appDetailsViewModel.exodusReport.collectAsStateWithLifecycle() val exodusReport by appDetailsViewModel.exodusReport.collectAsStateWithLifecycle()
val trackers by detailsExodusViewModel.trackers.collectAsStateWithLifecycle() val trackers by exodusViewModel.trackers.collectAsStateWithLifecycle()
val topAppBarTitle = when { val topAppBarTitle = when {
windowAdaptiveInfo.isWindowCompact -> app!!.displayName windowAdaptiveInfo.isWindowCompact -> app!!.displayName

View File

@@ -43,7 +43,7 @@ import com.aurora.store.compose.composables.app.AppComposable
import com.aurora.store.compose.preview.AppPreviewProvider import com.aurora.store.compose.preview.AppPreviewProvider
import com.aurora.store.compose.preview.coilPreviewProvider import com.aurora.store.compose.preview.coilPreviewProvider
import com.aurora.store.viewmodel.details.AppDetailsViewModel import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.details.DetailsMoreViewModel import com.aurora.store.viewmodel.details.MoreViewModel
import java.util.Locale import java.util.Locale
@Composable @Composable
@@ -52,15 +52,15 @@ fun MoreScreen(
onNavigateUp: () -> Unit, onNavigateUp: () -> Unit,
onNavigateToAppDetails: (packageName: String) -> Unit, onNavigateToAppDetails: (packageName: String) -> Unit,
appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName),
detailsMoreViewModel: DetailsMoreViewModel = hiltViewModel( moreViewModel: MoreViewModel = hiltViewModel(
key = "$packageName/more", key = "$packageName/more",
creationCallback = { factory: DetailsMoreViewModel.Factory -> creationCallback = { factory: MoreViewModel.Factory ->
factory.create(appDetailsViewModel.app.value!!.dependencies.dependentPackages) factory.create(appDetailsViewModel.app.value!!.dependencies.dependentPackages)
} }
) )
) { ) {
val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
val dependencies by detailsMoreViewModel.dependentApps.collectAsStateWithLifecycle() val dependencies by moreViewModel.dependentApps.collectAsStateWithLifecycle()
ScreenContent( ScreenContent(
app = app!!, app = app!!,

View File

@@ -33,7 +33,7 @@ import com.aurora.store.compose.composables.InfoComposable
import com.aurora.store.compose.composables.TopAppBarComposable import com.aurora.store.compose.composables.TopAppBarComposable
import com.aurora.store.compose.preview.AppPreviewProvider import com.aurora.store.compose.preview.AppPreviewProvider
import com.aurora.store.viewmodel.details.AppDetailsViewModel import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.details.DetailsPermissionViewModel import com.aurora.store.viewmodel.details.PermissionViewModel
import java.util.Locale import java.util.Locale
@Composable @Composable
@@ -41,16 +41,16 @@ fun PermissionScreen(
packageName: String, packageName: String,
onNavigateUp: () -> Unit, onNavigateUp: () -> Unit,
appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName),
detailsPermissionViewModel: DetailsPermissionViewModel = hiltViewModel( permissionViewModel: PermissionViewModel = hiltViewModel(
key = "$packageName/permission", key = "$packageName/permission",
creationCallback = { factory: DetailsPermissionViewModel.Factory -> creationCallback = { factory: PermissionViewModel.Factory ->
factory.create(appDetailsViewModel.app.value!!.permissions) factory.create(appDetailsViewModel.app.value!!.permissions)
} }
), ),
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
) { ) {
val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
val permissionsInfo by detailsPermissionViewModel.permissionsInfo.collectAsStateWithLifecycle() val permissionsInfo by permissionViewModel.permissionsInfo.collectAsStateWithLifecycle()
val topAppBarTitle = when { val topAppBarTitle = when {
windowAdaptiveInfo.isWindowCompact -> app!!.displayName windowAdaptiveInfo.isWindowCompact -> app!!.displayName

View File

@@ -49,7 +49,7 @@ import com.aurora.store.compose.composables.details.ReviewComposable
import com.aurora.store.compose.preview.ReviewPreviewProvider import com.aurora.store.compose.preview.ReviewPreviewProvider
import com.aurora.store.compose.preview.coilPreviewProvider import com.aurora.store.compose.preview.coilPreviewProvider
import com.aurora.store.viewmodel.details.AppDetailsViewModel import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.review.DetailsReviewViewModel import com.aurora.store.viewmodel.details.ReviewViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlin.random.Random import kotlin.random.Random
@@ -58,16 +58,16 @@ fun ReviewScreen(
packageName: String, packageName: String,
onNavigateUp: () -> Unit, onNavigateUp: () -> Unit,
appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName),
detailsReviewViewModel: DetailsReviewViewModel = hiltViewModel( reviewViewModel: ReviewViewModel = hiltViewModel(
key = "$packageName/review", key = "$packageName/review",
creationCallback = { factory: DetailsReviewViewModel.Factory -> creationCallback = { factory: ReviewViewModel.Factory ->
factory.create(appDetailsViewModel.app.value!!.packageName) factory.create(appDetailsViewModel.app.value!!.packageName)
} }
), ),
windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo()
) { ) {
val app by appDetailsViewModel.app.collectAsStateWithLifecycle() val app by appDetailsViewModel.app.collectAsStateWithLifecycle()
val reviews = detailsReviewViewModel.reviews.collectAsLazyPagingItems() val reviews = reviewViewModel.reviews.collectAsLazyPagingItems()
val topAppBarTitle = when { val topAppBarTitle = when {
windowAdaptiveInfo.isWindowCompact -> app!!.displayName windowAdaptiveInfo.isWindowCompact -> app!!.displayName
@@ -78,7 +78,7 @@ fun ReviewScreen(
topAppBarTitle = topAppBarTitle, topAppBarTitle = topAppBarTitle,
reviews = reviews, reviews = reviews,
onNavigateUp = onNavigateUp, onNavigateUp = onNavigateUp,
onFilter = { filter -> detailsReviewViewModel.fetchReviews(filter) } onFilter = { filter -> reviewViewModel.fetchReviews(filter) }
) )
} }

View File

@@ -1,126 +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.viewmodel.details
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aurora.gplayapi.data.models.StreamBundle
import com.aurora.gplayapi.data.models.StreamCluster
import com.aurora.gplayapi.helpers.AppDetailsHelper
import com.aurora.gplayapi.helpers.StreamHelper
import com.aurora.gplayapi.helpers.contracts.StreamContract
import com.aurora.store.AppStreamStash
import com.aurora.store.data.model.ViewState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import javax.inject.Inject
@HiltViewModel
class DetailsClusterViewModel @Inject constructor(
private val appDetailsHelper: AppDetailsHelper,
private val streamHelper: StreamHelper
) : ViewModel() {
private val TAG = DetailsClusterViewModel::class.java.simpleName
val liveData: MutableLiveData<ViewState> = MutableLiveData()
private val stash: AppStreamStash = mutableMapOf()
lateinit var type: StreamContract.Type
lateinit var category: StreamContract.Category
fun getStreamBundle(streamUrl: String) {
viewModelScope.launch(Dispatchers.IO) {
supervisorScope {
val bundle = targetBundle(streamUrl)
if (bundle.streamClusters.isNotEmpty()) {
liveData.postValue(ViewState.Success(stash))
}
try {
if (!bundle.hasCluster() || bundle.hasNext()) {
val newBundle = appDetailsHelper.getDetailsStream(streamUrl)
val mergedBundle = bundle.copy(
streamClusters = bundle.streamClusters + newBundle.streamClusters,
streamNextPageUrl = newBundle.streamNextPageUrl
)
stash[streamUrl] = mergedBundle
liveData.postValue(ViewState.Success(stash))
}
} catch (e: Exception) {
liveData.postValue(ViewState.Error(e.message))
}
}
}
}
fun observeCluster(url: String, streamCluster: StreamCluster) {
viewModelScope.launch(Dispatchers.IO) {
supervisorScope {
try {
if (streamCluster.hasNext()) {
val newCluster =
streamHelper.getNextStreamCluster(streamCluster.clusterNextPageUrl)
updateCluster(url, streamCluster.id, newCluster)
liveData.postValue(ViewState.Success(stash))
} else {
Log.i(TAG, "End of cluster")
}
} catch (e: Exception) {
liveData.postValue(ViewState.Error(e.message))
}
}
}
}
private fun updateCluster(
url: String,
clusterID: Int,
newCluster: StreamCluster
) {
val bundle = targetBundle(url)
bundle.streamClusters[clusterID]?.let { oldCluster ->
val mergedCluster = oldCluster.copy(
clusterNextPageUrl = newCluster.clusterNextPageUrl,
clusterAppList = oldCluster.clusterAppList + newCluster.clusterAppList
)
val newStreamClusters = bundle.streamClusters.toMutableMap().apply {
this[clusterID] = mergedCluster
}
stash.put(url, bundle.copy(streamClusters = newStreamClusters))
}
}
private fun targetBundle(url: String): StreamBundle {
val streamBundle = stash.getOrPut(url) {
StreamBundle()
}
return streamBundle
}
}

View File

@@ -19,15 +19,15 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.json.JSONObject import org.json.JSONObject
@HiltViewModel(assistedFactory = DetailsExodusViewModel.Factory::class) @HiltViewModel(assistedFactory = ExodusViewModel.Factory::class)
class DetailsExodusViewModel @AssistedInject constructor( class ExodusViewModel @AssistedInject constructor(
@Assisted private val exodusReport: Report, @Assisted private val exodusReport: Report,
private val exodusTrackers: JSONObject private val exodusTrackers: JSONObject
) : ViewModel() { ) : ViewModel() {
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create(exodusReport: Report): DetailsExodusViewModel fun create(exodusReport: Report): ExodusViewModel
} }
private val _trackers = MutableStateFlow<List<ExodusTracker>>(emptyList()) private val _trackers = MutableStateFlow<List<ExodusTracker>>(emptyList())

View File

@@ -20,18 +20,18 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@HiltViewModel(assistedFactory = DetailsMoreViewModel.Factory::class) @HiltViewModel(assistedFactory = MoreViewModel.Factory::class)
class DetailsMoreViewModel @AssistedInject constructor( class MoreViewModel @AssistedInject constructor(
@Assisted private val dependencies: List<String>, @Assisted private val dependencies: List<String>,
private val appDetailsHelper: AppDetailsHelper private val appDetailsHelper: AppDetailsHelper
) : ViewModel() { ) : ViewModel() {
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create(dependencies: List<String>): DetailsMoreViewModel fun create(dependencies: List<String>): MoreViewModel
} }
private val TAG = DetailsMoreViewModel::class.java.simpleName private val TAG = MoreViewModel::class.java.simpleName
private val _dependentApps = MutableStateFlow<List<App>?>(emptyList()) private val _dependentApps = MutableStateFlow<List<App>?>(emptyList())
val dependentApps = _dependentApps.asStateFlow() val dependentApps = _dependentApps.asStateFlow()

View File

@@ -17,15 +17,15 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@HiltViewModel(assistedFactory = DetailsPermissionViewModel.Factory::class) @HiltViewModel(assistedFactory = PermissionViewModel.Factory::class)
class DetailsPermissionViewModel @AssistedInject constructor( class PermissionViewModel @AssistedInject constructor(
@Assisted private val permissions: List<String>, @Assisted private val permissions: List<String>,
@ApplicationContext private val context: Context @ApplicationContext private val context: Context
): ViewModel() { ): ViewModel() {
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create(permissions: List<String>): DetailsPermissionViewModel fun create(permissions: List<String>): PermissionViewModel
} }
private val _permissionsInfo = MutableStateFlow<Map<String, PermissionInfo?>>(emptyMap()) private val _permissionsInfo = MutableStateFlow<Map<String, PermissionInfo?>>(emptyMap())

View File

@@ -1,10 +1,9 @@
/* /*
* SPDX-FileCopyrightText: 2021-2023 AuroraOSS * SPDX-FileCopyrightText: 2025 The Calyx Institute
* SPDX-FileCopyrightText: 2024-2025 The Calyx Institute
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
package com.aurora.store.viewmodel.review package com.aurora.store.viewmodel.details
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -13,7 +12,7 @@ import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import com.aurora.gplayapi.data.models.Review import com.aurora.gplayapi.data.models.Review
import com.aurora.gplayapi.helpers.ReviewsHelper import com.aurora.gplayapi.helpers.ReviewsHelper
import com.aurora.store.data.paging.GenericPagingSource.Companion.createPager import com.aurora.store.data.paging.GenericPagingSource
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
@@ -24,20 +23,20 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@HiltViewModel(assistedFactory = DetailsReviewViewModel.Factory::class) @HiltViewModel(assistedFactory = ReviewViewModel.Factory::class)
class DetailsReviewViewModel @AssistedInject constructor( class ReviewViewModel @AssistedInject constructor(
@Assisted private val packageName: String, @Assisted private val packageName: String,
private val reviewsHelper: ReviewsHelper private val reviewsHelper: ReviewsHelper
) : ViewModel() { ) : ViewModel() {
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create(packageName: String): DetailsReviewViewModel fun create(packageName: String): ReviewViewModel
} }
private val TAG = DetailsReviewViewModel::class.java.simpleName private val TAG = ReviewViewModel::class.java.simpleName
private val _reviews = MutableStateFlow<PagingData<Review>>(PagingData.empty()) private val _reviews = MutableStateFlow<PagingData<Review>>(PagingData.Companion.empty())
val reviews = _reviews.asStateFlow() val reviews = _reviews.asStateFlow()
init { init {
@@ -47,7 +46,7 @@ class DetailsReviewViewModel @AssistedInject constructor(
fun fetchReviews(filter: Review.Filter = Review.Filter.ALL) { fun fetchReviews(filter: Review.Filter = Review.Filter.ALL) {
var reviewsNextPageUrl: String? = null var reviewsNextPageUrl: String? = null
createPager { page -> GenericPagingSource.Companion.createPager { page ->
try { try {
when (page) { when (page) {
1 -> reviewsHelper.getReviews(packageName, filter).also { 1 -> reviewsHelper.getReviews(packageName, filter).also {