Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE REQUEST] oCIS Users light #4518

Merged
merged 25 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
afdfb47
feat: added new condition in the login to support light users
joragua Nov 25, 2024
64ab6f3
feat: added new main fragment (`MainEmptyListFragment`) for light users
joragua Nov 25, 2024
3e02b60
feat: disabled refresh operation for av.offline view and removed null…
joragua Nov 25, 2024
dae2f5a
feat: added new condition to support light users in drawer and manage…
joragua Nov 25, 2024
08d277a
feat: disabled light users for automatic uploads
joragua Nov 26, 2024
7b35c2e
feat: adapted `ReceiveExternalFiles` (Activity and ViewModel) for lig…
joragua Nov 26, 2024
05b9792
feat: added release note
joragua Nov 26, 2024
128d329
chore: added calens file
joragua Nov 26, 2024
d8989c3
refactor: removed unnecessary get in `ViewModelModule` and Ktlint cha…
joragua Nov 26, 2024
404a357
feat: added a new condition to avoid oCIS accounts warning dialog for…
joragua Nov 26, 2024
ef06698
refactor: changed the content of calens file and release note and ren…
joragua Nov 28, 2024
b4893f7
refactor: replaced the use case for checking if the account is a ligh…
joragua Nov 28, 2024
6b06f7a
feat: removed search in toolbar for light users
joragua Nov 28, 2024
35f5fa1
refactor: removed one unnecessary method from automatic uploads
joragua Nov 28, 2024
824294e
refactor: moved `ReceiveExternalFilesViewModel` creation (now when th…
joragua Nov 28, 2024
157264e
refactor: removed unnecessary code in toolbar for light users
joragua Nov 28, 2024
2b15213
refactor: added identation in `DrawerActivity`
joragua Nov 28, 2024
1f953dd
feat: added a snackbar in automatic uploads for light users and repla…
joragua Nov 28, 2024
af6ddc6
fix: added a condition to distinguish between `FileDisplayActivity` a…
joragua Nov 28, 2024
9832da9
fix: created a new method in 'DrawerViewModel' to avoid navigation wh…
joragua Nov 29, 2024
98ebf7c
fix: set an account by default when automatic uploads are enabled
joragua Dec 2, 2024
70e6e98
docs: calens changelog updated
joragua Dec 2, 2024
1c13299
refactor: moved `checkUserLight` method to `ManageAccountsViewModel` …
joragua Dec 3, 2024
4f3409b
fix: set the correct account for automatic uploads when there are use…
joragua Dec 3, 2024
7908a14
fix: set the correct backup account in UI and not the current one
joragua Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ownCloud admins and users.
* Enhancement - Quota improvements from GraphAPI: [#4411](https://github.com/owncloud/android/issues/4411)
* Enhancement - Upgraded AGP version to 8.7.2: [#4478](https://github.com/owncloud/android/issues/4478)
* Enhancement - Added text labels for BottomNavigationView: [#4484](https://github.com/owncloud/android/issues/4484)
* Enhancement - OCIS Light Users: [#4490](https://github.com/owncloud/android/issues/4490)
* Enhancement - Enforce OIDC auth flow via branding: [#4500](https://github.com/owncloud/android/issues/4500)

## Details
Expand Down Expand Up @@ -94,6 +95,13 @@ ownCloud admins and users.
https://github.com/owncloud/android/issues/4484
https://github.com/owncloud/android/pull/4498

* Enhancement - OCIS Light Users: [#4490](https://github.com/owncloud/android/issues/4490)

OCIS light users (users without personal space) are now supported in the app

https://github.com/owncloud/android/issues/4490
https://github.com/owncloud/android/pull/4518

* Enhancement - Enforce OIDC auth flow via branding: [#4500](https://github.com/owncloud/android/issues/4500)

A new branded parameter `enforce_oidc` has been added to enforce the app to
Expand Down
6 changes: 6 additions & 0 deletions changelog/unreleased/4518
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: oCIS Light Users

oCIS light users (users without personal space) are now supported in the app

https://github.com/owncloud/android/issues/4490
https://github.com/owncloud/android/pull/4518
13 changes: 12 additions & 1 deletion owncloudApp/src/main/java/com/owncloud/android/MainApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import com.owncloud.android.dependecyinjection.viewModelModule
import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase
import com.owncloud.android.domain.spaces.model.OCSpace
import com.owncloud.android.domain.spaces.usecases.GetPersonalSpaceForAccountUseCase
import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase
import com.owncloud.android.extensions.createNotificationChannel
import com.owncloud.android.lib.common.SingleSessionManager
import com.owncloud.android.presentation.authentication.AccountUtils
Expand Down Expand Up @@ -194,7 +195,17 @@ class MainApp : Application() {
}
}

spacesAllowed && personalSpace == null
val getStoredQuotaUseCase: GetStoredQuotaUseCase by inject()
val quota = withContext(CoroutineScope(CoroutinesDispatcherProvider().io).coroutineContext) {
getStoredQuotaUseCase(
GetStoredQuotaUseCase.Params(
accountName = account.name
)
)
}
val isLightUser = quota.getDataOrNull()?.available == -4L

spacesAllowed && personalSpace == null && !isLightUser
}

override fun onActivityStarted(activity: Activity) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ val viewModelModule = module {
viewModel { AuthenticationViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
viewModel { MigrationViewModel(MainApp.dataFolder, get(), get(), get(), get(), get(), get(), get()) }
viewModel { TransfersViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
viewModel { ReceiveExternalFilesViewModel(get(), get(), get()) }
viewModel { ReceiveExternalFilesViewModel(get(), get(), get(), get()) }
viewModel { (accountName: String, showPersonalSpace: Boolean) ->
SpacesListViewModel(get(), get(), get(), get(), get(), accountName, showPersonalSpace)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ class ManageAccountsAdapter(

private fun updateQuota(quotaText: TextView, quotaBar: ProgressBar, userQuota: UserQuota, context: Context) {
when {
userQuota.available == -4L -> { // Light users (oCIS)
quotaBar.visibility = View.GONE
quotaText.text = context.getString(R.string.drawer_unavailable_used_storage)
}

userQuota.available < 0 -> { // Pending, unknown or unlimited free storage. The progress bar is hid
quotaBar.visibility = View.GONE
quotaText.text = DisplayUtils.bytesToHumanReadable(userQuota.used, context, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.lifecycle.viewModelScope
import com.owncloud.android.domain.user.model.UserQuota
import com.owncloud.android.domain.automaticuploads.model.AutomaticUploadsConfiguration
import com.owncloud.android.domain.automaticuploads.usecases.GetAutomaticUploadsConfigurationUseCase
import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase
import com.owncloud.android.domain.user.usecases.GetUserQuotasAsStreamUseCase
import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.ViewModelExt.runUseCaseWithResult
Expand All @@ -40,11 +41,14 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext

class ManageAccountsViewModel(
private val accountProvider: AccountProvider,
private val removeLocalFilesForAccountUseCase: RemoveLocalFilesForAccountUseCase,
private val getAutomaticUploadsConfigurationUseCase: GetAutomaticUploadsConfigurationUseCase,
private val getStoredQuotaUseCase: GetStoredQuotaUseCase,
getUserQuotasAsStreamUseCase: GetUserQuotasAsStreamUseCase,
private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider,
) : ViewModel() {
Expand Down Expand Up @@ -84,4 +88,11 @@ class ManageAccountsViewModel(
return accountName == automaticUploadsConfiguration?.pictureUploadsConfiguration?.accountName ||
accountName == automaticUploadsConfiguration?.videoUploadsConfiguration?.accountName
}

fun checkUserLight(accountName: String): Boolean = runBlocking(CoroutinesDispatcherProvider().io) {
val quota = withContext(CoroutinesDispatcherProvider().io) {
getStoredQuotaUseCase(GetStoredQuotaUseCase.Params(accountName))
}
quota.getDataOrNull()?.available == -4L
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* @author David González Verdugo
* @author Abel García de Prada
* @author Aitor Ballesteros Pavón
* @author Jorge Aguado Recio
*
* Copyright (C) 2024 ownCloud GmbH.
*
Expand Down Expand Up @@ -58,6 +59,7 @@ class DrawerViewModel(
accountName: String
) = runUseCaseWithResult(
coroutineDispatcher = coroutinesDispatcherProvider.io,
requiresConnection = false,
showLoading = true,
liveData = _userQuota,
useCase = getStoredQuotaUseCase,
Expand Down Expand Up @@ -105,4 +107,5 @@ class DrawerViewModel(
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* ownCloud Android client application
*
* @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,
* as published by the Free Software Foundation.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.owncloud.android.presentation.files.filelist

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.owncloud.android.R
import com.owncloud.android.databinding.MainEmptyListFragmentBinding


class MainEmptyListFragment : Fragment() {

private var _binding: MainEmptyListFragmentBinding? = null
private val binding get() = _binding!!

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = MainEmptyListFragmentBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.emptyDataParent.apply {
listEmptyDatasetIcon.setImageResource(R.drawable.ic_folder)
listEmptyDatasetTitle.setText(R.string.file_list_empty_title_all_files)
JuancaG05 marked this conversation as resolved.
Show resolved Hide resolved
listEmptyDatasetSubTitle.setText(R.string.light_users_subtitle)
}
val titleToolbar = requireActivity().findViewById<TextView>(R.id.root_toolbar_title)
titleToolbar.apply {
setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
isClickable = false
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ class MainFileListFragment : Fragment(),
binding.recyclerViewMainFileList.adapter = fileListAdapter

// Set Swipe to refresh and its listener
binding.swipeRefreshMainFileList.isEnabled = mainFileListViewModel.fileListOption.value != FileListOption.AV_OFFLINE
binding.swipeRefreshMainFileList.setOnRefreshListener {
fileOperationsViewModel.performOperation(
FileOperation.RefreshFolderOperation(
Expand Down Expand Up @@ -317,7 +318,7 @@ class MainFileListFragment : Fragment(),
fileActions?.onCurrentFolderUpdated(currentFolderDisplayed, mainFileListViewModel.getSpace())
val fileListOption = mainFileListViewModel.fileListOption.value
val refreshFolderNeeded = fileListOption.isAllFiles() ||
(!fileListOption.isAllFiles() && currentFolderDisplayed.remotePath != ROOT_PATH)
(!fileListOption.isAllFiles() && currentFolderDisplayed.remotePath != ROOT_PATH && !fileListOption.isAvailableOffline())
if (refreshFolderNeeded) {
fileOperationsViewModel.performOperation(
FileOperation.RefreshFolderOperation(
Expand Down Expand Up @@ -609,29 +610,28 @@ class MainFileListFragment : Fragment(),
)
showOrHideEmptyView(fileListUiState)

fileListUiState.space?.let {
binding.spaceHeader.root.apply {
if (fileListUiState.space.isProject && fileListUiState.folderToDisplay?.remotePath == ROOT_PATH) {
isVisible = true
animate().translationY(0f).duration = 100
} else {
animate().translationY(-height.toFloat()).withEndAction { isVisible = false }
}

binding.spaceHeader.root.apply {
if (fileListUiState.space?.isProject == true && fileListUiState.folderToDisplay?.remotePath == ROOT_PATH) {
isVisible = true
animate().translationY(0f).duration = 100
} else {
animate().translationY(-height.toFloat()).withEndAction { isVisible = false }
}
}

val spaceSpecialImage = it.getSpaceSpecialImage()
if (spaceSpecialImage != null) {
binding.spaceHeader.spaceHeaderImage.load(
ThumbnailsRequester.getPreviewUriForSpaceSpecial(spaceSpecialImage),
ThumbnailsRequester.getCoilImageLoader()
) {
placeholder(R.drawable.ic_spaces)
error(R.drawable.ic_spaces)
}
val spaceSpecialImage = fileListUiState.space?.getSpaceSpecialImage()
if (spaceSpecialImage != null) {
binding.spaceHeader.spaceHeaderImage.load(
ThumbnailsRequester.getPreviewUriForSpaceSpecial(spaceSpecialImage),
ThumbnailsRequester.getCoilImageLoader()
) {
placeholder(R.drawable.ic_spaces)
error(R.drawable.ic_spaces)
}
binding.spaceHeader.spaceHeaderName.text = it.name
binding.spaceHeader.spaceHeaderSubtitle.text = it.description
}
binding.spaceHeader.spaceHeaderName.text = fileListUiState.space?.name
binding.spaceHeader.spaceHeaderSubtitle.text = fileListUiState.space?.description

actionMode?.invalidate()
}
Expand Down Expand Up @@ -810,8 +810,9 @@ class MainFileListFragment : Fragment(),
}

fun updateFileListOption(newFileListOption: FileListOption, file: OCFile) {
mainFileListViewModel.updateFolderToDisplay(file)
mainFileListViewModel.updateFileListOption(newFileListOption)
binding.swipeRefreshMainFileList.isEnabled = newFileListOption != FileListOption.AV_OFFLINE
mainFileListViewModel.updateFolderToDisplay(file)
showOrHideFab(newFileListOption, file)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ class ReleaseNotesViewModel(
subtitle = R.string.release_notes_4_5_0_subtitle_quota_improvements,
type = ReleaseNoteType.ENHANCEMENT
),
ReleaseNote(
title = R.string.release_notes_4_5_0_title_light_users,
subtitle = R.string.release_notes_4_5_0_subtitle_light_users,
type = ReleaseNoteType.ENHANCEMENT
),
)
}
}
Loading
Loading