Skip to content

Commit

Permalink
feat: added a new use case to fetch the user quota as Flow (`GetStore…
Browse files Browse the repository at this point in the history
…dQuotaAsStreamUseCase`)
  • Loading branch information
joragua committed Dec 11, 2024
1 parent afa1aea commit e7e2c94
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @author Abel García de Prada
* @author Juan Carlos Garrote Gascón
* @author Aitor Ballesteros Pavón
* @author Jorge Aguado Recio
*
* Copyright (C) 2024 ownCloud GmbH.
*
Expand Down Expand Up @@ -101,6 +102,7 @@ import com.owncloud.android.domain.transfers.usecases.GetAllTransfersAsStreamUse
import com.owncloud.android.domain.transfers.usecases.GetAllTransfersUseCase
import com.owncloud.android.domain.transfers.usecases.UpdatePendingUploadsPathUseCase
import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase
import com.owncloud.android.domain.user.usecases.GetStoredQuotaAsStreamUseCase
import com.owncloud.android.domain.user.usecases.GetUserAvatarAsyncUseCase
import com.owncloud.android.domain.user.usecases.GetUserInfoAsyncUseCase
import com.owncloud.android.domain.user.usecases.GetUserQuotasUseCase
Expand Down Expand Up @@ -252,6 +254,7 @@ val useCaseModule = module {
factoryOf(::UploadFilesFromSystemUseCase)

// User
factoryOf(::GetStoredQuotaAsStreamUseCase)
factoryOf(::GetStoredQuotaUseCase)
factoryOf(::GetUserAvatarAsyncUseCase)
factoryOf(::GetUserInfoAsyncUseCase)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,65 +25,43 @@ package com.owncloud.android.presentation.common

import android.accounts.Account
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.owncloud.android.R
import com.owncloud.android.data.providers.LocalStorageProvider
import com.owncloud.android.domain.user.model.UserQuota
import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase
import com.owncloud.android.domain.user.usecases.GetStoredQuotaAsStreamUseCase
import com.owncloud.android.domain.user.usecases.GetUserQuotasUseCase
import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.ViewModelExt.runUseCaseWithResult
import com.owncloud.android.presentation.authentication.AccountUtils
import com.owncloud.android.providers.ContextProvider
import com.owncloud.android.providers.CoroutinesDispatcherProvider
import com.owncloud.android.usecases.accounts.RemoveAccountUseCase
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import timber.log.Timber

class DrawerViewModel(
private val getStoredQuotaUseCase: GetStoredQuotaUseCase,
getStoredQuotaAsStreamUseCase: GetStoredQuotaAsStreamUseCase,
private val removeAccountUseCase: RemoveAccountUseCase,
private val getUserQuotasUseCase: GetUserQuotasUseCase,
private val localStorageProvider: LocalStorageProvider,
private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider,
private val contextProvider: ContextProvider,
accountName: String,
) : ViewModel() {

private val _userQuota = MediatorLiveData<Event<UIResult<UserQuota?>>>()
val userQuota: LiveData<Event<UIResult<UserQuota?>>> = _userQuota

fun getStoredQuota(
accountName: String
) = runUseCaseWithResult(
coroutineDispatcher = coroutinesDispatcherProvider.io,
requiresConnection = false,
showLoading = true,
liveData = _userQuota,
useCase = getStoredQuotaUseCase,
useCaseParams = GetStoredQuotaUseCase.Params(accountName = accountName)
)
val userQuota: Flow<UserQuota> = getStoredQuotaAsStreamUseCase(GetStoredQuotaAsStreamUseCase.Params(accountName))

fun getAccounts(context: Context): List<Account> {
return AccountUtils.getAccounts(context).asList()
}

fun getCurrentAccount(context: Context): Account? {
return AccountUtils.getCurrentOwnCloudAccount(context)
}

fun getUsernameOfAccount(accountName: String): String {
return AccountUtils.getUsernameOfAccount(accountName)
}

fun getFeedbackMail() = contextProvider.getString(R.string.mail_feedback)

fun setCurrentAccount(context: Context, accountName: String): Boolean {
return AccountUtils.setCurrentOwnCloudAccount(context, accountName)
}

fun removeAccount(context: Context) {
viewModelScope.launch(coroutinesDispatcherProvider.io) {
val loggedAccounts = AccountUtils.getAccounts(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import com.owncloud.android.domain.capabilities.model.OCCapability
import com.owncloud.android.domain.files.model.FileListOption
import com.owncloud.android.domain.user.model.UserQuotaState
import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.collectLatestLifecycleFlow
import com.owncloud.android.extensions.goToUrl
import com.owncloud.android.extensions.openPrivacyPolicy
import com.owncloud.android.extensions.sendEmailOrOpenFeedbackDialogAction
Expand All @@ -82,7 +83,11 @@ import timber.log.Timber
*/
abstract class DrawerActivity : ToolbarActivity() {

private val drawerViewModel by viewModel<DrawerViewModel>()
private val drawerViewModel by viewModel<DrawerViewModel> {
parametersOf(
account?.name
)
}
private val capabilitiesViewModel by viewModel<CapabilityViewModel> {
parametersOf(
account?.name
Expand Down Expand Up @@ -287,7 +292,6 @@ abstract class DrawerActivity : ToolbarActivity() {
open fun openDrawer() {
getDrawerLayout()?.openDrawer(GravityCompat.START)
findViewById<View>(R.id.nav_view).requestFocus()
drawerViewModel.getStoredQuota(account.name)
}

/**
Expand All @@ -305,115 +309,105 @@ abstract class DrawerActivity : ToolbarActivity() {
*/
private fun updateQuota() {
Timber.d("Update Quota")
val account = drawerViewModel.getCurrentAccount(this) ?: return
drawerViewModel.getStoredQuota(account.name)
drawerViewModel.userQuota.observe(this) { event ->
when (val uiResult = event.peekContent()) {
is UIResult.Success -> {
uiResult.data?.let { userQuota ->
when {
userQuota.available == -4L -> { // Light users (oCIS)
getAccountQuotaText()?.text = getString(R.string.drawer_unavailable_used_storage)
getAccountQuotaBar()?.isVisible = false
getAccountQuotaStatusText()?.isVisible = false
}

userQuota.available < 0 -> { // Pending, unknown or unlimited free storage
getAccountQuotaBar()?.apply {
isVisible = true
progress = 0
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.color_accent))
}
getAccountQuotaText()?.text = String.format(
getString(R.string.drawer_unavailable_free_storage),
DisplayUtils.bytesToHumanReadable(userQuota.used, this, true)
)
getAccountQuotaStatusText()?.visibility = View.GONE
}

userQuota.available == 0L -> { // Exceeded storage. The value is over 100%.
getAccountQuotaBar()?.apply {
isVisible = true
progress = 100
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.quota_exceeded))
}

if (userQuota.state == UserQuotaState.EXCEEDED) { // oCIS
getAccountQuotaText()?.apply {
text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, context, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), context, true),
userQuota.getRelative()
)
}
getAccountQuotaStatusText()?.apply {
visibility = View.VISIBLE
text = getString(R.string.drawer_exceeded_quota)
}
} else { // oC10
getAccountQuotaText()?.text = getString(R.string.drawer_exceeded_quota)
getAccountQuotaStatusText()?.visibility = View.GONE
}
}

else -> { // Limited storage. Value under 100%
if (userQuota.state == UserQuotaState.NEARING) { // Nearing storage. Value between 75% and 90%
getAccountQuotaBar()?.apply {
isVisible = true
progress = userQuota.getRelative().toInt()
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.color_accent))
}
getAccountQuotaText()?.apply {
text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, context, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), context, true),
userQuota.getRelative()
)
}
getAccountQuotaStatusText()?.apply {
visibility = View.VISIBLE
text = getString(R.string.drawer_nearing_quota)
}
} else if (userQuota.state == UserQuotaState.CRITICAL || userQuota.state == UserQuotaState.EXCEEDED) { // Critical storage. Value over 90%
getAccountQuotaBar()?.apply {
isVisible = true
progress = userQuota.getRelative().toInt()
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.quota_exceeded))
}
getAccountQuotaText()?.apply {
text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, context, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), context, true),
userQuota.getRelative()
)
}
getAccountQuotaStatusText()?.apply {
visibility = View.VISIBLE
text = getString(R.string.drawer_critical_quota)
}
} else { // Normal storage. Value under 75%
getAccountQuotaBar()?.apply {
progress = userQuota.getRelative().toInt()
isVisible = true
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.color_accent))
}
getAccountQuotaText()?.text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, this, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), this, true),
userQuota.getRelative()
)
getAccountQuotaStatusText()?.visibility = View.GONE
}
}
collectLatestLifecycleFlow(drawerViewModel.userQuota) { userQuota ->
when {
userQuota.available == -4L -> { // Light users (oCIS)
getAccountQuotaText()?.text = getString(R.string.drawer_unavailable_used_storage)
getAccountQuotaBar()?.isVisible = false
getAccountQuotaStatusText()?.isVisible = false
}

userQuota.available < 0 -> { // Pending, unknown or unlimited free storage
getAccountQuotaBar()?.apply {
isVisible = true
progress = 0
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.color_accent))
}
getAccountQuotaText()?.text = String.format(
getString(R.string.drawer_unavailable_free_storage),
DisplayUtils.bytesToHumanReadable(userQuota.used, this, true)
)
getAccountQuotaStatusText()?.visibility = View.GONE
}

