(R.id.root_toolbar_title)
+ titleToolbar.apply {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
+ isClickable = false
+ }
+ }
+
+
+}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt
index 46778355b76..ee9abe69faf 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/files/filelist/MainFileListFragment.kt
@@ -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(
@@ -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(
@@ -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()
}
@@ -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)
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt
index c1991be1e03..d0247f18059 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt
@@ -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
+ ),
)
}
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt
index edb74b12ca4..730108e8132 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsFragment.kt
@@ -3,8 +3,9 @@
*
* @author Juan Carlos Garrote Gascón
* @author Aitor Ballesteros Pavón
+ * @author Jorge Aguado Recio
*
- * Copyright (C) 2023 ownCloud GmbH.
+ * 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,
@@ -48,7 +49,10 @@ import com.owncloud.android.db.PreferenceManager.PREF__CAMERA_PICTURE_UPLOADS_PA
import com.owncloud.android.db.PreferenceManager.PREF__CAMERA_PICTURE_UPLOADS_SOURCE
import com.owncloud.android.db.PreferenceManager.PREF__CAMERA_PICTURE_UPLOADS_WIFI_ONLY
import com.owncloud.android.domain.automaticuploads.model.UploadBehavior
+import com.owncloud.android.extensions.collectLatestLifecycleFlow
import com.owncloud.android.extensions.showAlertDialog
+import com.owncloud.android.extensions.showMessageInSnackbar
+import com.owncloud.android.presentation.accounts.ManageAccountsViewModel
import com.owncloud.android.ui.activity.FolderPickerActivity
import com.owncloud.android.utils.DisplayUtils
import kotlinx.coroutines.launch
@@ -59,6 +63,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
// ViewModel
private val picturesViewModel by viewModel()
+ private val manageAccountsViewModel by viewModel()
private var prefEnablePictureUploads: SwitchPreferenceCompat? = null
private var prefPictureUploadsPath: Preference? = null
@@ -69,6 +74,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
private var prefPictureUploadsAccount: ListPreference? = null
private var prefPictureUploadsLastSync: Preference? = null
private var spaceId: String? = null
+ private lateinit var selectedAccount: String
private val selectPictureUploadsPathLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
@@ -103,10 +109,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
).toTypedArray()
entryValues = listOf(UploadBehavior.COPY.name, UploadBehavior.MOVE.name).toTypedArray()
}
- prefPictureUploadsAccount = findPreference(PREF__CAMERA_PICTURE_UPLOADS_ACCOUNT_NAME)?.apply {
- entries = picturesViewModel.getLoggedAccountNames()
- entryValues = picturesViewModel.getLoggedAccountNames()
- }
+ prefPictureUploadsAccount = findPreference(PREF__CAMERA_PICTURE_UPLOADS_ACCOUNT_NAME)
val comment = getString(R.string.prefs_camera_upload_source_path_title_required)
prefPictureUploadsSourcePath?.title = String.format(prefPictureUploadsSourcePath?.title.toString(), comment)
@@ -123,18 +126,40 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
private fun initStateObservers() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
- picturesViewModel.pictureUploads.collect { pictureUploadsConfiguration ->
- enablePictureUploads(pictureUploadsConfiguration != null)
- pictureUploadsConfiguration?.let {
- prefPictureUploadsAccount?.value = it.accountName
- prefPictureUploadsPath?.summary = picturesViewModel.getUploadPathString()
- prefPictureUploadsSourcePath?.summary = DisplayUtils.getPathWithoutLastSlash(it.sourcePath.toUri().path)
- prefPictureUploadsOnWifi?.isChecked = it.wifiOnly
- prefPictureUploadsOnCharging?.isChecked = it.chargingOnly
- prefPictureUploadsBehaviour?.value = it.behavior.name
- prefPictureUploadsLastSync?.summary = DisplayUtils.unixTimeToHumanReadable(it.lastSyncTimestamp)
- spaceId = it.spaceId
- } ?: resetFields()
+ collectLatestLifecycleFlow(manageAccountsViewModel.userQuotas) { listUserQuotas ->
+ val availableAccounts = listUserQuotas.filter { it.available != -4L }
+ prefPictureUploadsAccount?.apply {
+ entries = availableAccounts.map { it.accountName }.toTypedArray()
+ entryValues = availableAccounts.map { it.accountName }.toTypedArray()
+ }
+
+ if (availableAccounts.isEmpty()) {
+ enablePictureUploads(false, true)
+ showMessageInSnackbar(getString(R.string.prefs_automatic_uploads_not_available_users_light))
+ } else {
+ val currentAccount = manageAccountsViewModel.getCurrentAccount()?.name
+ currentAccount?.let {
+ selectedAccount = if (manageAccountsViewModel.checkUserLight(currentAccount)) {
+ availableAccounts.first().accountName
+ } else {
+ currentAccount
+ }
+ }
+
+ picturesViewModel.pictureUploads.collect { pictureUploadsConfiguration ->
+ enablePictureUploads(pictureUploadsConfiguration != null, false)
+ pictureUploadsConfiguration?.let {
+ prefPictureUploadsAccount?.value = it.accountName
+ prefPictureUploadsPath?.summary = picturesViewModel.getUploadPathString()
+ prefPictureUploadsSourcePath?.summary = DisplayUtils.getPathWithoutLastSlash(it.sourcePath.toUri().path)
+ prefPictureUploadsOnWifi?.isChecked = it.wifiOnly
+ prefPictureUploadsOnCharging?.isChecked = it.chargingOnly
+ prefPictureUploadsBehaviour?.value = it.behavior.name
+ prefPictureUploadsLastSync?.summary = DisplayUtils.unixTimeToHumanReadable(it.lastSyncTimestamp)
+ spaceId = it.spaceId
+ } ?: resetFields()
+ }
+ }
}
}
}
@@ -145,7 +170,7 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
val value = newValue as Boolean
if (value) {
- picturesViewModel.enablePictureUploads()
+ picturesViewModel.enablePictureUploads(selectedAccount)
showAlertDialog(
title = getString(R.string.common_important),
message = getString(R.string.proper_pics_folder_warning_camera_upload)
@@ -228,8 +253,11 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
super.onDestroy()
}
- private fun enablePictureUploads(value: Boolean) {
+ private fun enablePictureUploads(value: Boolean, isLightUser: Boolean) {
prefEnablePictureUploads?.isChecked = value
+ if (isLightUser) {
+ prefEnablePictureUploads?.isEnabled = false
+ }
prefPictureUploadsPath?.isEnabled = value
prefPictureUploadsOnWifi?.isEnabled = value
prefPictureUploadsOnCharging?.isEnabled = value
@@ -248,4 +276,5 @@ class SettingsPictureUploadsFragment : PreferenceFragmentCompat() {
prefPictureUploadsBehaviour?.value = UploadBehavior.COPY.name
prefPictureUploadsLastSync?.summary = null
}
+
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsViewModel.kt
index 256c28e7a90..beedf878cc3 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsViewModel.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsPictureUploadsViewModel.kt
@@ -3,8 +3,9 @@
*
* @author Juan Carlos Garrote Gascón
* @author Aitor Ballesteros Pavón
+ * @author Jorge Aguado Recio
*
- * Copyright (C) 2023 ownCloud GmbH.
+ * 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,
@@ -81,20 +82,18 @@ class SettingsPictureUploadsViewModel(
}
}
- fun enablePictureUploads() {
- // Use current account as default. It should never be null. If no accounts are attached, picture uploads are hidden
- accountProvider.getCurrentOwnCloudAccount()?.name?.let { name ->
- viewModelScope.launch(coroutinesDispatcherProvider.io) {
- getPersonalSpaceForAccount(name)
- savePictureUploadsConfigurationUseCase(
- SavePictureUploadsConfigurationUseCase.Params(
- composePictureUploadsConfiguration(
- accountName = name,
- spaceId = pictureUploadsSpace?.id,
- )
+ fun enablePictureUploads(accountName: String) {
+ // Use selected account as default.
+ viewModelScope.launch(coroutinesDispatcherProvider.io) {
+ getPersonalSpaceForAccount(accountName)
+ savePictureUploadsConfigurationUseCase(
+ SavePictureUploadsConfigurationUseCase.Params(
+ composePictureUploadsConfiguration(
+ accountName = accountName,
+ spaceId = pictureUploadsSpace?.id,
)
)
- }
+ )
}
}
@@ -124,8 +123,6 @@ class SettingsPictureUploadsViewModel(
fun getPictureUploadsAccount() = _pictureUploads.value?.accountName
- fun getLoggedAccountNames(): Array = accountProvider.getLoggedAccounts().map { it.name }.toTypedArray()
-
fun getPictureUploadsPath() = _pictureUploads.value?.uploadPath ?: PREF__CAMERA_UPLOADS_DEFAULT_PATH
fun getPictureUploadsSourcePath(): String? = _pictureUploads.value?.sourcePath
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt
index 2fbf963fba1..9d1f39b2b45 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsFragment.kt
@@ -3,8 +3,9 @@
*
* @author Juan Carlos Garrote Gascón
* @author Aitor Ballesteros Pavón
+ * @author Jorge Aguado Recio
*
- * Copyright (C) 2023 ownCloud GmbH.
+ * 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,
@@ -48,7 +49,10 @@ import com.owncloud.android.db.PreferenceManager.PREF__CAMERA_VIDEO_UPLOADS_PATH
import com.owncloud.android.db.PreferenceManager.PREF__CAMERA_VIDEO_UPLOADS_SOURCE
import com.owncloud.android.db.PreferenceManager.PREF__CAMERA_VIDEO_UPLOADS_WIFI_ONLY
import com.owncloud.android.domain.automaticuploads.model.UploadBehavior
+import com.owncloud.android.extensions.collectLatestLifecycleFlow
import com.owncloud.android.extensions.showAlertDialog
+import com.owncloud.android.extensions.showMessageInSnackbar
+import com.owncloud.android.presentation.accounts.ManageAccountsViewModel
import com.owncloud.android.ui.activity.FolderPickerActivity
import com.owncloud.android.utils.DisplayUtils
import kotlinx.coroutines.launch
@@ -59,6 +63,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
// ViewModel
private val videosViewModel by viewModel()
+ private val manageAccountsViewModel by viewModel()
private var prefEnableVideoUploads: SwitchPreferenceCompat? = null
private var prefVideoUploadsPath: Preference? = null
@@ -69,6 +74,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
private var prefVideoUploadsAccount: ListPreference? = null
private var prefVideoUploadsLastSync: Preference? = null
private var spaceId: String? = null
+ private lateinit var selectedAccount: String
private val selectVideoUploadsPathLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
@@ -100,10 +106,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
entries = listOf(getString(R.string.pref_behaviour_entries_keep_file), getString(R.string.pref_behaviour_entries_remove_original_file)).toTypedArray()
entryValues = listOf(UploadBehavior.COPY.name, UploadBehavior.MOVE.name).toTypedArray()
}
- prefVideoUploadsAccount = findPreference(PREF__CAMERA_VIDEO_UPLOADS_ACCOUNT_NAME)?.apply {
- entries = videosViewModel.getLoggedAccountNames()
- entryValues = videosViewModel.getLoggedAccountNames()
- }
+ prefVideoUploadsAccount = findPreference(PREF__CAMERA_VIDEO_UPLOADS_ACCOUNT_NAME)
val comment = getString(R.string.prefs_camera_upload_source_path_title_required)
prefVideoUploadsSourcePath?.title = String.format(prefVideoUploadsSourcePath?.title.toString(), comment)
@@ -120,18 +123,40 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
private fun initLiveDataObservers() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
- videosViewModel.videoUploads.collect { videoUploadsConfiguration ->
- enableVideoUploads(videoUploadsConfiguration != null)
- videoUploadsConfiguration?.let {
- prefVideoUploadsAccount?.value = it.accountName
- prefVideoUploadsPath?.summary = videosViewModel.getUploadPathString()
- prefVideoUploadsSourcePath?.summary = DisplayUtils.getPathWithoutLastSlash(it.sourcePath.toUri().path)
- prefVideoUploadsOnWifi?.isChecked = it.wifiOnly
- prefVideoUploadsOnCharging?.isChecked = it.chargingOnly
- prefVideoUploadsBehaviour?.value = it.behavior.name
- prefVideoUploadsLastSync?.summary = DisplayUtils.unixTimeToHumanReadable(it.lastSyncTimestamp)
- spaceId = it.spaceId
- } ?: resetFields()
+ collectLatestLifecycleFlow(manageAccountsViewModel.userQuotas) { listUserQuotas ->
+ val availableAccounts = listUserQuotas.filter { it.available != -4L }
+ prefVideoUploadsAccount?.apply {
+ entries = availableAccounts.map { it.accountName }.toTypedArray()
+ entryValues = availableAccounts.map { it.accountName }.toTypedArray()
+ }
+
+ if (availableAccounts.isEmpty()) {
+ enableVideoUploads(false, true)
+ showMessageInSnackbar(getString(R.string.prefs_automatic_uploads_not_available_users_light))
+ } else {
+ val currentAccount = manageAccountsViewModel.getCurrentAccount()?.name
+ currentAccount?.let {
+ selectedAccount = if (manageAccountsViewModel.checkUserLight(currentAccount)) {
+ availableAccounts.first().accountName
+ } else {
+ currentAccount
+ }
+ }
+
+ videosViewModel.videoUploads.collect { videoUploadsConfiguration ->
+ enableVideoUploads(videoUploadsConfiguration != null, false)
+ videoUploadsConfiguration?.let {
+ prefVideoUploadsAccount?.value = it.accountName
+ prefVideoUploadsPath?.summary = videosViewModel.getUploadPathString()
+ prefVideoUploadsSourcePath?.summary = DisplayUtils.getPathWithoutLastSlash(it.sourcePath.toUri().path)
+ prefVideoUploadsOnWifi?.isChecked = it.wifiOnly
+ prefVideoUploadsOnCharging?.isChecked = it.chargingOnly
+ prefVideoUploadsBehaviour?.value = it.behavior.name
+ prefVideoUploadsLastSync?.summary = DisplayUtils.unixTimeToHumanReadable(it.lastSyncTimestamp)
+ spaceId = it.spaceId
+ } ?: resetFields()
+ }
+ }
}
}
}
@@ -142,7 +167,7 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
val value = newValue as Boolean
if (value) {
- videosViewModel.enableVideoUploads()
+ videosViewModel.enableVideoUploads(selectedAccount)
showAlertDialog(
title = getString(R.string.common_important),
message = getString(R.string.proper_videos_folder_warning_camera_upload)
@@ -225,8 +250,11 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
super.onDestroy()
}
- private fun enableVideoUploads(value: Boolean) {
+ private fun enableVideoUploads(value: Boolean, isLightUser: Boolean) {
prefEnableVideoUploads?.isChecked = value
+ if (isLightUser) {
+ prefEnableVideoUploads?.isEnabled = false
+ }
prefVideoUploadsPath?.isEnabled = value
prefVideoUploadsOnWifi?.isEnabled = value
prefVideoUploadsOnCharging?.isEnabled = value
@@ -245,4 +273,5 @@ class SettingsVideoUploadsFragment : PreferenceFragmentCompat() {
prefVideoUploadsBehaviour?.value = UploadBehavior.COPY.name
prefVideoUploadsLastSync?.summary = null
}
+
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsViewModel.kt
index e205bd0477c..89d88041c48 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsViewModel.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/settings/automaticuploads/SettingsVideoUploadsViewModel.kt
@@ -3,8 +3,9 @@
*
* @author Juan Carlos Garrote Gascón
* @author Aitor Ballesteros Pavón
+ * @author Jorge Aguado Recio
*
- * Copyright (C) 2023 ownCloud GmbH.
+ * 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,
@@ -81,20 +82,18 @@ class SettingsVideoUploadsViewModel(
}
}
- fun enableVideoUploads() {
- // Use current account as default. It should never be null. If no accounts are attached, video uploads are hidden
- accountProvider.getCurrentOwnCloudAccount()?.name?.let { name ->
- viewModelScope.launch(coroutinesDispatcherProvider.io) {
- getPersonalSpaceForAccount(name)
- saveVideoUploadsConfigurationUseCase(
- SaveVideoUploadsConfigurationUseCase.Params(
- composeVideoUploadsConfiguration(
- accountName = name,
- spaceId = videoUploadsSpace?.id,
- )
+ fun enableVideoUploads(accountName: String) {
+ // Use selected account as default.
+ viewModelScope.launch(coroutinesDispatcherProvider.io) {
+ getPersonalSpaceForAccount(accountName)
+ saveVideoUploadsConfigurationUseCase(
+ SaveVideoUploadsConfigurationUseCase.Params(
+ composeVideoUploadsConfiguration(
+ accountName = accountName,
+ spaceId = videoUploadsSpace?.id,
)
)
- }
+ )
}
}
@@ -124,8 +123,6 @@ class SettingsVideoUploadsViewModel(
fun getVideoUploadsAccount() = _videoUploads.value?.accountName
- fun getLoggedAccountNames(): Array = accountProvider.getLoggedAccounts().map { it.name }.toTypedArray()
-
fun getVideoUploadsPath() = _videoUploads.value?.uploadPath ?: PREF__CAMERA_UPLOADS_DEFAULT_PATH
fun getVideoUploadsSourcePath(): String? = _videoUploads.value?.sourcePath
diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/ReceiveExternalFilesViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/ui/ReceiveExternalFilesViewModel.kt
index 469aeda09b5..9fccbcf8eeb 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/ui/ReceiveExternalFilesViewModel.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/ui/ReceiveExternalFilesViewModel.kt
@@ -1,7 +1,7 @@
/**
* ownCloud Android client application
*
- * Copyright (C) 2022 ownCloud GmbH.
+ * 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,
@@ -22,9 +22,8 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase
import com.owncloud.android.domain.files.model.OCFile
-import com.owncloud.android.domain.spaces.model.OCSpace
-import com.owncloud.android.domain.spaces.usecases.GetPersonalSpaceForAccountUseCase
import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.ViewModelExt.runUseCaseWithResult
import com.owncloud.android.presentation.common.UIResult
@@ -35,15 +34,23 @@ import kotlinx.coroutines.launch
class ReceiveExternalFilesViewModel(
private val synchronizeFolderUseCase: SynchronizeFolderUseCase,
private val coroutinesDispatcherProvider: CoroutinesDispatcherProvider,
- private val getPersonalSpaceForAccountUseCase: GetPersonalSpaceForAccountUseCase,
+ private val getStoredCapabilitiesUseCase: GetStoredCapabilitiesUseCase,
+ private val accountName: String,
) : ViewModel() {
private val _syncFolderLiveData = MediatorLiveData>>()
val syncFolderLiveData: LiveData>> = _syncFolderLiveData
- private val _personalSpaceLiveData = MutableLiveData()
- val personalSpaceLiveData: LiveData = _personalSpaceLiveData
+ private val _spacesAreAllowed = MutableLiveData()
+ val spacesAreAllowed: LiveData = _spacesAreAllowed
+ init {
+ viewModelScope.launch(coroutinesDispatcherProvider.io) {
+ val capabilities = getStoredCapabilitiesUseCase(GetStoredCapabilitiesUseCase.Params(accountName))
+ val spacesAvailableForAccount = capabilities?.isSpacesAllowed() == true
+ _spacesAreAllowed.postValue(spacesAvailableForAccount)
+ }
+ }
fun refreshFolderUseCase(
folderToSync: OCFile,
@@ -60,16 +67,4 @@ class ReceiveExternalFilesViewModel(
)
)
- fun getPersonalSpaceForAccount(accountName: String) {
- viewModelScope.launch(coroutinesDispatcherProvider.io) {
- val result = getPersonalSpaceForAccountUseCase(
- GetPersonalSpaceForAccountUseCase.Params(
- accountName = accountName
- )
- )
- _personalSpaceLiveData.postValue(result)
- }
- }
-
-
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.kt b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.kt
index 7f68c85f245..10a17618690 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.kt
@@ -312,15 +312,21 @@ abstract class DrawerActivity : ToolbarActivity() {
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))
+ 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)
+ getString(R.string.drawer_unavailable_free_storage),
+ DisplayUtils.bytesToHumanReadable(userQuota.used, this, true)
)
getAccountQuotaStatusText()?.visibility = View.GONE
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt
index 85b4397ba97..74319110fa8 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt
@@ -92,11 +92,13 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import com.owncloud.android.operations.SyncProfileOperation
+import com.owncloud.android.presentation.accounts.ManageAccountsViewModel
import com.owncloud.android.presentation.authentication.AccountUtils.getCurrentOwnCloudAccount
import com.owncloud.android.presentation.capabilities.CapabilityViewModel
import com.owncloud.android.presentation.common.UIResult
import com.owncloud.android.presentation.conflicts.ConflictsResolveActivity
import com.owncloud.android.presentation.files.details.FileDetailsFragment
+import com.owncloud.android.presentation.files.filelist.MainEmptyListFragment
import com.owncloud.android.presentation.files.filelist.MainFileListFragment
import com.owncloud.android.presentation.files.operations.FileOperation
import com.owncloud.android.presentation.files.operations.FileOperationsViewModel
@@ -176,7 +178,7 @@ class FileDisplayActivity : FileActivity(),
private var syncInProgress = false
- private var fileListOption = FileListOption.ALL_FILES
+ var fileListOption = FileListOption.ALL_FILES
private var waitingToSend: OCFile? = null
private var waitingToOpen: OCFile? = null
@@ -185,6 +187,7 @@ class FileDisplayActivity : FileActivity(),
private val fileOperationsViewModel: FileOperationsViewModel by viewModel()
private val transfersViewModel: TransfersViewModel by viewModel()
private lateinit var spacesListViewModel: SpacesListViewModel
+ private val manageAccountsViewModel: ManageAccountsViewModel by viewModel()
private val sharedPreferences: SharedPreferencesProvider by inject()
@@ -193,6 +196,8 @@ class FileDisplayActivity : FileActivity(),
private lateinit var binding: ActivityMainBinding
+ private var isLightUser = false
+
override fun onCreate(savedInstanceState: Bundle?) {
Timber.v("onCreate() start")
@@ -318,7 +323,9 @@ class FileDisplayActivity : FileActivity(),
capabilitiesViewModel.capabilities.observe(this, Event.EventObserver {
onCapabilitiesOperationFinish(it)
})
+ isLightUser = manageAccountsViewModel.checkUserLight(account.name)
navigateTo(fileListOption, initialState = true)
+
}
startListeningToOperations()
@@ -422,6 +429,14 @@ class FileDisplayActivity : FileActivity(),
transaction.commit()
}
+ private fun initAndShowEmptyPersonalSpace() {
+ val emptyListFragment = MainEmptyListFragment()
+ this.fileListOption = FileListOption.ALL_FILES
+ val transaction = supportFragmentManager.beginTransaction()
+ transaction.replace(R.id.left_fragment_container, emptyListFragment)
+ transaction.commit()
+ }
+
private fun initFragmentsWithFile() {
if (account != null && file != null) {
/// First fragment
@@ -1743,13 +1758,20 @@ class FileDisplayActivity : FileActivity(),
val previousFileListOption = fileListOption
when (newFileListOption) {
FileListOption.ALL_FILES -> {
- if (previousFileListOption != newFileListOption || initialState) {
- file = storageManager.getRootPersonalFolder()
+ if (isLightUser) {
+ file = null
fileListOption = newFileListOption
- mainFileListFragment?.updateFileListOption(newFileListOption, file) ?: initAndShowListOfFiles(newFileListOption)
- updateToolbar(file)
+ initAndShowEmptyPersonalSpace()
+ updateToolbar(null)
} else {
- browseToRoot()
+ if (previousFileListOption != newFileListOption || initialState) {
+ file = storageManager.getRootPersonalFolder()
+ fileListOption = newFileListOption
+ mainFileListFragment?.updateFileListOption(newFileListOption, file) ?: initAndShowListOfFiles(newFileListOption)
+ updateToolbar(file)
+ } else {
+ browseToRoot()
+ }
}
}
diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
index ea2c2e2947e..1e8af8197b5 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
+++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
@@ -10,6 +10,7 @@
* @author Abel García de Prada
* @author John Kalimeris
* @author Aitor Ballesteros Pavón
+ * @author Jorge Aguado Recio
*
* Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2024 ownCloud GmbH.
@@ -72,7 +73,6 @@
import com.owncloud.android.db.PreferenceManager;
import com.owncloud.android.domain.exceptions.UnauthorizedException;
import com.owncloud.android.domain.files.model.OCFile;
-import com.owncloud.android.domain.spaces.model.OCSpace;
import com.owncloud.android.extensions.ActivityExtKt;
import com.owncloud.android.extensions.ThrowableExtKt;
import com.owncloud.android.lib.common.OwnCloudAccount;
@@ -117,6 +117,7 @@
import java.util.regex.Pattern;
import static com.owncloud.android.presentation.settings.advanced.SettingsAdvancedFragment.PREF_SHOW_HIDDEN_FILES;
+import static org.koin.core.parameter.ParametersHolderKt.parametersOf;
import static org.koin.java.KoinJavaComponent.get;
import static org.koin.java.KoinJavaComponent.inject;
@@ -179,7 +180,7 @@ public class ReceiveExternalFilesActivity extends FileActivity
private boolean showHiddenFiles;
private OCSharedPreferencesProvider sharedPreferencesProvider;
- private OCSpace personalSpace;
+ private boolean areSpacesAllowed;
Pattern pattern = Pattern.compile("[/\\\\]");
@@ -221,17 +222,15 @@ protected void onCreate(Bundle savedInstanceState) {
}
mSortOptionsView.setVisibility(View.GONE);
- mReceiveExternalFilesViewModel = get(ReceiveExternalFilesViewModel.class);
- subscribeToViewModels();
initPickerListener();
}
private void subscribeToViewModels() {
- mReceiveExternalFilesViewModel.getPersonalSpaceLiveData().observe(this, ocSpace -> {
- personalSpace = ocSpace;
+ mReceiveExternalFilesViewModel.getSpacesAreAllowed().observe(this, spaces -> {
+ areSpacesAllowed = spaces;
- if (personalSpace == null) { // OC10 Server
+ if (!areSpacesAllowed) { // OC10 Server
showListOfFiles();
showRetainerFragment();
updateDirectoryList();
@@ -337,7 +336,8 @@ protected void setAccount(Account account, boolean savedAccount) {
@Override
protected void onAccountSet(boolean stateWasRecovered) {
super.onAccountSet(mAccountWasRestored);
- mReceiveExternalFilesViewModel.getPersonalSpaceForAccount(getAccount().name);
+ mReceiveExternalFilesViewModel = get(ReceiveExternalFilesViewModel.class, null , () -> parametersOf(getAccount().name));
+ subscribeToViewModels();
initTargetFolder();
mReceiveExternalFilesViewModel.getSyncFolderLiveData().observe(this, eventUiResult -> {
@@ -360,7 +360,7 @@ protected void onAccountSet(boolean stateWasRecovered) {
} else if (uiResult instanceof UIResult.Success) {
mSyncInProgress = false;
updateDirectoryList();
- if (mParents.size() == 1 && personalSpace == null) {
+ if (mParents.size() == 1 && !areSpacesAllowed) {
updateToolbar(getString(R.string.uploader_top_message));
}
if(fragmentContainer.getVisibility() == View.VISIBLE) {
@@ -433,7 +433,6 @@ public void onClick(DialogInterface dialog, int which) {
onAccountSet(mAccountWasRestored);
dialog.dismiss();
PreferenceManager.setLastUploadPath("/", this);
- mReceiveExternalFilesViewModel.getPersonalSpaceForAccount(getAccount().name);
mAccountSelected = true;
mAccountSelectionShowing = false;
});
@@ -458,7 +457,7 @@ public void onBackPressed() {
String full_path = generatePath(mParents);
startSyncFolderOperation(getStorageManager().getFileByPath(full_path, currentSpaceId));
updateDirectoryList();
- if (mParents.size() <= 1 && personalSpace == null) {
+ if (mParents.size() <= 1 && !areSpacesAllowed) {
updateToolbar(getString(R.string.uploader_top_message));
}
}
diff --git a/owncloudApp/src/main/res/layout/main_empty_list_fragment.xml b/owncloudApp/src/main/res/layout/main_empty_list_fragment.xml
new file mode 100644
index 00000000000..2b2655226c3
--- /dev/null
+++ b/owncloudApp/src/main/res/layout/main_empty_list_fragment.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
diff --git a/owncloudApp/src/main/res/values/strings.xml b/owncloudApp/src/main/res/values/strings.xml
index c9f71477b41..2bab6878a91 100644
--- a/owncloudApp/src/main/res/values/strings.xml
+++ b/owncloudApp/src/main/res/values/strings.xml
@@ -78,6 +78,7 @@
Video upload path
Upload videos via wifi only
Upload videos only when charging
+ Automatic uploads are not available for users light
Advanced
Manage notifications
Show hidden files
@@ -165,6 +166,7 @@
No available offline files
No shared links
Upload some content or sync with your devices!
+ Personal space is not available
No shares
You are not collaborating on other people\'s resources.
You don\'t have access to any space!
@@ -738,6 +740,8 @@
Added feedback when (un)setting av. offline in all previews and updated options menu depending on file status
Improvements in storage occupation display
Storage occupation refreshed frequently in file and refresh operations and available in accounts manager view, besides of drawer menu
+ ownCloud Infinite Scale servers users light
+ ownCloud Infinite Scale servers users light (users without personal space) are now supported in the app
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetBaseUrlRemoteOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetBaseUrlRemoteOperation.kt
index 65a8faf90e3..2fd6ab35cb5 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetBaseUrlRemoteOperation.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/GetBaseUrlRemoteOperation.kt
@@ -51,7 +51,7 @@ class GetBaseUrlRemoteOperation : RemoteOperation() {
val status = client.executeHttpMethod(propFindMethod)
- if (isSuccess(status)) {
+ if (isSuccess(status) || status == HttpConstants.HTTP_NOT_FOUND) { // A light user returns 404 (NOT FOUND)
RemoteOperationResult(RemoteOperationResult.ResultCode.OK).apply {
data = propFindMethod.getFinalUrl().toString()
}
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt
index bcabd393582..63fdf11d44e 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt
+++ b/owncloudData/src/main/java/com/owncloud/android/data/spaces/repository/OCSpacesRepository.kt
@@ -39,15 +39,14 @@ class OCSpacesRepository(
remoteSpacesDataSource.refreshSpacesForAccount(accountName).also { listOfSpaces ->
localSpacesDataSource.saveSpacesForAccount(listOfSpaces)
val personalSpace = listOfSpaces.find { it.isPersonal }
- personalSpace?.let {
- val userQuota = if (it.quota?.total!!.toInt() == 0) {
+ val userQuota = personalSpace?.let {
+ if (it.quota?.total!!.toInt() == 0) {
UserQuota(accountName, -3, it.quota?.used!!, it.quota?.total!!, UserQuotaState.fromValue(it.quota?.state!!))
} else {
UserQuota(accountName, it.quota?.remaining!!, it.quota?.used!!, it.quota?.total!!, UserQuotaState.fromValue(it.quota?.state!!))
}
- localUserDataSource.saveQuotaForAccount(accountName, userQuota)
- }
-
+ } ?: UserQuota(accountName, -4, 0, 0, UserQuotaState.NORMAL)
+ localUserDataSource.saveQuotaForAccount(accountName, userQuota)
}
}
diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/user/model/UserQuota.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/user/model/UserQuota.kt
index d3ad5c755e1..51bb3c6ccf9 100644
--- a/owncloudDomain/src/main/java/com/owncloud/android/domain/user/model/UserQuota.kt
+++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/user/model/UserQuota.kt
@@ -26,7 +26,7 @@ import kotlin.math.roundToLong
data class UserQuota(
val accountName: String,
- val available: Long,
+ val available: Long, // -4 : Light Users | -3: Unlimited quota | OTHER: Limited quota
val used: Long,
val total: Long?,
val state: UserQuotaState?