userQuota.available == 0L -> { // Exceeded storage. The value is over 100%.
getAccountQuotaBar()?.apply {
isVisible = true
progress = 100
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.quota_exceeded))
}

if (userQuota.state == UserQuotaState.EXCEEDED) { // oCIS
getAccountQuotaText()?.apply {
text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, context, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), context, true),
userQuota.getRelative()
)
}
getAccountQuotaStatusText()?.apply {
visibility = View.VISIBLE
text = getString(R.string.drawer_exceeded_quota)
}
} else { // oC10
getAccountQuotaText()?.text = getString(R.string.drawer_exceeded_quota)
getAccountQuotaStatusText()?.visibility = View.GONE
}
}

else -> { // Limited storage. Value under 100%
if (userQuota.state == UserQuotaState.NEARING) { // Nearing storage. Value between 75% and 90%
getAccountQuotaBar()?.apply {
isVisible = true
progress = userQuota.getRelative().toInt()
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.color_accent))
}
getAccountQuotaText()?.apply {
text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, context, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), context, true),
userQuota.getRelative()
)
}
getAccountQuotaStatusText()?.apply {
visibility = View.VISIBLE
text = getString(R.string.drawer_nearing_quota)
}
} else if (userQuota.state == UserQuotaState.CRITICAL || userQuota.state == UserQuotaState.EXCEEDED) { // Critical storage. Value over 90%
getAccountQuotaBar()?.apply {
isVisible = true
progress = userQuota.getRelative().toInt()
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.quota_exceeded))
}
getAccountQuotaText()?.apply {
text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, context, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), context, true),
userQuota.getRelative()
)
}
getAccountQuotaStatusText()?.apply {
visibility = View.VISIBLE
text = getString(R.string.drawer_critical_quota)
}
} else { // Normal storage. Value under 75%
getAccountQuotaBar()?.apply {
progress = userQuota.getRelative().toInt()
isVisible = true
progressTintList = ColorStateList.valueOf(resources.getColor(R.color.color_accent))
}
getAccountQuotaText()?.text = String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(userQuota.used, this, true),
DisplayUtils.bytesToHumanReadable(userQuota.getTotal(), this, true),
userQuota.getRelative()
)
getAccountQuotaStatusText()?.visibility = View.GONE
}
}
is UIResult.Loading -> getAccountQuotaText()?.text = getString(R.string.drawer_loading_quota)
is UIResult.Error -> getAccountQuotaText()?.text = getString(R.string.drawer_unavailable_used_storage)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
* ownCloud Android client application
*
* @author Abel García de Prada
* Copyright (C) 2020 ownCloud GmbH.
* @author Jorge Aguado Recio
*
* Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
Expand Down Expand Up @@ -32,6 +34,10 @@ interface LocalUserDataSource {
accountName: String
): UserQuota?

fun getQuotaForAccountAsFlow(
accountName: String
): Flow<UserQuota>

fun getAllUserQuotas(): List<UserQuota>

fun getAllUserQuotasAsFlow(): Flow<List<UserQuota>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class OCLocalUserDataSource(
override fun getQuotaForAccount(accountName: String): UserQuota? =
userDao.getQuotaForAccount(accountName = accountName)?.toModel()

override fun getQuotaForAccountAsFlow(accountName: String): Flow<UserQuota> =
userDao.getQuotaForAccountAsFlow(accountName = accountName).map { it.toModel() }

override fun getAllUserQuotas(): List<UserQuota> {
return userDao.getAllUserQuotas().map { userQuotaEntity ->
userQuotaEntity.toModel()
Expand Down
Loading

0 comments on commit e7e2c94

Please sign in to comment.