Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
0c69072e9d
1355
app/schemas/com.nextcloud.client.database.NextcloudDatabase/90.json
Normal file
1355
app/schemas/com.nextcloud.client.database.NextcloudDatabase/90.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType
|
||||
import com.owncloud.android.lib.resources.shares.OCShare
|
||||
import com.owncloud.android.lib.resources.shares.ShareType
|
||||
import com.owncloud.android.lib.resources.shares.attributes.ShareAttributes
|
||||
import com.owncloud.android.ui.fragment.util.SharePermissionManager
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertFalse
|
||||
import junit.framework.TestCase.assertNotNull
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
class SharePermissionManagerTest {
|
||||
|
||||
private fun createShare(sharePermission: Int, isFolder: Boolean = false, attributesJson: String? = null): OCShare {
|
||||
return if (isFolder) {
|
||||
OCShare("/test")
|
||||
.apply {
|
||||
permissions = sharePermission
|
||||
attributes = attributesJson
|
||||
shareType = ShareType.INTERNAL
|
||||
sharedDate = 1188206955
|
||||
shareWith = "User 1"
|
||||
sharedWithDisplayName = "User 1"
|
||||
}
|
||||
} else {
|
||||
OCShare("/test.png")
|
||||
.apply {
|
||||
permissions = sharePermission
|
||||
attributes = attributesJson
|
||||
shareType = ShareType.INTERNAL
|
||||
sharedDate = 1188206955
|
||||
shareWith = "User 1"
|
||||
sharedWithDisplayName = "User 1"
|
||||
}
|
||||
}.apply {
|
||||
this.isFolder = isFolder
|
||||
}
|
||||
}
|
||||
|
||||
// region Permission change tests
|
||||
@Test
|
||||
fun testTogglePermissionShouldAddPermissionFlagWhenChecked() {
|
||||
val initialPermission = OCShare.READ_PERMISSION_FLAG
|
||||
val updatedPermission =
|
||||
SharePermissionManager.togglePermission(true, initialPermission, OCShare.UPDATE_PERMISSION_FLAG)
|
||||
val updatedShare = createShare(updatedPermission)
|
||||
assertTrue(SharePermissionManager.isCustomPermission(updatedShare))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTogglePermissionShouldRemovePermissionFlagWhenUnchecked() {
|
||||
val initialPermission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
|
||||
val updatedPermission =
|
||||
SharePermissionManager.togglePermission(false, initialPermission, OCShare.UPDATE_PERMISSION_FLAG)
|
||||
val updatedShare = createShare(updatedPermission)
|
||||
assertTrue(SharePermissionManager.isViewOnly(updatedShare))
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region HasPermissions tests
|
||||
@Test
|
||||
fun testHasPermissionShouldReturnTrueIfPermissionPresent() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
|
||||
assertTrue(SharePermissionManager.hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHasPermissionShouldReturnFalseIfPermissionNotPresent() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG
|
||||
assertFalse(SharePermissionManager.hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG))
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Helper Method Tests
|
||||
@Test
|
||||
fun testCanEditShouldReturnTrueIfAllPermissionsPresent() {
|
||||
val share = createShare(OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER, isFolder = true)
|
||||
assertTrue(SharePermissionManager.canEdit(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCanEditShouldReturnFalseIfPermissionsAreInsufficient() {
|
||||
val share = createShare(OCShare.READ_PERMISSION_FLAG)
|
||||
assertFalse(SharePermissionManager.canEdit(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsViewOnlyShouldReturnTrueIfOnlyReadPermissionSet() {
|
||||
val share = createShare(OCShare.READ_PERMISSION_FLAG)
|
||||
assertTrue(SharePermissionManager.isViewOnly(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsFileRequestShouldReturnTrueIfOnlyCreatePermissionSetOnFolder() {
|
||||
val share = createShare(OCShare.CREATE_PERMISSION_FLAG, isFolder = true)
|
||||
assertTrue(SharePermissionManager.isFileRequest(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsFileRequestShouldReturnFalseIfOnlyCreatePermissionSetOnFile() {
|
||||
val share = createShare(OCShare.CREATE_PERMISSION_FLAG)
|
||||
assertFalse(SharePermissionManager.isFileRequest(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsSecureFileDropShouldReturnTrueIfReadAndCreatePermissionsPresent() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
|
||||
val share = createShare(permission)
|
||||
assertTrue(SharePermissionManager.isSecureFileDrop(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCanReshareShouldReturnTrueIfSharePermissionIsPresent() {
|
||||
val share = createShare(OCShare.SHARE_PERMISSION_FLAG)
|
||||
assertTrue(SharePermissionManager.canReshare(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetMaximumPermissionForFolder() {
|
||||
assertEquals(
|
||||
OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER,
|
||||
SharePermissionManager.getMaximumPermission(isFolder = true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetMaximumPermissionForFile() {
|
||||
assertEquals(
|
||||
OCShare.MAXIMUM_PERMISSIONS_FOR_FILE,
|
||||
SharePermissionManager.getMaximumPermission(isFolder = false)
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region GetSelectedTypeTests
|
||||
@Test
|
||||
fun testGetSelectedTypeShouldReturnCanEditWhenFullPermissionsGiven() {
|
||||
val share = createShare(OCShare.MAXIMUM_PERMISSIONS_FOR_FILE)
|
||||
assertEquals(QuickPermissionType.CAN_EDIT, SharePermissionManager.getSelectedType(share, encrypted = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSelectedTypeShouldReturnSecureFileDropWhenEncryptedAndReadCreateGiven() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
|
||||
val share = createShare(permission)
|
||||
assertEquals(
|
||||
QuickPermissionType.SECURE_FILE_DROP,
|
||||
SharePermissionManager.getSelectedType(share, encrypted = true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSelectedTypeShouldReturnFileRequestWhenCreatePermissionGiven() {
|
||||
val share = createShare(OCShare.CREATE_PERMISSION_FLAG, isFolder = true)
|
||||
assertEquals(QuickPermissionType.FILE_REQUEST, SharePermissionManager.getSelectedType(share, encrypted = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSelectedTypeShouldReturnViewOnlyWhenReadPermissionGiven() {
|
||||
val share = createShare(OCShare.READ_PERMISSION_FLAG)
|
||||
assertEquals(QuickPermissionType.VIEW_ONLY, SharePermissionManager.getSelectedType(share, encrypted = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSelectedTypeShouldReturnCustomPermissionOnlyWhenCustomPermissionGiven() {
|
||||
val share = createShare(OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG)
|
||||
assertEquals(
|
||||
QuickPermissionType.CUSTOM_PERMISSIONS,
|
||||
SharePermissionManager.getSelectedType(share, encrypted = false)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSelectedTypeShouldReturnNoneOnlyWhenNoPermissionGiven() {
|
||||
val share = createShare(OCShare.NO_PERMISSION)
|
||||
assertEquals(
|
||||
QuickPermissionType.NONE,
|
||||
SharePermissionManager.getSelectedType(share, encrypted = false)
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region CustomPermissions Tests
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnFalseWhenNoPermissionsGiven() {
|
||||
val permission = OCShare.NO_PERMISSION
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertFalse(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnFalseWhenNoReadPermissionsGiven() {
|
||||
val permission = OCShare.SHARE_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertFalse(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnTrueWhenUpdatePermissionsGivenOnFile() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertTrue(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnTrueWhenUpdateAndSharePermissionsGivenOnFile() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG + OCShare.SHARE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertTrue(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnFalseWhenCreatePermissionsGivenOnFile() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertFalse(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnFalseWhenDeletePermissionsGivenOnFile() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.DELETE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertFalse(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnTrueWhenCreatePermissionsGivenOnFolder() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.CREATE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = true)
|
||||
assertTrue(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsCustomPermissionShouldReturnTrueWhenMixedPermissionsOnFile() {
|
||||
val permission = OCShare.READ_PERMISSION_FLAG + OCShare.UPDATE_PERMISSION_FLAG
|
||||
val share = createShare(permission, isFolder = false)
|
||||
assertTrue(SharePermissionManager.isCustomPermission(share))
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Attributes Tests
|
||||
@Test
|
||||
fun testToggleAllowDownloadAndSyncShouldCreateAttributeJsonIfNoneExists() {
|
||||
val json = SharePermissionManager.toggleAllowDownloadAndSync(true, null)
|
||||
assertNotNull(json)
|
||||
val downloadAttribute = ShareAttributes.createDownloadAttributes(true)
|
||||
val expectedJson = Gson().toJson(listOf(downloadAttribute))
|
||||
assertEquals(json, expectedJson)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsAllowDownloadAndSyncEnabledShouldReturnFalseIfAttributeIsMissing() {
|
||||
val share = createShare(OCShare.READ_PERMISSION_FLAG, attributesJson = null)
|
||||
assertFalse(SharePermissionManager.isAllowDownloadAndSyncEnabled(share))
|
||||
}
|
||||
// endregion
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -72,7 +72,8 @@ import com.owncloud.android.db.ProviderMeta
|
||||
AutoMigration(from = 85, to = 86, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class),
|
||||
AutoMigration(from = 86, to = 87, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class),
|
||||
AutoMigration(from = 87, to = 88, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class),
|
||||
AutoMigration(from = 88, to = 89)
|
||||
AutoMigration(from = 88, to = 89),
|
||||
AutoMigration(from = 89, to = 90)
|
||||
],
|
||||
exportSchema = true
|
||||
)
|
||||
|
@ -58,5 +58,7 @@ data class ShareEntity(
|
||||
@ColumnInfo(name = ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_LIMIT)
|
||||
val downloadLimitLimit: Int?,
|
||||
@ColumnInfo(name = ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT)
|
||||
val downloadLimitCount: Int?
|
||||
val downloadLimitCount: Int?,
|
||||
@ColumnInfo(name = ProviderTableMeta.OCSHARES_ATTRIBUTES)
|
||||
val attributes: String?
|
||||
)
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.utils.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.util.TypedValue
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.owncloud.android.R
|
||||
|
||||
@JvmOverloads
|
||||
fun ImageView.makeRoundedWithIcon(
|
||||
context: Context,
|
||||
@DrawableRes icon: Int,
|
||||
paddingDp: Int = 6,
|
||||
@ColorInt backgroundColor: Int = ContextCompat.getColor(context, R.color.primary),
|
||||
@ColorInt foregroundColor: Int = ContextCompat.getColor(context, R.color.white)
|
||||
) {
|
||||
setImageResource(icon)
|
||||
|
||||
val drawable = GradientDrawable().apply {
|
||||
shape = GradientDrawable.OVAL
|
||||
setColor(backgroundColor)
|
||||
}
|
||||
|
||||
background = drawable
|
||||
clipToOutline = true
|
||||
scaleType = ImageView.ScaleType.CENTER_INSIDE
|
||||
outlineProvider = ViewOutlineProvider.BACKGROUND
|
||||
|
||||
setColorFilter(foregroundColor)
|
||||
|
||||
val paddingPx = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
paddingDp.toFloat(),
|
||||
context.resources.displayMetrics
|
||||
).toInt()
|
||||
|
||||
setPadding(paddingPx, paddingPx, paddingPx, paddingPx)
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Your Name <your@email.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.utils.extensions
|
||||
|
||||
import com.owncloud.android.lib.resources.shares.OCShare
|
||||
|
||||
fun OCShare.hasFileRequestPermission(): Boolean {
|
||||
return (isFolder && shareType?.isPublicOrMail() == true)
|
||||
}
|
||||
|
||||
fun List<OCShare>.mergeDistinctByToken(other: List<OCShare>): List<OCShare> {
|
||||
return (this + other).distinctBy { it.token }
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.utils.extensions
|
||||
|
||||
import com.owncloud.android.lib.resources.shares.ShareType
|
||||
|
||||
fun ShareType.isPublicOrMail(): Boolean = (this == ShareType.PUBLIC_LINK || this == ShareType.EMAIL)
|
@ -7,6 +7,8 @@
|
||||
*/
|
||||
package com.nextcloud.utils.extensions
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.content.Context
|
||||
import android.graphics.Outline
|
||||
import android.util.TypedValue
|
||||
@ -19,6 +21,30 @@ fun View?.setVisibleIf(condition: Boolean) {
|
||||
visibility = if (condition) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
fun View?.setVisibilityWithAnimation(condition: Boolean, duration: Long = 200L) {
|
||||
this ?: return
|
||||
|
||||
if (condition) {
|
||||
this.apply {
|
||||
alpha = 0f
|
||||
visibility = View.VISIBLE
|
||||
animate()
|
||||
.alpha(1f)
|
||||
.setDuration(duration)
|
||||
.setListener(null)
|
||||
}
|
||||
} else {
|
||||
animate()
|
||||
.alpha(0f)
|
||||
.setDuration(duration)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
visibility = View.GONE
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun View?.makeRounded(context: Context, cornerRadius: Float) {
|
||||
this?.let {
|
||||
it.apply {
|
||||
|
@ -1569,6 +1569,8 @@ public class FileDataStorageManager {
|
||||
contentValues.putNull(ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT);
|
||||
}
|
||||
|
||||
contentValues.put(ProviderTableMeta.OCSHARES_ATTRIBUTES, share.getAttributes());
|
||||
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
@ -1599,6 +1601,8 @@ public class FileDataStorageManager {
|
||||
getInt(cursor, ProviderTableMeta.OCSHARES_DOWNLOADLIMIT_COUNT));
|
||||
share.setFileDownloadLimit(downloadLimit);
|
||||
|
||||
share.setAttributes(getString(cursor, ProviderTableMeta.OCSHARES_ATTRIBUTES));
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author TSI-mc
|
||||
* Copyright (C) 2021 TSI-mc
|
||||
* Copyright (C) 2021 Nextcloud GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
||||
*/
|
||||
|
||||
package com.owncloud.android.datamodel
|
||||
|
||||
data class QuickPermissionModel(val permissionName: String, val isSelected: Boolean)
|
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.owncloud.android.datamodel.quickPermission
|
||||
|
||||
data class QuickPermission(val type: QuickPermissionType, var isSelected: Boolean)
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.owncloud.android.datamodel.quickPermission
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.owncloud.android.R
|
||||
|
||||
enum class QuickPermissionType(
|
||||
val iconId: Int,
|
||||
val textId: Int
|
||||
) {
|
||||
NONE(R.drawable.ic_unknown, R.string.unknown),
|
||||
VIEW_ONLY(R.drawable.ic_eye, R.string.share_permission_view_only),
|
||||
CAN_EDIT(R.drawable.ic_edit, R.string.share_permission_can_edit),
|
||||
FILE_REQUEST(R.drawable.ic_file_request, R.string.share_permission_file_request),
|
||||
SECURE_FILE_DROP(R.drawable.ic_file_request, R.string.share_permission_secure_file_drop),
|
||||
CUSTOM_PERMISSIONS(R.drawable.ic_custom_permissions, R.string.share_custom_permission);
|
||||
|
||||
fun getText(context: Context): String = context.getString(textId)
|
||||
|
||||
fun getIcon(context: Context): Drawable? = ContextCompat.getDrawable(context, iconId)
|
||||
|
||||
companion object {
|
||||
fun getAvailablePermissions(
|
||||
hasFileRequestPermission: Boolean,
|
||||
selectedType: QuickPermissionType
|
||||
): List<QuickPermission> {
|
||||
val permissions = listOf(VIEW_ONLY, CAN_EDIT, FILE_REQUEST, CUSTOM_PERMISSIONS)
|
||||
val result = if (hasFileRequestPermission) permissions else permissions.filter { it != FILE_REQUEST }
|
||||
|
||||
return result.map { type ->
|
||||
QuickPermission(
|
||||
type = type,
|
||||
isSelected = (type == selectedType)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ import java.util.List;
|
||||
*/
|
||||
public class ProviderMeta {
|
||||
public static final String DB_NAME = "filelist";
|
||||
public static final int DB_VERSION = 89;
|
||||
public static final int DB_VERSION = 90;
|
||||
|
||||
private ProviderMeta() {
|
||||
// No instance
|
||||
@ -203,6 +203,7 @@ public class ProviderMeta {
|
||||
public static final String OCSHARES_SHARE_LABEL = "share_label";
|
||||
public static final String OCSHARES_DOWNLOADLIMIT_LIMIT = "download_limit_limit";
|
||||
public static final String OCSHARES_DOWNLOADLIMIT_COUNT = "download_limit_count";
|
||||
public static final String OCSHARES_ATTRIBUTES = "attributes";
|
||||
|
||||
public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE
|
||||
+ " collate nocase asc";
|
||||
|
@ -56,6 +56,7 @@ public class CreateShareWithShareeOperation extends SyncOperation {
|
||||
private String label;
|
||||
private final Context context;
|
||||
private final User user;
|
||||
private String attributes;
|
||||
|
||||
private ArbitraryDataProvider arbitraryDataProvider;
|
||||
|
||||
@ -85,6 +86,7 @@ public class CreateShareWithShareeOperation extends SyncOperation {
|
||||
String sharePassword,
|
||||
long expirationDateInMillis,
|
||||
boolean hideFileDownload,
|
||||
String attributes,
|
||||
FileDataStorageManager storageManager,
|
||||
Context context,
|
||||
User user,
|
||||
@ -105,6 +107,7 @@ public class CreateShareWithShareeOperation extends SyncOperation {
|
||||
this.context = context;
|
||||
this.user = user;
|
||||
this.arbitraryDataProvider = arbitraryDataProvider;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,7 +159,8 @@ public class CreateShareWithShareeOperation extends SyncOperation {
|
||||
false,
|
||||
sharePassword,
|
||||
permissions,
|
||||
noteMessage
|
||||
noteMessage,
|
||||
attributes
|
||||
);
|
||||
operation.setGetShareDetails(true);
|
||||
RemoteOperationResult shareResult = operation.execute(client);
|
||||
|
@ -113,6 +113,8 @@ public class UnshareOperation extends SyncOperation {
|
||||
|
||||
RemoveShareRemoteOperation operation = new RemoveShareRemoteOperation(share.getRemoteId());
|
||||
result = operation.execute(client);
|
||||
boolean isFileExists = existsFile(client, file.getRemotePath());
|
||||
boolean isShareExists = getStorageManager().getShareById(shareId) != null;
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// E2E: unlock folder
|
||||
@ -140,10 +142,12 @@ public class UnshareOperation extends SyncOperation {
|
||||
|
||||
getStorageManager().saveFile(file);
|
||||
getStorageManager().removeShare(share);
|
||||
|
||||
} else if (result.getCode() != ResultCode.MAINTENANCE_MODE && !existsFile(client, file.getRemotePath())) {
|
||||
// unshare failed because file was deleted before
|
||||
} else if (result.getCode() != ResultCode.MAINTENANCE_MODE && !isFileExists) {
|
||||
// UnShare failed because file was deleted before
|
||||
getStorageManager().removeFile(file, true, true);
|
||||
} else if (isShareExists && result.getCode() == ResultCode.FILE_NOT_FOUND) {
|
||||
// UnShare failed because share was deleted before
|
||||
getStorageManager().removeShare(share);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -35,6 +35,7 @@ public class UpdateShareInfoOperation extends SyncOperation {
|
||||
private int permissions = -1;
|
||||
private String password;
|
||||
private String label;
|
||||
private String attributes;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -78,7 +79,7 @@ public class UpdateShareInfoOperation extends SyncOperation {
|
||||
|
||||
if (share == null) {
|
||||
// TODO try to get remote share before failing?
|
||||
return new RemoteOperationResult(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND);
|
||||
return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Update remote share
|
||||
@ -93,11 +94,12 @@ public class UpdateShareInfoOperation extends SyncOperation {
|
||||
}
|
||||
updateOp.setPassword(password);
|
||||
updateOp.setLabel(label);
|
||||
updateOp.setAttributes(attributes);
|
||||
|
||||
RemoteOperationResult result = updateOp.execute(client);
|
||||
var result = updateOp.execute(client);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
RemoteOperation getShareOp = new GetShareRemoteOperation(share.getRemoteId());
|
||||
final var getShareOp = new GetShareRemoteOperation(share.getRemoteId());
|
||||
result = getShareOp.execute(client);
|
||||
|
||||
//only update the share in storage if shareId is available
|
||||
@ -125,6 +127,10 @@ public class UpdateShareInfoOperation extends SyncOperation {
|
||||
this.hideFileDownload = hideFileDownload;
|
||||
}
|
||||
|
||||
public void setAttributes(String attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public void setPermissions(int permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ public class OperationsService extends Service {
|
||||
public static final String EXTRA_SHARE_NOTE = "SHARE_NOTE";
|
||||
public static final String EXTRA_IN_BACKGROUND = "IN_BACKGROUND";
|
||||
public static final String EXTRA_FILES_DOWNLOAD_LIMIT = "FILES_DOWNLOAD_LIMIT";
|
||||
public static final String EXTRA_SHARE_ATTRIBUTES = "SHARE_ATTRIBUTES";
|
||||
|
||||
public static final String ACTION_CREATE_SHARE_VIA_LINK = "CREATE_SHARE_VIA_LINK";
|
||||
public static final String ACTION_CREATE_SECURE_FILE_DROP = "CREATE_SECURE_FILE_DROP";
|
||||
@ -437,6 +438,11 @@ public class OperationsService extends Service {
|
||||
// perform the operation
|
||||
try {
|
||||
result = mCurrentOperation.execute(mOwnCloudClient);
|
||||
if (!result.isSuccess()) {
|
||||
final var code = "code: " + result.getCode();
|
||||
final var httpCode = "HTTP_CODE: " + result.getHttpCode();
|
||||
Log_OC.e(TAG,"Operation failed " + code + httpCode);
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// TODO remove - added to aid in transition to NextcloudClient
|
||||
|
||||
@ -593,6 +599,8 @@ public class OperationsService extends Service {
|
||||
.getLongExtra(EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, 0L);
|
||||
boolean hideFileDownload = operationIntent.getBooleanExtra(EXTRA_SHARE_HIDE_FILE_DOWNLOAD,
|
||||
false);
|
||||
String attributes = operationIntent.getStringExtra(EXTRA_SHARE_ATTRIBUTES);
|
||||
|
||||
if (!TextUtils.isEmpty(remotePath)) {
|
||||
CreateShareWithShareeOperation createShareWithShareeOperation =
|
||||
new CreateShareWithShareeOperation(remotePath,
|
||||
@ -603,6 +611,7 @@ public class OperationsService extends Service {
|
||||
sharePassword,
|
||||
expirationDateInMillis,
|
||||
hideFileDownload,
|
||||
attributes,
|
||||
fileDataStorageManager,
|
||||
getApplicationContext(),
|
||||
user,
|
||||
@ -641,6 +650,9 @@ public class OperationsService extends Service {
|
||||
updateShare.setLabel(operationIntent.getStringExtra(EXTRA_SHARE_PUBLIC_LABEL));
|
||||
}
|
||||
|
||||
String shareAttributes = operationIntent.getStringExtra(EXTRA_SHARE_ATTRIBUTES);
|
||||
updateShare.setAttributes(shareAttributes);
|
||||
|
||||
operation = updateShare;
|
||||
}
|
||||
break;
|
||||
|
@ -426,8 +426,10 @@ public abstract class FileActivity extends DrawerActivity
|
||||
onCreateShareViaLinkOperationFinish((CreateShareViaLinkOperation) operation, result);
|
||||
} else if (operation instanceof CreateShareWithShareeOperation) {
|
||||
onUpdateShareInformation(result, R.string.sharee_add_failed);
|
||||
} else if (operation instanceof UpdateShareViaLinkOperation || operation instanceof UpdateShareInfoOperation || operation instanceof SetFilesDownloadLimitOperation) {
|
||||
} else if (operation instanceof UpdateShareViaLinkOperation || operation instanceof UpdateShareInfoOperation) {
|
||||
onUpdateShareInformation(result, R.string.updating_share_failed);
|
||||
} else if (operation instanceof SetFilesDownloadLimitOperation) {
|
||||
onUpdateShareInformation(result, R.string.set_download_limit_failed);
|
||||
} else if (operation instanceof UpdateSharePermissionsOperation) {
|
||||
onUpdateShareInformation(result, R.string.updating_share_failed);
|
||||
} else if (operation instanceof UnshareOperation) {
|
||||
|
@ -15,7 +15,6 @@
|
||||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
@ -23,9 +22,10 @@ import com.nextcloud.android.lib.resources.files.FileDownloadLimit;
|
||||
import com.nextcloud.utils.mdm.MDMConfig;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding;
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType;
|
||||
import com.owncloud.android.lib.resources.shares.OCShare;
|
||||
import com.owncloud.android.lib.resources.shares.ShareType;
|
||||
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
|
||||
import com.owncloud.android.ui.fragment.util.SharePermissionManager;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -36,6 +36,7 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder {
|
||||
private FileDetailsShareLinkShareItemBinding binding;
|
||||
private Context context;
|
||||
private ViewThemeUtils viewThemeUtils;
|
||||
private boolean encrypted;
|
||||
|
||||
public LinkShareViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
@ -43,40 +44,42 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public LinkShareViewHolder(FileDetailsShareLinkShareItemBinding binding,
|
||||
Context context,
|
||||
final ViewThemeUtils viewThemeUtils) {
|
||||
final ViewThemeUtils viewThemeUtils,
|
||||
boolean encrypted) {
|
||||
this(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.context = context;
|
||||
this.viewThemeUtils = viewThemeUtils;
|
||||
this.encrypted = encrypted;
|
||||
}
|
||||
|
||||
public void bind(OCShare publicShare, ShareeListAdapterListener listener) {
|
||||
public void bind(OCShare publicShare, ShareeListAdapterListener listener, int position) {
|
||||
if (ShareType.EMAIL == publicShare.getShareType()) {
|
||||
final var res = context.getResources();
|
||||
binding.name.setText(publicShare.getSharedWithDisplayName());
|
||||
binding.icon.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
|
||||
R.drawable.ic_email,
|
||||
null));
|
||||
|
||||
final var emailDrawable = ResourcesCompat.getDrawable(res, R.drawable.ic_email, null);
|
||||
binding.icon.setImageDrawable(emailDrawable);
|
||||
binding.copyLink.setVisibility(View.GONE);
|
||||
|
||||
binding.icon.getBackground().setColorFilter(context.getResources().getColor(R.color.nc_grey),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
binding.icon.getDrawable().mutate().setColorFilter(context.getResources().getColor(R.color.icon_on_nc_grey),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(publicShare.getLabel())) {
|
||||
String text = String.format(context.getString(R.string.share_link_with_label), publicShare.getLabel());
|
||||
binding.name.setText(text);
|
||||
} else {
|
||||
if (SharingMenuHelper.isSecureFileDrop(publicShare)) {
|
||||
binding.name.setText(context.getResources().getString(R.string.share_permission_secure_file_drop));
|
||||
} else {
|
||||
binding.name.setText(R.string.share_link);
|
||||
}
|
||||
}
|
||||
String label = publicShare.getLabel();
|
||||
|
||||
viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon);
|
||||
if (!TextUtils.isEmpty(label)) {
|
||||
binding.name.setText(context.getString(R.string.share_link_with_label, label));
|
||||
} else if (SharePermissionManager.INSTANCE.isFileRequest(publicShare)) {
|
||||
binding.name.setText(R.string.share_permission_file_request);
|
||||
} else if (SharePermissionManager.INSTANCE.isSecureFileDrop(publicShare) && encrypted) {
|
||||
binding.name.setText(R.string.share_permission_secure_file_drop);
|
||||
} else {
|
||||
int textRes = (position == 0) ? R.string.share_link : R.string.share_link_with_label;
|
||||
Object arg = (position == 0) ? null : String.valueOf(position);
|
||||
binding.name.setText((position == 0) ? context.getString(textRes)
|
||||
: context.getString(textRes, arg));
|
||||
}
|
||||
}
|
||||
|
||||
viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon);
|
||||
|
||||
FileDownloadLimit downloadLimit = publicShare.getFileDownloadLimit();
|
||||
if (downloadLimit != null && downloadLimit.getLimit() > 0) {
|
||||
int remaining = downloadLimit.getLimit() - downloadLimit.getCount();
|
||||
@ -88,11 +91,11 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder {
|
||||
binding.subline.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
String permissionName = SharingMenuHelper.getPermissionName(context, publicShare);
|
||||
setPermissionName(publicShare, permissionName);
|
||||
QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(publicShare, encrypted);
|
||||
setPermissionName(publicShare, quickPermissionType.getText(context));
|
||||
|
||||
binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare));
|
||||
if (!SharingMenuHelper.isSecureFileDrop(publicShare)) {
|
||||
if (!SharePermissionManager.INSTANCE.isSecureFileDrop(publicShare) && !encrypted) {
|
||||
binding.shareByLinkContainer.setOnClickListener(v -> listener.showPermissionsDialog(publicShare));
|
||||
}
|
||||
|
||||
@ -104,12 +107,13 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
|
||||
private void setPermissionName(OCShare publicShare, String permissionName) {
|
||||
if (!TextUtils.isEmpty(permissionName) && !SharingMenuHelper.isSecureFileDrop(publicShare)) {
|
||||
binding.permissionName.setText(permissionName);
|
||||
binding.permissionName.setVisibility(View.VISIBLE);
|
||||
viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName);
|
||||
} else {
|
||||
if (TextUtils.isEmpty(permissionName) || (SharePermissionManager.INSTANCE.isSecureFileDrop(publicShare) && encrypted)) {
|
||||
binding.permissionName.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
binding.permissionName.setText(permissionName);
|
||||
binding.permissionName.setVisibility(View.VISIBLE);
|
||||
viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName);
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,14 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding
|
||||
import com.owncloud.android.datamodel.QuickPermissionModel
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermission
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils
|
||||
|
||||
class QuickSharingPermissionsAdapter(
|
||||
private val quickPermissionList: MutableList<QuickPermissionModel>,
|
||||
private val quickPermissionList: MutableList<QuickPermission>,
|
||||
private val onPermissionChangeListener: QuickSharingPermissionViewHolder.OnPermissionChangeListener,
|
||||
private val viewThemeUtils: ViewThemeUtils
|
||||
) :
|
||||
@ -40,27 +42,35 @@ class QuickSharingPermissionsAdapter(
|
||||
}
|
||||
|
||||
class QuickSharingPermissionViewHolder(
|
||||
val binding: ItemQuickSharePermissionsBinding,
|
||||
private val binding: ItemQuickSharePermissionsBinding,
|
||||
itemView: View,
|
||||
val onPermissionChangeListener: OnPermissionChangeListener,
|
||||
private val onPermissionChangeListener: OnPermissionChangeListener,
|
||||
private val viewThemeUtils: ViewThemeUtils
|
||||
) :
|
||||
RecyclerView
|
||||
.ViewHolder(itemView) {
|
||||
) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bindData(quickPermissionModel: QuickPermissionModel) {
|
||||
binding.tvQuickShareName.text = quickPermissionModel.permissionName
|
||||
if (quickPermissionModel.isSelected) {
|
||||
viewThemeUtils.platform.colorImageView(binding.tvQuickShareCheckIcon)
|
||||
binding.tvQuickShareCheckIcon.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.tvQuickShareCheckIcon.visibility = View.INVISIBLE
|
||||
fun bindData(quickPermission: QuickPermission) {
|
||||
val context = itemView.context
|
||||
val permissionName = quickPermission.type.getText(context)
|
||||
|
||||
binding.run {
|
||||
quickPermissionButton.text = permissionName
|
||||
quickPermissionButton.iconGravity = MaterialButton.ICON_GRAVITY_START
|
||||
quickPermissionButton.icon = quickPermission.type.getIcon(context)
|
||||
|
||||
if (quickPermission.isSelected) {
|
||||
viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(quickPermissionButton)
|
||||
}
|
||||
}
|
||||
|
||||
val customPermissionName = context.getString(R.string.share_custom_permission)
|
||||
val isCustomPermission = permissionName.equals(customPermissionName, ignoreCase = true)
|
||||
|
||||
itemView.setOnClickListener {
|
||||
// if user select different options then only update the permission
|
||||
if (!quickPermissionModel.isSelected) {
|
||||
onPermissionChangeListener.onPermissionChanged(adapterPosition)
|
||||
if (isCustomPermission) {
|
||||
onPermissionChangeListener.onCustomPermissionSelected()
|
||||
} else if (!quickPermission.isSelected) {
|
||||
// if user select different options then only update the permission
|
||||
onPermissionChangeListener.onPermissionChanged(absoluteAdapterPosition)
|
||||
} else {
|
||||
// dismiss sheet on selection of same permission
|
||||
onPermissionChangeListener.onDismissSheet()
|
||||
@ -70,6 +80,7 @@ class QuickSharingPermissionsAdapter(
|
||||
|
||||
interface OnPermissionChangeListener {
|
||||
fun onPermissionChanged(position: Int)
|
||||
fun onCustomPermissionSelected()
|
||||
fun onDismissSheet()
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,16 @@ import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.utils.extensions.ImageViewExtensionsKt;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.databinding.FileDetailsShareShareItemBinding;
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType;
|
||||
import com.owncloud.android.lib.resources.shares.OCShare;
|
||||
import com.owncloud.android.ui.TextDrawable;
|
||||
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
|
||||
import com.owncloud.android.ui.fragment.util.SharePermissionManager;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@ -37,6 +38,7 @@ class ShareViewHolder extends RecyclerView.ViewHolder {
|
||||
private User user;
|
||||
private Context context;
|
||||
private ViewThemeUtils viewThemeUtils;
|
||||
private boolean encrypted;
|
||||
|
||||
public ShareViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
@ -45,12 +47,14 @@ class ShareViewHolder extends RecyclerView.ViewHolder {
|
||||
public ShareViewHolder(FileDetailsShareShareItemBinding binding,
|
||||
User user,
|
||||
Context context,
|
||||
final ViewThemeUtils viewThemeUtils) {
|
||||
final ViewThemeUtils viewThemeUtils,
|
||||
boolean encrypted) {
|
||||
this(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.user = user;
|
||||
this.context = context;
|
||||
this.viewThemeUtils = viewThemeUtils;
|
||||
this.encrypted = encrypted;
|
||||
}
|
||||
|
||||
public void bind(OCShare share,
|
||||
@ -67,47 +71,53 @@ class ShareViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
binding.icon.setTag(null);
|
||||
|
||||
switch (share.getShareType()) {
|
||||
case GROUP:
|
||||
name = context.getString(R.string.share_group_clarification, name);
|
||||
viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context);
|
||||
break;
|
||||
case ROOM:
|
||||
name = context.getString(R.string.share_room_clarification, name);
|
||||
viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context);
|
||||
break;
|
||||
case CIRCLE:
|
||||
viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context);
|
||||
break;
|
||||
case FEDERATED:
|
||||
name = context.getString(R.string.share_remote_clarification, name);
|
||||
setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_user);
|
||||
break;
|
||||
case USER:
|
||||
binding.icon.setTag(share.getShareWith());
|
||||
float avatarRadius = context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius);
|
||||
DisplayUtils.setAvatar(user,
|
||||
share.getShareWith(),
|
||||
share.getSharedWithDisplayName(),
|
||||
avatarListener,
|
||||
avatarRadius,
|
||||
context.getResources(),
|
||||
binding.icon,
|
||||
context);
|
||||
if (share.getShareType() != null) {
|
||||
switch (share.getShareType()) {
|
||||
case GROUP:
|
||||
name = context.getString(R.string.share_group_clarification, name);
|
||||
viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context);
|
||||
break;
|
||||
case ROOM:
|
||||
name = context.getString(R.string.share_room_clarification, name);
|
||||
viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context);
|
||||
break;
|
||||
case CIRCLE:
|
||||
viewThemeUtils.files.createAvatar(share.getShareType(), binding.icon, context);
|
||||
break;
|
||||
case FEDERATED:
|
||||
name = context.getString(R.string.share_remote_clarification, name);
|
||||
setImage(binding.icon, share.getSharedWithDisplayName());
|
||||
break;
|
||||
case USER:
|
||||
binding.icon.setTag(share.getShareWith());
|
||||
float avatarRadius = context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius);
|
||||
|
||||
binding.icon.setOnClickListener(v -> listener.showProfileBottomSheet(user, share.getShareWith()));
|
||||
default:
|
||||
setImage(binding.icon, name, R.drawable.ic_user);
|
||||
break;
|
||||
if (share.getShareWith() != null) {
|
||||
DisplayUtils.setAvatar(user,
|
||||
share.getShareWith(),
|
||||
share.getSharedWithDisplayName(),
|
||||
avatarListener,
|
||||
avatarRadius,
|
||||
context.getResources(),
|
||||
binding.icon,
|
||||
context);
|
||||
}
|
||||
|
||||
binding.icon.setOnClickListener(v -> listener.showProfileBottomSheet(user, share.getShareWith()));
|
||||
default:
|
||||
setImage(binding.icon, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
binding.name.setText(name);
|
||||
|
||||
if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
|
||||
if (share.getShareWith() != null && share.getShareWith().equalsIgnoreCase(userId) ||
|
||||
share.getUserId() != null && share.getUserId().equalsIgnoreCase(userId)) {
|
||||
binding.overflowMenu.setVisibility(View.VISIBLE);
|
||||
|
||||
String permissionName = SharingMenuHelper.getPermissionName(context, share);
|
||||
setPermissionName(permissionName);
|
||||
QuickPermissionType quickPermissionType = SharePermissionManager.INSTANCE.getSelectedType(share, encrypted);
|
||||
setPermissionName(quickPermissionType.getText(context));
|
||||
|
||||
// bind listener to edit privileges
|
||||
binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(share));
|
||||
@ -126,11 +136,21 @@ class ShareViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
}
|
||||
|
||||
private void setImage(ImageView avatar, String name, @DrawableRes int fallback) {
|
||||
private void setImage(ImageView avatar, String name) {
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
setUserImage(avatar);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
avatar.setImageResource(fallback);
|
||||
setUserImage(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUserImage(ImageView avatar) {
|
||||
ImageViewExtensionsKt.makeRoundedWithIcon(avatar, context, R.drawable.ic_user);
|
||||
viewThemeUtils.platform.colorImageViewBackgroundAndIcon(avatar);
|
||||
}
|
||||
}
|
||||
|
@ -79,57 +79,60 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return shares.get(position).getShareType().getValue();
|
||||
if (shares == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (position < 0 || position >= shares.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final var share = shares.get(position);
|
||||
if (share == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final var shareType = share.getShareType();
|
||||
if (shareType == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shareType.getValue();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
boolean shareViaLink = MDMConfig.INSTANCE.shareViaLink(fileActivity);
|
||||
final var parentViewGroup = LayoutInflater.from(fileActivity);
|
||||
|
||||
if (shareViaLink) {
|
||||
switch (ShareType.fromValue(viewType)) {
|
||||
case PUBLIC_LINK, EMAIL -> {
|
||||
return new LinkShareViewHolder(
|
||||
FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
parent,
|
||||
false),
|
||||
fileActivity,
|
||||
viewThemeUtils);
|
||||
}
|
||||
case NEW_PUBLIC_LINK -> {
|
||||
if (encrypted) {
|
||||
return new NewSecureFileDropViewHolder(
|
||||
FileDetailsShareSecureFileDropAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
parent,
|
||||
false)
|
||||
);
|
||||
} else {
|
||||
return new NewLinkShareViewHolder(
|
||||
FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
parent,
|
||||
false)
|
||||
);
|
||||
}
|
||||
}
|
||||
case INTERNAL -> {
|
||||
return new InternalShareViewHolder(
|
||||
FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
|
||||
fileActivity);
|
||||
}
|
||||
default -> {
|
||||
return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(fileActivity),
|
||||
parent,
|
||||
false),
|
||||
user,
|
||||
fileActivity,
|
||||
viewThemeUtils);
|
||||
if (!shareViaLink) {
|
||||
final var binding = FileDetailsShareInternalShareLinkBinding.inflate(parentViewGroup, parent, false);
|
||||
return new InternalShareViewHolder(binding, fileActivity);
|
||||
}
|
||||
|
||||
switch (ShareType.fromValue(viewType)) {
|
||||
case PUBLIC_LINK, EMAIL -> {
|
||||
final var binding = FileDetailsShareLinkShareItemBinding.inflate(parentViewGroup, parent, false);
|
||||
return new LinkShareViewHolder(binding, fileActivity, viewThemeUtils, encrypted);
|
||||
}
|
||||
case NEW_PUBLIC_LINK -> {
|
||||
if (encrypted) {
|
||||
final var binding = FileDetailsShareSecureFileDropAddNewItemBinding.inflate(parentViewGroup, parent, false);
|
||||
return new NewSecureFileDropViewHolder(binding);
|
||||
} else {
|
||||
final var binding = FileDetailsSharePublicLinkAddNewItemBinding.inflate(parentViewGroup, parent, false);
|
||||
return new NewLinkShareViewHolder(binding);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return new InternalShareViewHolder(
|
||||
FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
|
||||
fileActivity);
|
||||
case INTERNAL -> {
|
||||
final var binding = FileDetailsShareInternalShareLinkBinding.inflate(parentViewGroup, parent, false);
|
||||
return new InternalShareViewHolder(binding, fileActivity);
|
||||
}
|
||||
default -> {
|
||||
final var binding = FileDetailsShareShareItemBinding.inflate(parentViewGroup, parent, false);
|
||||
return new ShareViewHolder(binding, user, fileActivity, viewThemeUtils, encrypted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +155,7 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
}
|
||||
|
||||
if (holder instanceof LinkShareViewHolder publicShareViewHolder) {
|
||||
publicShareViewHolder.bind(share, listener);
|
||||
publicShareViewHolder.bind(share, listener, position);
|
||||
} else if (holder instanceof InternalShareViewHolder internalShareViewHolder) {
|
||||
internalShareViewHolder.bind(share, listener);
|
||||
} else if (holder instanceof NewLinkShareViewHolder newLinkShareViewHolder) {
|
||||
@ -186,7 +189,7 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
public void toggleShowAll() {
|
||||
this.showAll = !this.showAll;
|
||||
showAll = !showAll;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@ -201,6 +204,12 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
public void removeAll() {
|
||||
shares.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
|
||||
if (callContext instanceof ImageView iv) {
|
||||
@ -217,10 +226,12 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
public void remove(OCShare share) {
|
||||
shares.remove(share);
|
||||
notifyDataSetChanged();
|
||||
int position = shares.indexOf(share);
|
||||
if (position != -1) {
|
||||
shares.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,13 +266,4 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
public List<OCShare> getShares() {
|
||||
return shares;
|
||||
}
|
||||
|
||||
public void removeNewPublicShare() {
|
||||
for (OCShare share : shares) {
|
||||
if (share.getShareType() == ShareType.NEW_PUBLIC_LINK) {
|
||||
shares.remove(share);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ import org.greenrobot.eventbus.ThreadMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -509,11 +510,11 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
||||
setFileModificationTimestamp(getFile(), showDetailedTimestamp);
|
||||
} else if (id == R.id.folder_sync_button) {
|
||||
if (binding.folderSyncButton.isChecked()) {
|
||||
getFile().setInternalFolderSyncTimestamp(0L);
|
||||
getFile().setInternalFolderSyncTimestamp(0L);
|
||||
} else {
|
||||
getFile().setInternalFolderSyncTimestamp(-1L);
|
||||
}
|
||||
|
||||
|
||||
storageManager.saveFile(getFile());
|
||||
} else {
|
||||
Log_OC.e(TAG, "Incorrect view clicked!");
|
||||
@ -598,11 +599,11 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
||||
if (fabMain != null) {
|
||||
fabMain.hide();
|
||||
}
|
||||
|
||||
|
||||
binding.syncBlock.setVisibility(file.isFolder() ? View.VISIBLE : View.GONE);
|
||||
|
||||
|
||||
if (file.isInternalFolderSync()) {
|
||||
binding.folderSyncButton.setChecked(file.isInternalFolderSync());
|
||||
binding.folderSyncButton.setChecked(file.isInternalFolderSync());
|
||||
} else {
|
||||
if (storageManager.isPartOfInternalTwoWaySync(file)) {
|
||||
binding.folderSyncButton.setChecked(true);
|
||||
@ -814,18 +815,27 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
||||
/**
|
||||
* open the sharing process fragment for creating new share
|
||||
*
|
||||
* @param shareeName
|
||||
* @param shareType
|
||||
*/
|
||||
public void initiateSharingProcess(String shareeName,
|
||||
ShareType shareType,
|
||||
boolean secureShare) {
|
||||
requireActivity().getSupportFragmentManager().beginTransaction().add(R.id.sharing_frame_container,
|
||||
FileDetailsSharingProcessFragment.newInstance(getFile(),
|
||||
shareeName,
|
||||
shareType,
|
||||
secureShare),
|
||||
FileDetailsSharingProcessFragment.TAG)
|
||||
if (getFile() == null) {
|
||||
DisplayUtils.showSnackMessage(requireView(), R.string.file_not_found_cannot_share);
|
||||
return;
|
||||
}
|
||||
|
||||
final var file = getFile();
|
||||
if (Objects.equals(file.getOwnerId(), shareeName)) {
|
||||
DisplayUtils.showSnackMessage(requireView(), R.string.file_detail_share_already_active);
|
||||
return;
|
||||
}
|
||||
|
||||
final var fileShareDetailFragment = FileDetailsSharingProcessFragment.newInstance(file, shareeName, shareType, secureShare);
|
||||
|
||||
requireActivity()
|
||||
.getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.add(R.id.sharing_frame_container, fileShareDetailFragment, FileDetailsSharingProcessFragment.TAG)
|
||||
.commit();
|
||||
|
||||
showHideFragmentView(true);
|
||||
|
@ -37,6 +37,7 @@ import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.nextcloud.utils.extensions.BundleExtensionsKt;
|
||||
import com.nextcloud.utils.extensions.FileExtensionsKt;
|
||||
import com.nextcloud.utils.extensions.OCShareExtensionsKt;
|
||||
import com.nextcloud.utils.extensions.ViewExtensionsKt;
|
||||
import com.nextcloud.utils.mdm.MDMConfig;
|
||||
import com.owncloud.android.R;
|
||||
@ -178,6 +179,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
file.isEncrypted(),
|
||||
SharesType.INTERNAL);
|
||||
|
||||
internalShareeListAdapter.setHasStableIds(true);
|
||||
|
||||
binding.sharesListInternal.setAdapter(internalShareeListAdapter);
|
||||
|
||||
binding.sharesListInternal.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
@ -190,6 +193,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
viewThemeUtils,
|
||||
file.isEncrypted(),
|
||||
SharesType.EXTERNAL);
|
||||
|
||||
externalShareeListAdapter.setHasStableIds(true);
|
||||
|
||||
binding.sharesListExternal.setAdapter(externalShareeListAdapter);
|
||||
|
||||
@ -214,10 +219,11 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
if (!(getActivity() instanceof FileActivity)) {
|
||||
throw new IllegalArgumentException("Calling activity must be of type FileActivity");
|
||||
}
|
||||
|
||||
try {
|
||||
onEditShareListener = (OnEditShareListener) context;
|
||||
} catch (Exception ignored) {
|
||||
throw new IllegalArgumentException("Calling activity must implement the interface", ignored);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Calling activity must implement the interface" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,23 +253,15 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
viewThemeUtils.material.colorMaterialTextButton(binding.sharesListInternalShowAll);
|
||||
binding.sharesListInternalShowAll.setOnClickListener(view -> {
|
||||
internalShareeListAdapter.toggleShowAll();
|
||||
|
||||
if (internalShareeListAdapter.isShowAll()) {
|
||||
binding.sharesListInternalShowAll.setText(R.string.show_less);
|
||||
} else {
|
||||
binding.sharesListInternalShowAll.setText(R.string.show_all);
|
||||
}
|
||||
int textRes = internalShareeListAdapter.isShowAll() ? R.string.show_less : R.string.show_all;
|
||||
binding.sharesListInternalShowAll.setText(textRes);
|
||||
});
|
||||
|
||||
|
||||
viewThemeUtils.material.colorMaterialTextButton(binding.sharesListExternalShowAll);
|
||||
binding.sharesListExternalShowAll.setOnClickListener(view -> {
|
||||
externalShareeListAdapter.toggleShowAll();
|
||||
|
||||
if (internalShareeListAdapter.isShowAll()) {
|
||||
binding.sharesListExternalShowAll.setText(R.string.show_less);
|
||||
} else {
|
||||
binding.sharesListExternalShowAll.setText(R.string.show_all);
|
||||
}
|
||||
int textRes = externalShareeListAdapter.isShowAll() ? R.string.show_less : R.string.show_all;
|
||||
binding.sharesListExternalShowAll.setText(textRes);
|
||||
});
|
||||
|
||||
if (file.canReshare() && !FileDetailSharingFragmentHelper.isPublicShareDisabled(capabilities)) {
|
||||
@ -409,7 +407,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
@VisibleForTesting
|
||||
public void showSharingMenuActionSheet(OCShare share) {
|
||||
if (fileActivity != null && !fileActivity.isFinishing()) {
|
||||
new FileDetailSharingMenuBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show();
|
||||
new FileDetailSharingMenuBottomSheetDialog(fileActivity, this, share, viewThemeUtils, file.isEncrypted()).show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,7 +418,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
*/
|
||||
@Override
|
||||
public void showPermissionsDialog(OCShare share) {
|
||||
new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show();
|
||||
new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils, file.isEncrypted()).show();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -460,8 +458,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
setupView();
|
||||
}
|
||||
|
||||
private void unshareWith(OCShare share) {
|
||||
fileOperationsHelper.unshareShare(file, share);
|
||||
private void unShareWith(OCShare share) {
|
||||
fileOperationsHelper.unShareShare(file, share);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -517,7 +515,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
DisplayUtils.showSnackMessage(getView(), getString(R.string.could_not_retrieve_shares));
|
||||
return;
|
||||
}
|
||||
internalShareeListAdapter.getShares().clear();
|
||||
|
||||
internalShareeListAdapter.removeAll();
|
||||
|
||||
// to show share with users/groups info
|
||||
List<OCShare> shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(),
|
||||
@ -544,25 +543,17 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
}
|
||||
|
||||
internalShareeListAdapter.addShares(internalShares);
|
||||
ViewExtensionsKt.setVisibleIf(binding.sharesListInternalShowAll, internalShareeListAdapter.getShares().size() > 3);
|
||||
|
||||
ViewExtensionsKt.setVisibleIf(binding.sharesListInternalShowAll,
|
||||
internalShareeListAdapter.getShares().size() > 3
|
||||
);
|
||||
addExternalAndPublicShares(externalShares);
|
||||
ViewExtensionsKt.setVisibleIf(binding.sharesListExternalShowAll, externalShareeListAdapter.getShares().size() > 3);
|
||||
}
|
||||
|
||||
externalShareeListAdapter.getShares().clear();
|
||||
|
||||
// Get public share
|
||||
List<OCShare> publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(),
|
||||
ShareType.PUBLIC_LINK,
|
||||
"");
|
||||
|
||||
externalShareeListAdapter.addShares(externalShares);
|
||||
|
||||
externalShareeListAdapter.addShares(publicShares);
|
||||
|
||||
ViewExtensionsKt.setVisibleIf(binding.sharesListExternalShowAll,
|
||||
externalShareeListAdapter.getShares().size() > 3
|
||||
);
|
||||
private void addExternalAndPublicShares(List<OCShare> externalShares) {
|
||||
final var publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), ShareType.PUBLIC_LINK, "");
|
||||
externalShareeListAdapter.removeAll();
|
||||
final var shares = OCShareExtensionsKt.mergeDistinctByToken(externalShares, publicShares);
|
||||
externalShareeListAdapter.addShares(shares);
|
||||
}
|
||||
|
||||
private void checkContactPermission() {
|
||||
@ -650,7 +641,6 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sendNewEmail(OCShare share) {
|
||||
modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_NOTE);
|
||||
@ -658,13 +648,15 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
|
||||
@Override
|
||||
public void unShare(OCShare share) {
|
||||
unshareWith(share);
|
||||
ShareeListAdapter adapter = (ShareeListAdapter) binding.sharesListInternal.getAdapter();
|
||||
if (adapter == null) {
|
||||
unShareWith(share);
|
||||
|
||||
if (binding.sharesListInternal.getAdapter() instanceof ShareeListAdapter adapter) {
|
||||
adapter.remove(share);
|
||||
} else if (binding.sharesListExternal.getAdapter() instanceof ShareeListAdapter adapter) {
|
||||
adapter.remove(share);
|
||||
} else {
|
||||
DisplayUtils.showSnackMessage(getView(), getString(R.string.failed_update_ui));
|
||||
return;
|
||||
}
|
||||
adapter.remove(share);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -691,6 +683,11 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
|
||||
fileOperationsHelper.setPermissionsToShare(share, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openShareDetailWithCustomPermissions(OCShare share) {
|
||||
modifyExistingShare(share, FileDetailsSharingProcessFragment.SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION);
|
||||
}
|
||||
|
||||
//launcher for contact permission
|
||||
private final ActivityResultLauncher<String> requestContactPermissionLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
|
||||
|
@ -16,12 +16,13 @@ import android.view.ViewGroup;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
|
||||
import com.nextcloud.utils.mdm.MDMConfig;
|
||||
import com.owncloud.android.databinding.FileDetailsSharingMenuBottomSheetFragmentBinding;
|
||||
import com.owncloud.android.lib.resources.shares.OCShare;
|
||||
import com.owncloud.android.lib.resources.shares.ShareType;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
|
||||
import com.owncloud.android.ui.fragment.util.SharePermissionManager;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
||||
/**
|
||||
@ -32,14 +33,18 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog {
|
||||
private final FileDetailsSharingMenuBottomSheetActions actions;
|
||||
private final OCShare ocShare;
|
||||
private final ViewThemeUtils viewThemeUtils;
|
||||
private final boolean encrypted;
|
||||
|
||||
public FileDetailSharingMenuBottomSheetDialog(FileActivity fileActivity,
|
||||
FileDetailsSharingMenuBottomSheetActions actions,
|
||||
OCShare ocShare,
|
||||
ViewThemeUtils viewThemeUtils) {
|
||||
ViewThemeUtils viewThemeUtils,
|
||||
boolean encrypted) {
|
||||
super(fileActivity);
|
||||
this.actions = actions;
|
||||
this.ocShare = ocShare;
|
||||
this.viewThemeUtils = viewThemeUtils;
|
||||
this.encrypted = encrypted;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,10 +59,10 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog {
|
||||
|
||||
viewThemeUtils.platform.themeDialog(binding.getRoot());
|
||||
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconAdvancedPermissions);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconSendLink);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconUnshare);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconSendNewEmail);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconAdvancedPermissions, ColorRole.PRIMARY);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconSendLink, ColorRole.PRIMARY);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconUnshare, ColorRole.PRIMARY);
|
||||
viewThemeUtils.platform.colorImageView(binding.menuIconSendNewEmail, ColorRole.PRIMARY);
|
||||
|
||||
updateUI();
|
||||
|
||||
@ -78,7 +83,7 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog {
|
||||
binding.menuShareSendLink.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (SharingMenuHelper.isSecureFileDrop(ocShare)) {
|
||||
if (SharePermissionManager.INSTANCE.isSecureFileDrop(ocShare) && encrypted) {
|
||||
binding.menuShareAdvancedPermissions.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
/*
|
||||
* Nextcloud Android client application
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* @author TSI-mc
|
||||
* Copyright (C) 2021 TSI-mc
|
||||
* Copyright (C) 2021 Nextcloud GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.fragment
|
||||
@ -21,17 +18,20 @@ import androidx.fragment.app.Fragment
|
||||
import com.nextcloud.client.di.Injectable
|
||||
import com.nextcloud.utils.extensions.getParcelableArgument
|
||||
import com.nextcloud.utils.extensions.getSerializableArgument
|
||||
import com.nextcloud.utils.extensions.isPublicOrMail
|
||||
import com.nextcloud.utils.extensions.setVisibilityWithAnimation
|
||||
import com.nextcloud.utils.extensions.setVisibleIf
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
import com.owncloud.android.lib.resources.shares.OCShare
|
||||
import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder
|
||||
import com.owncloud.android.lib.resources.shares.ShareType
|
||||
import com.owncloud.android.lib.resources.status.OCCapability
|
||||
import com.owncloud.android.ui.activity.FileActivity
|
||||
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment
|
||||
import com.owncloud.android.ui.fragment.util.SharingMenuHelper
|
||||
import com.owncloud.android.ui.fragment.util.SharePermissionManager
|
||||
import com.owncloud.android.ui.helpers.FileOperationsHelper
|
||||
import com.owncloud.android.utils.ClipboardUtil
|
||||
import com.owncloud.android.utils.DisplayUtils
|
||||
@ -69,6 +69,7 @@ class FileDetailsSharingProcessFragment :
|
||||
// types of screens to be displayed
|
||||
const val SCREEN_TYPE_PERMISSION = 1 // permissions screen
|
||||
const val SCREEN_TYPE_NOTE = 2 // note screen
|
||||
const val SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION = 3 // permissions screen with custom permission
|
||||
|
||||
/**
|
||||
* fragment instance to be called while creating new share for internal and external share
|
||||
@ -80,14 +81,16 @@ class FileDetailsSharingProcessFragment :
|
||||
shareType: ShareType,
|
||||
secureShare: Boolean
|
||||
): FileDetailsSharingProcessFragment {
|
||||
val args = Bundle()
|
||||
args.putParcelable(ARG_OCFILE, file)
|
||||
args.putSerializable(ARG_SHARE_TYPE, shareType)
|
||||
args.putString(ARG_SHAREE_NAME, shareeName)
|
||||
args.putBoolean(ARG_SECURE_SHARE, secureShare)
|
||||
val fragment = FileDetailsSharingProcessFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
val bundle = Bundle().apply {
|
||||
putParcelable(ARG_OCFILE, file)
|
||||
putSerializable(ARG_SHARE_TYPE, shareType)
|
||||
putString(ARG_SHAREE_NAME, shareeName)
|
||||
putBoolean(ARG_SECURE_SHARE, secureShare)
|
||||
}
|
||||
|
||||
return FileDetailsSharingProcessFragment().apply {
|
||||
arguments = bundle
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,14 +103,16 @@ class FileDetailsSharingProcessFragment :
|
||||
isReshareShown: Boolean,
|
||||
isExpirationDateShown: Boolean
|
||||
): FileDetailsSharingProcessFragment {
|
||||
val args = Bundle()
|
||||
args.putParcelable(ARG_OCSHARE, share)
|
||||
args.putInt(ARG_SCREEN_TYPE, screenType)
|
||||
args.putBoolean(ARG_RESHARE_SHOWN, isReshareShown)
|
||||
args.putBoolean(ARG_EXP_DATE_SHOWN, isExpirationDateShown)
|
||||
val fragment = FileDetailsSharingProcessFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
val bundle = Bundle().apply {
|
||||
putParcelable(ARG_OCSHARE, share)
|
||||
putInt(ARG_SCREEN_TYPE, screenType)
|
||||
putBoolean(ARG_RESHARE_SHOWN, isReshareShown)
|
||||
putBoolean(ARG_EXP_DATE_SHOWN, isExpirationDateShown)
|
||||
}
|
||||
|
||||
return FileDetailsSharingProcessFragment().apply {
|
||||
arguments = bundle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,12 +140,13 @@ class FileDetailsSharingProcessFragment :
|
||||
private lateinit var capabilities: OCCapability
|
||||
|
||||
private var expirationDatePickerFragment: ExpirationDatePickerDialogFragment? = null
|
||||
private var downloadAttribute: String? = null
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
try {
|
||||
onEditShareListener = context as FileDetailSharingFragment.OnEditShareListener
|
||||
} catch (e: ClassCastException) {
|
||||
} catch (_: ClassCastException) {
|
||||
throw IllegalStateException("Calling activity must implement the interface")
|
||||
}
|
||||
}
|
||||
@ -148,6 +154,18 @@ class FileDetailsSharingProcessFragment :
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
initArguments()
|
||||
fileActivity = activity as FileActivity?
|
||||
capabilities = CapabilityUtils.getCapability(context)
|
||||
|
||||
requireNotNull(fileActivity) { "FileActivity may not be null" }
|
||||
|
||||
permission = share?.permissions
|
||||
?: capabilities.defaultPermissions
|
||||
?: SharePermissionManager.getMaximumPermission(isFolder())
|
||||
}
|
||||
|
||||
private fun initArguments() {
|
||||
arguments?.let {
|
||||
file = it.getParcelableArgument(ARG_OCFILE, OCFile::class.java)
|
||||
shareeName = it.getString(ARG_SHAREE_NAME)
|
||||
@ -164,13 +182,6 @@ class FileDetailsSharingProcessFragment :
|
||||
isExpDateShown = it.getBoolean(ARG_EXP_DATE_SHOWN, true)
|
||||
isSecureShare = it.getBoolean(ARG_SECURE_SHARE, false)
|
||||
}
|
||||
|
||||
fileActivity = activity as FileActivity?
|
||||
capabilities = CapabilityUtils.getCapability(context)
|
||||
|
||||
requireNotNull(fileActivity) { "FileActivity may not be null" }
|
||||
|
||||
permission = capabilities.defaultPermissions ?: OCShare.NO_PERMISSION
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
@ -181,39 +192,84 @@ class FileDetailsSharingProcessFragment :
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (shareProcessStep == SCREEN_TYPE_PERMISSION) {
|
||||
showShareProcessFirst()
|
||||
if (isShareProcessStepIsPermission()) {
|
||||
setupUI()
|
||||
} else {
|
||||
showShareProcessSecond()
|
||||
updateViewForNoteScreenType()
|
||||
}
|
||||
implementClickEvents()
|
||||
|
||||
implementClickEvents()
|
||||
setCheckboxStates()
|
||||
themeView()
|
||||
setVisibilitiesOfShareOption()
|
||||
toggleNextButtonAvailability(isAnyShareOptionChecked())
|
||||
logShareInfo()
|
||||
}
|
||||
|
||||
private fun logShareInfo() {
|
||||
share?.run {
|
||||
Log_OC.i(TAG, "-----BEFORE UPDATE SHARE-----")
|
||||
Log_OC.i(TAG, "ID: $id")
|
||||
Log_OC.i(TAG, "Permission: $permissions")
|
||||
Log_OC.i(TAG, "Hide File Download: $isHideFileDownload")
|
||||
Log_OC.i(TAG, "Label: $label")
|
||||
Log_OC.i(TAG, "Attributes: $attributes")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVisibilitiesOfShareOption() {
|
||||
binding.run {
|
||||
shareAllowDownloadAndSyncCheckbox.setVisibleIf(!isPublicShare())
|
||||
fileRequestRadioButton.setVisibleIf(canSetFileRequest())
|
||||
}
|
||||
}
|
||||
|
||||
private fun themeView() {
|
||||
viewThemeUtils.platform.colorTextView(binding.shareProcessEditShareLink)
|
||||
viewThemeUtils.platform.colorTextView(binding.shareProcessAdvancePermissionTitle)
|
||||
viewThemeUtils.platform.run {
|
||||
binding.run {
|
||||
colorTextView(shareProcessEditShareLink)
|
||||
colorTextView(shareCustomPermissionsText)
|
||||
|
||||
viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionReadOnly)
|
||||
viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionUploadEditing)
|
||||
viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionFileDrop)
|
||||
themeRadioButton(viewOnlyRadioButton)
|
||||
themeRadioButton(canEditRadioButton)
|
||||
themeRadioButton(customPermissionRadioButton)
|
||||
|
||||
viewThemeUtils.platform.themeCheckbox(binding.shareProcessAllowResharingCheckbox)
|
||||
if (!isPublicShare()) {
|
||||
themeCheckbox(shareAllowDownloadAndSyncCheckbox)
|
||||
}
|
||||
|
||||
viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetPasswordSwitch)
|
||||
viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetExpDateSwitch)
|
||||
viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetDownloadLimitSwitch)
|
||||
viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessHideDownloadCheckbox)
|
||||
viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessChangeNameSwitch)
|
||||
if (canSetFileRequest()) {
|
||||
themeRadioButton(fileRequestRadioButton)
|
||||
}
|
||||
|
||||
viewThemeUtils.material.colorTextInputLayout(binding.shareProcessEnterPasswordContainer)
|
||||
viewThemeUtils.material.colorTextInputLayout(binding.shareProcessSetDownloadLimitInputContainer)
|
||||
viewThemeUtils.material.colorTextInputLayout(binding.shareProcessChangeNameContainer)
|
||||
viewThemeUtils.material.colorTextInputLayout(binding.noteContainer)
|
||||
themeCheckbox(shareReadCheckbox)
|
||||
themeCheckbox(shareCreateCheckbox)
|
||||
themeCheckbox(shareEditCheckbox)
|
||||
themeCheckbox(shareCheckbox)
|
||||
themeCheckbox(shareDeleteCheckbox)
|
||||
}
|
||||
}
|
||||
|
||||
viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.shareProcessBtnNext)
|
||||
viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.shareProcessBtnCancel)
|
||||
viewThemeUtils.androidx.run {
|
||||
binding.run {
|
||||
colorSwitchCompat(shareProcessSetPasswordSwitch)
|
||||
colorSwitchCompat(shareProcessSetExpDateSwitch)
|
||||
colorSwitchCompat(shareProcessSetDownloadLimitSwitch)
|
||||
colorSwitchCompat(shareProcessHideDownloadCheckbox)
|
||||
colorSwitchCompat(shareProcessChangeNameSwitch)
|
||||
}
|
||||
}
|
||||
|
||||
viewThemeUtils.material.run {
|
||||
binding.run {
|
||||
colorTextInputLayout(shareProcessEnterPasswordContainer)
|
||||
colorTextInputLayout(shareProcessSetDownloadLimitInputContainer)
|
||||
colorTextInputLayout(shareProcessChangeNameContainer)
|
||||
colorTextInputLayout(noteContainer)
|
||||
colorMaterialButtonPrimaryFilled(shareProcessBtnNext)
|
||||
colorMaterialButtonPrimaryOutlined(shareProcessBtnCancel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
@ -229,40 +285,63 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun showShareProcessFirst() {
|
||||
binding.shareProcessGroupOne.visibility = View.VISIBLE
|
||||
binding.shareProcessEditShareLink.visibility = View.VISIBLE
|
||||
binding.shareProcessGroupTwo.visibility = View.GONE
|
||||
|
||||
if (share != null) {
|
||||
setupModificationUI()
|
||||
} else {
|
||||
setupUpdateUI()
|
||||
private fun setupUI() {
|
||||
binding.run {
|
||||
shareProcessGroupOne.visibility = View.VISIBLE
|
||||
shareProcessEditShareLink.visibility = View.VISIBLE
|
||||
shareProcessGroupTwo.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (isSecureShare) {
|
||||
binding.shareProcessAdvancePermissionTitle.visibility = View.GONE
|
||||
}
|
||||
updateView()
|
||||
|
||||
// show or hide expiry date
|
||||
if (isExpDateShown && !isSecureShare) {
|
||||
binding.shareProcessSetExpDateSwitch.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.shareProcessSetExpDateSwitch.visibility = View.GONE
|
||||
}
|
||||
binding.shareProcessSetExpDateSwitch.setVisibleIf(isExpDateShown && !isSecureShare)
|
||||
shareProcessStep = SCREEN_TYPE_PERMISSION
|
||||
}
|
||||
|
||||
private fun setupModificationUI() {
|
||||
private fun updateView() {
|
||||
if (share != null) {
|
||||
updateViewForUpdate()
|
||||
} else {
|
||||
updateViewForCreate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMaxPermissionsIfDefaultPermissionExists() {
|
||||
if (capabilities.defaultPermissions != null) {
|
||||
binding.canEditRadioButton.isChecked = true
|
||||
permission = SharePermissionManager.getMaximumPermission(isFolder())
|
||||
}
|
||||
}
|
||||
|
||||
// region ViewUpdates
|
||||
private fun updateViewForCreate() {
|
||||
binding.shareProcessBtnNext.text = getString(R.string.common_next)
|
||||
updateViewAccordingToFile()
|
||||
showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked)
|
||||
showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked)
|
||||
showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked)
|
||||
setMaxPermissionsIfDefaultPermissionExists()
|
||||
}
|
||||
|
||||
private fun updateViewAccordingToFile() {
|
||||
file?.run {
|
||||
if (isFolder == true) {
|
||||
updateViewForFolder()
|
||||
} else {
|
||||
updateViewForFile()
|
||||
}
|
||||
updateViewForShareType()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateViewForUpdate() {
|
||||
if (share?.isFolder == true) updateViewForFolder() else updateViewForFile()
|
||||
|
||||
// read only / allow upload and editing / file drop
|
||||
if (SharingMenuHelper.isUploadAndEditingAllowed(share)) {
|
||||
binding.shareProcessPermissionUploadEditing.isChecked = true
|
||||
} else if (SharingMenuHelper.isFileDrop(share) && share?.isFolder == true) {
|
||||
binding.shareProcessPermissionFileDrop.isChecked = true
|
||||
} else if (SharingMenuHelper.isReadOnly(share)) {
|
||||
binding.shareProcessPermissionReadOnly.isChecked = true
|
||||
selectRadioButtonAccordingToPermission()
|
||||
|
||||
if (isShareProcessStepIsCustomPermission()) {
|
||||
selectCustomPermissionLayout()
|
||||
}
|
||||
|
||||
shareType = share?.shareType ?: ShareType.NO_SHARED
|
||||
@ -270,7 +349,7 @@ class FileDetailsSharingProcessFragment :
|
||||
// show different text for link share and other shares
|
||||
// because we have link to share in Public Link
|
||||
binding.shareProcessBtnNext.text = getString(
|
||||
if (shareType == ShareType.PUBLIC_LINK) {
|
||||
if (isPublicShare()) {
|
||||
R.string.share_copy_link
|
||||
} else {
|
||||
R.string.common_confirm
|
||||
@ -286,19 +365,34 @@ class FileDetailsSharingProcessFragment :
|
||||
showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked)
|
||||
}
|
||||
|
||||
private fun setupUpdateUI() {
|
||||
binding.shareProcessBtnNext.text = getString(R.string.common_next)
|
||||
file.let {
|
||||
if (file?.isFolder == true) {
|
||||
updateViewForFolder()
|
||||
} else {
|
||||
updateViewForFile()
|
||||
private fun selectRadioButtonAccordingToPermission() {
|
||||
val selectedType = SharePermissionManager.getSelectedType(share, encrypted = file?.isEncrypted == true)
|
||||
binding.run {
|
||||
when (selectedType) {
|
||||
QuickPermissionType.VIEW_ONLY -> {
|
||||
viewOnlyRadioButton.isChecked = true
|
||||
}
|
||||
|
||||
QuickPermissionType.CAN_EDIT -> {
|
||||
canEditRadioButton.isChecked = true
|
||||
}
|
||||
|
||||
QuickPermissionType.FILE_REQUEST -> {
|
||||
fileRequestRadioButton.isChecked = true
|
||||
}
|
||||
|
||||
QuickPermissionType.CUSTOM_PERMISSIONS -> {
|
||||
selectCustomPermissionLayout()
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
updateViewForShareType()
|
||||
}
|
||||
showPasswordInput(binding.shareProcessSetPasswordSwitch.isChecked)
|
||||
showExpirationDateInput(binding.shareProcessSetExpDateSwitch.isChecked)
|
||||
showFileDownloadLimitInput(binding.shareProcessSetDownloadLimitSwitch.isChecked)
|
||||
}
|
||||
|
||||
private fun selectCustomPermissionLayout() {
|
||||
binding.customPermissionRadioButton.isChecked = true
|
||||
binding.customPermissionLayout.setVisibilityWithAnimation(true)
|
||||
}
|
||||
|
||||
private fun updateViewForShareType() {
|
||||
@ -318,61 +412,60 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
|
||||
private fun updateViewForExternalShare() {
|
||||
binding.shareProcessChangeNameSwitch.visibility = View.GONE
|
||||
binding.shareProcessChangeNameContainer.visibility = View.GONE
|
||||
updateViewForExternalAndLinkShare()
|
||||
binding.run {
|
||||
shareProcessChangeNameSwitch.visibility = View.GONE
|
||||
shareProcessChangeNameContainer.visibility = View.GONE
|
||||
updateViewForExternalAndLinkShare()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateViewForLinkShare() {
|
||||
updateViewForExternalAndLinkShare()
|
||||
binding.shareProcessChangeNameSwitch.visibility = View.VISIBLE
|
||||
if (share != null) {
|
||||
binding.shareProcessChangeName.setText(share?.label)
|
||||
binding.shareProcessChangeNameSwitch.isChecked = !TextUtils.isEmpty(share?.label)
|
||||
binding.run {
|
||||
shareProcessChangeNameSwitch.visibility = View.VISIBLE
|
||||
if (share != null) {
|
||||
shareProcessChangeName.setText(share?.label)
|
||||
shareProcessChangeNameSwitch.isChecked = !TextUtils.isEmpty(share?.label)
|
||||
}
|
||||
shareReadCheckbox.isEnabled = isFolder()
|
||||
showChangeNameInput(shareProcessChangeNameSwitch.isChecked)
|
||||
}
|
||||
showChangeNameInput(binding.shareProcessChangeNameSwitch.isChecked)
|
||||
}
|
||||
|
||||
private fun updateViewForInternalShare() {
|
||||
binding.shareProcessChangeNameSwitch.visibility = View.GONE
|
||||
binding.shareProcessChangeNameContainer.visibility = View.GONE
|
||||
binding.shareProcessHideDownloadCheckbox.visibility = View.GONE
|
||||
if (isSecureShare) {
|
||||
binding.shareProcessAllowResharingCheckbox.visibility = View.GONE
|
||||
} else {
|
||||
binding.shareProcessAllowResharingCheckbox.visibility = View.VISIBLE
|
||||
}
|
||||
binding.shareProcessSetPasswordSwitch.visibility = View.GONE
|
||||
binding.run {
|
||||
shareProcessChangeNameSwitch.visibility = View.GONE
|
||||
shareProcessChangeNameContainer.visibility = View.GONE
|
||||
shareProcessHideDownloadCheckbox.visibility = View.GONE
|
||||
shareCheckbox.setVisibleIf(!isSecureShare)
|
||||
shareProcessSetPasswordSwitch.visibility = View.GONE
|
||||
|
||||
if (share != null) {
|
||||
if (!isReShareShown) {
|
||||
binding.shareProcessAllowResharingCheckbox.visibility = View.GONE
|
||||
if (share != null) {
|
||||
if (!isReShareShown) {
|
||||
shareCheckbox.visibility = View.GONE
|
||||
}
|
||||
shareCheckbox.isChecked = SharePermissionManager.canReshare(share)
|
||||
}
|
||||
binding.shareProcessAllowResharingCheckbox.isChecked = SharingMenuHelper.canReshare(share)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update views where share type external or link share
|
||||
*/
|
||||
private fun updateViewForExternalAndLinkShare() {
|
||||
binding.shareProcessHideDownloadCheckbox.visibility = View.VISIBLE
|
||||
binding.shareProcessAllowResharingCheckbox.visibility = View.GONE
|
||||
binding.shareProcessSetPasswordSwitch.visibility = View.VISIBLE
|
||||
binding.run {
|
||||
shareProcessHideDownloadCheckbox.visibility = View.VISIBLE
|
||||
shareCheckbox.visibility = View.GONE
|
||||
shareProcessSetPasswordSwitch.visibility = View.VISIBLE
|
||||
|
||||
if (share != null) {
|
||||
if (SharingMenuHelper.isFileDrop(share)) {
|
||||
binding.shareProcessHideDownloadCheckbox.visibility = View.GONE
|
||||
} else {
|
||||
binding.shareProcessHideDownloadCheckbox.visibility = View.VISIBLE
|
||||
binding.shareProcessHideDownloadCheckbox.isChecked = share?.isHideFileDownload == true
|
||||
if (share != null) {
|
||||
if (SharePermissionManager.isFileRequest(share)) {
|
||||
shareProcessHideDownloadCheckbox.visibility = View.GONE
|
||||
} else {
|
||||
shareProcessHideDownloadCheckbox.visibility = View.VISIBLE
|
||||
shareProcessHideDownloadCheckbox.isChecked = share?.isHideFileDownload == true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update expiration date view while modifying the share
|
||||
*/
|
||||
private fun updateExpirationDateView() {
|
||||
share?.let { share ->
|
||||
if (share.expirationDate > 0) {
|
||||
@ -387,7 +480,7 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
|
||||
private fun updateFileDownloadLimitView() {
|
||||
if (capabilities.filesDownloadLimit.isTrue && share?.isFolder == false) {
|
||||
if (canSetDownloadLimit()) {
|
||||
binding.shareProcessSetDownloadLimitSwitch.visibility = View.VISIBLE
|
||||
|
||||
val currentDownloadLimit = share?.fileDownloadLimit?.limit ?: capabilities.filesDownloadLimitDefault
|
||||
@ -400,63 +493,175 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
|
||||
private fun updateViewForFile() {
|
||||
binding.shareProcessPermissionUploadEditing.text = getString(R.string.link_share_editing)
|
||||
binding.shareProcessPermissionFileDrop.visibility = View.GONE
|
||||
binding.run {
|
||||
canEditRadioButton.text = getString(R.string.link_share_editing)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateViewForFolder() {
|
||||
binding.shareProcessPermissionUploadEditing.text = getString(R.string.link_share_allow_upload_and_editing)
|
||||
binding.shareProcessPermissionFileDrop.visibility = View.VISIBLE
|
||||
if (isSecureShare) {
|
||||
binding.shareProcessPermissionFileDrop.visibility = View.GONE
|
||||
binding.shareProcessAllowResharingCheckbox.visibility = View.GONE
|
||||
binding.shareProcessSetExpDateSwitch.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
binding.run {
|
||||
canEditRadioButton.text = getString(R.string.share_permission_can_edit)
|
||||
|
||||
/**
|
||||
* update views for screen type Note
|
||||
*/
|
||||
private fun showShareProcessSecond() {
|
||||
binding.shareProcessGroupOne.visibility = View.GONE
|
||||
binding.shareProcessEditShareLink.visibility = View.GONE
|
||||
binding.shareProcessGroupTwo.visibility = View.VISIBLE
|
||||
if (share != null) {
|
||||
binding.shareProcessBtnNext.text = getString(R.string.set_note)
|
||||
binding.noteText.setText(share?.note)
|
||||
} else {
|
||||
binding.shareProcessBtnNext.text = getString(R.string.send_share)
|
||||
binding.noteText.setText(R.string.empty)
|
||||
}
|
||||
shareProcessStep = SCREEN_TYPE_NOTE
|
||||
}
|
||||
|
||||
private fun implementClickEvents() {
|
||||
binding.shareProcessBtnCancel.setOnClickListener {
|
||||
onCancelClick()
|
||||
}
|
||||
binding.shareProcessBtnNext.setOnClickListener {
|
||||
if (shareProcessStep == SCREEN_TYPE_PERMISSION) {
|
||||
validateShareProcessFirst()
|
||||
} else {
|
||||
validateShareProcessSecond()
|
||||
if (isSecureShare) {
|
||||
shareCheckbox.visibility = View.GONE
|
||||
shareProcessSetExpDateSwitch.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
binding.shareProcessSetPasswordSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showPasswordInput(isChecked)
|
||||
}
|
||||
|
||||
private fun updateViewForNoteScreenType() {
|
||||
binding.run {
|
||||
shareProcessGroupOne.visibility = View.GONE
|
||||
shareProcessEditShareLink.visibility = View.GONE
|
||||
shareProcessGroupTwo.visibility = View.VISIBLE
|
||||
if (share != null) {
|
||||
shareProcessBtnNext.text = getString(R.string.set_note)
|
||||
noteText.setText(share?.note)
|
||||
} else {
|
||||
shareProcessBtnNext.text = getString(R.string.send_share)
|
||||
noteText.setText(R.string.empty)
|
||||
}
|
||||
shareProcessStep = SCREEN_TYPE_NOTE
|
||||
shareProcessBtnNext.performClick()
|
||||
}
|
||||
binding.shareProcessSetExpDateSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showExpirationDateInput(isChecked)
|
||||
}
|
||||
// endregion
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun implementClickEvents() {
|
||||
binding.run {
|
||||
shareProcessBtnCancel.setOnClickListener {
|
||||
onCancelClick()
|
||||
}
|
||||
shareProcessBtnNext.setOnClickListener {
|
||||
if (isShareProcessStepIsPermission()) {
|
||||
validateShareProcessFirst()
|
||||
} else {
|
||||
createShareOrUpdateNoteShare()
|
||||
}
|
||||
}
|
||||
shareProcessSetPasswordSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showPasswordInput(isChecked)
|
||||
}
|
||||
shareProcessSetExpDateSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showExpirationDateInput(isChecked)
|
||||
}
|
||||
shareProcessSetDownloadLimitSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showFileDownloadLimitInput(isChecked)
|
||||
}
|
||||
shareProcessChangeNameSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showChangeNameInput(isChecked)
|
||||
}
|
||||
shareProcessSelectExpDate.setOnClickListener {
|
||||
showExpirationDateDialog()
|
||||
}
|
||||
|
||||
// region RadioButtons
|
||||
shareRadioGroup.setOnCheckedChangeListener { _, optionId ->
|
||||
when (optionId) {
|
||||
R.id.view_only_radio_button -> {
|
||||
permission = OCShare.READ_PERMISSION_FLAG
|
||||
}
|
||||
|
||||
R.id.can_edit_radio_button -> {
|
||||
permission = SharePermissionManager.getMaximumPermission(isFolder())
|
||||
}
|
||||
|
||||
R.id.file_request_radio_button -> {
|
||||
permission = OCShare.CREATE_PERMISSION_FLAG
|
||||
}
|
||||
}
|
||||
|
||||
val isCustomPermissionSelected = (optionId == R.id.custom_permission_radio_button)
|
||||
customPermissionLayout.setVisibilityWithAnimation(isCustomPermissionSelected)
|
||||
toggleNextButtonAvailability(true)
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
binding.shareProcessSetDownloadLimitSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showFileDownloadLimitInput(isChecked)
|
||||
}
|
||||
|
||||
private fun isAnyShareOptionChecked(): Boolean {
|
||||
return binding.run {
|
||||
val isCustomPermissionChecked = customPermissionRadioButton.isChecked &&
|
||||
(
|
||||
shareReadCheckbox.isChecked ||
|
||||
shareCreateCheckbox.isChecked ||
|
||||
shareEditCheckbox.isChecked ||
|
||||
shareCheckbox.isChecked ||
|
||||
shareDeleteCheckbox.isChecked
|
||||
)
|
||||
|
||||
viewOnlyRadioButton.isChecked ||
|
||||
canEditRadioButton.isChecked ||
|
||||
fileRequestRadioButton.isChecked ||
|
||||
isCustomPermissionChecked
|
||||
}
|
||||
binding.shareProcessChangeNameSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
showChangeNameInput(isChecked)
|
||||
}
|
||||
|
||||
private fun toggleNextButtonAvailability(value: Boolean) {
|
||||
binding.run {
|
||||
shareProcessBtnNext.isEnabled = value
|
||||
shareProcessBtnNext.isClickable = value
|
||||
}
|
||||
binding.shareProcessSelectExpDate.setOnClickListener {
|
||||
showExpirationDateDialog()
|
||||
}
|
||||
|
||||
@Suppress("NestedBlockDepth")
|
||||
private fun setCheckboxStates() {
|
||||
val currentPermissions = share?.permissions ?: permission
|
||||
|
||||
binding.run {
|
||||
SharePermissionManager.run {
|
||||
shareReadCheckbox.isChecked = hasPermission(currentPermissions, OCShare.READ_PERMISSION_FLAG)
|
||||
shareEditCheckbox.isChecked = hasPermission(currentPermissions, OCShare.UPDATE_PERMISSION_FLAG)
|
||||
shareCheckbox.isChecked = hasPermission(currentPermissions, OCShare.SHARE_PERMISSION_FLAG)
|
||||
|
||||
if (isFolder()) {
|
||||
// Only for the folder makes sense to have create permission
|
||||
// so that user can create files in the shared folder
|
||||
shareCreateCheckbox.isChecked = hasPermission(currentPermissions, OCShare.CREATE_PERMISSION_FLAG)
|
||||
shareDeleteCheckbox.isChecked = hasPermission(currentPermissions, OCShare.DELETE_PERMISSION_FLAG)
|
||||
} else {
|
||||
shareCreateCheckbox.visibility = View.GONE
|
||||
shareDeleteCheckbox.apply {
|
||||
isChecked = false
|
||||
isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPublicShare()) {
|
||||
shareAllowDownloadAndSyncCheckbox.isChecked = isAllowDownloadAndSyncEnabled(share)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCheckboxesListeners()
|
||||
}
|
||||
|
||||
private fun setCheckboxesListeners() {
|
||||
val checkboxes = mapOf(
|
||||
binding.shareReadCheckbox to OCShare.READ_PERMISSION_FLAG,
|
||||
binding.shareCreateCheckbox to OCShare.CREATE_PERMISSION_FLAG,
|
||||
binding.shareEditCheckbox to OCShare.UPDATE_PERMISSION_FLAG,
|
||||
binding.shareCheckbox to OCShare.SHARE_PERMISSION_FLAG,
|
||||
binding.shareDeleteCheckbox to OCShare.DELETE_PERMISSION_FLAG
|
||||
)
|
||||
|
||||
checkboxes.forEach { (checkbox, flag) ->
|
||||
checkbox.setOnCheckedChangeListener { _, isChecked -> togglePermission(isChecked, flag) }
|
||||
}
|
||||
|
||||
if (!isPublicShare()) {
|
||||
binding.shareAllowDownloadAndSyncCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
val result = SharePermissionManager.toggleAllowDownloadAndSync(isChecked, share)
|
||||
share?.attributes = result
|
||||
downloadAttribute = result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun togglePermission(isChecked: Boolean, permissionFlag: Int) {
|
||||
permission = SharePermissionManager.togglePermission(isChecked, permission, permissionFlag)
|
||||
toggleNextButtonAvailability(true)
|
||||
}
|
||||
|
||||
private fun showExpirationDateDialog(chosenDateInMillis: Long = chosenExpDateInMills) {
|
||||
@ -472,7 +677,8 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
|
||||
private fun showChangeNameInput(isChecked: Boolean) {
|
||||
binding.shareProcessChangeNameContainer.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||
binding.shareProcessChangeNameContainer.setVisibleIf(isChecked)
|
||||
|
||||
if (!isChecked) {
|
||||
binding.shareProcessChangeName.setText(R.string.empty)
|
||||
}
|
||||
@ -483,11 +689,12 @@ class FileDetailsSharingProcessFragment :
|
||||
if (share != null) {
|
||||
removeCurrentFragment()
|
||||
}
|
||||
|
||||
// else we have to check if user is in step 2(note screen) then show step 1 (permission screen)
|
||||
// and if user is in step 1 (permission screen) then remove the fragment
|
||||
else {
|
||||
if (shareProcessStep == SCREEN_TYPE_NOTE) {
|
||||
showShareProcessFirst()
|
||||
if (isShareProcessStepIsNote()) {
|
||||
setupUI()
|
||||
} else {
|
||||
removeCurrentFragment()
|
||||
}
|
||||
@ -495,8 +702,8 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
|
||||
private fun showExpirationDateInput(isChecked: Boolean) {
|
||||
binding.shareProcessSelectExpDate.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||
binding.shareProcessExpDateDivider.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||
binding.shareProcessSelectExpDate.setVisibleIf(isChecked)
|
||||
binding.shareProcessExpDateDivider.setVisibleIf(isChecked)
|
||||
|
||||
// reset the expiration date if switch is unchecked
|
||||
if (!isChecked) {
|
||||
@ -515,7 +722,7 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
|
||||
private fun showPasswordInput(isChecked: Boolean) {
|
||||
binding.shareProcessEnterPasswordContainer.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||
binding.shareProcessEnterPasswordContainer.setVisibleIf(isChecked)
|
||||
|
||||
// reset the password if switch is unchecked
|
||||
if (!isChecked) {
|
||||
@ -528,18 +735,11 @@ class FileDetailsSharingProcessFragment :
|
||||
fileActivity?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
|
||||
}
|
||||
|
||||
private fun getReSharePermission(): Int {
|
||||
val spb = SharePermissionsBuilder()
|
||||
spb.setSharePermission(true)
|
||||
return spb.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* method to validate the step 1 screen information
|
||||
*/
|
||||
@Suppress("ReturnCount")
|
||||
private fun validateShareProcessFirst() {
|
||||
permission = getSelectedPermission()
|
||||
if (permission == OCShare.NO_PERMISSION) {
|
||||
DisplayUtils.showSnackMessage(binding.root, R.string.no_share_permission_selected)
|
||||
return
|
||||
@ -572,26 +772,48 @@ class FileDetailsSharingProcessFragment :
|
||||
removeCurrentFragment()
|
||||
} else {
|
||||
// else show step 2 (note screen)
|
||||
showShareProcessSecond()
|
||||
updateViewForNoteScreenType()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the permissions on the basis of selection
|
||||
*/
|
||||
private fun getSelectedPermission() = when {
|
||||
binding.shareProcessAllowResharingCheckbox.isChecked -> getReSharePermission()
|
||||
binding.shareProcessPermissionReadOnly.isChecked -> OCShare.READ_PERMISSION_FLAG
|
||||
binding.shareProcessPermissionUploadEditing.isChecked -> when {
|
||||
file?.isFolder == true || share?.isFolder == true -> OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER
|
||||
else -> OCShare.MAXIMUM_PERMISSIONS_FOR_FILE
|
||||
@Suppress("ReturnCount")
|
||||
private fun createShareOrUpdateNoteShare() {
|
||||
if (!isAnyShareOptionChecked()) {
|
||||
DisplayUtils.showSnackMessage(requireActivity(), R.string.share_option_required)
|
||||
return
|
||||
}
|
||||
|
||||
binding.shareProcessPermissionFileDrop.isChecked -> OCShare.CREATE_PERMISSION_FLAG
|
||||
else -> permission
|
||||
val noteText = binding.noteText.text.toString().trim()
|
||||
if (file == null && (share != null && share?.note == noteText)) {
|
||||
DisplayUtils.showSnackMessage(requireActivity(), R.string.share_cannot_update_empty_note)
|
||||
return
|
||||
}
|
||||
|
||||
when {
|
||||
// if modifying existing share then directly update the note and send email
|
||||
share != null && share?.note != noteText -> {
|
||||
fileOperationsHelper?.updateNoteToShare(share, noteText)
|
||||
}
|
||||
|
||||
file == null -> {
|
||||
DisplayUtils.showSnackMessage(requireActivity(), R.string.file_not_found_cannot_share)
|
||||
return
|
||||
}
|
||||
|
||||
else -> {
|
||||
createShare(noteText)
|
||||
}
|
||||
}
|
||||
|
||||
removeCurrentFragment()
|
||||
}
|
||||
|
||||
private fun updateShare() {
|
||||
// empty string causing fails
|
||||
if (share?.attributes?.isEmpty() == true) {
|
||||
share?.attributes = null
|
||||
}
|
||||
|
||||
fileOperationsHelper?.updateShareInformation(
|
||||
share,
|
||||
permission,
|
||||
@ -601,16 +823,8 @@ class FileDetailsSharingProcessFragment :
|
||||
binding.shareProcessChangeName.text.toString().trim()
|
||||
)
|
||||
|
||||
if (capabilities.filesDownloadLimit.isTrue) {
|
||||
val downloadLimitInput = binding.shareProcessSetDownloadLimitInput.text.toString().trim()
|
||||
val downloadLimit =
|
||||
if (binding.shareProcessSetDownloadLimitSwitch.isChecked && downloadLimitInput.isNotEmpty()) {
|
||||
downloadLimitInput.toInt()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
fileOperationsHelper?.updateFilesDownloadLimit(share, downloadLimit)
|
||||
if (canSetDownloadLimit()) {
|
||||
setDownloadLimit()
|
||||
}
|
||||
|
||||
// copy the share link if available
|
||||
@ -619,31 +833,32 @@ class FileDetailsSharingProcessFragment :
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* method to validate step 2 (note screen) information
|
||||
*/
|
||||
private fun validateShareProcessSecond() {
|
||||
val noteText = binding.noteText.text.toString().trim()
|
||||
// if modifying existing share then directly update the note and send email
|
||||
if (share != null && share?.note != noteText) {
|
||||
fileOperationsHelper?.updateNoteToShare(share, noteText)
|
||||
} else {
|
||||
// else create new share
|
||||
fileOperationsHelper?.shareFileWithSharee(
|
||||
file,
|
||||
shareeName,
|
||||
shareType,
|
||||
permission,
|
||||
binding
|
||||
.shareProcessHideDownloadCheckbox.isChecked,
|
||||
binding.shareProcessEnterPassword.text.toString().trim(),
|
||||
chosenExpDateInMills,
|
||||
noteText,
|
||||
binding.shareProcessChangeName.text.toString().trim(),
|
||||
true
|
||||
)
|
||||
}
|
||||
removeCurrentFragment()
|
||||
private fun setDownloadLimit() {
|
||||
val downloadLimitInput = binding.shareProcessSetDownloadLimitInput.text.toString().trim()
|
||||
val downloadLimit =
|
||||
if (binding.shareProcessSetDownloadLimitSwitch.isChecked && downloadLimitInput.isNotEmpty()) {
|
||||
downloadLimitInput.toInt()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
fileOperationsHelper?.updateFilesDownloadLimit(share, downloadLimit)
|
||||
}
|
||||
|
||||
private fun createShare(noteText: String) {
|
||||
fileOperationsHelper?.shareFileWithSharee(
|
||||
file,
|
||||
shareeName,
|
||||
shareType,
|
||||
permission,
|
||||
binding.shareProcessHideDownloadCheckbox.isChecked,
|
||||
binding.shareProcessEnterPassword.text.toString().trim(),
|
||||
chosenExpDateInMills,
|
||||
noteText,
|
||||
downloadAttribute,
|
||||
binding.shareProcessChangeName.text.toString().trim(),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -664,4 +879,25 @@ class FileDetailsSharingProcessFragment :
|
||||
override fun onDateUnSet() {
|
||||
binding.shareProcessSetExpDateSwitch.isChecked = false
|
||||
}
|
||||
|
||||
// region Helpers
|
||||
private fun isShareProcessStepIsPermission(): Boolean = (
|
||||
shareProcessStep == SCREEN_TYPE_PERMISSION ||
|
||||
isShareProcessStepIsCustomPermission()
|
||||
)
|
||||
|
||||
private fun isShareProcessStepIsCustomPermission(): Boolean =
|
||||
(shareProcessStep == SCREEN_TYPE_PERMISSION_WITH_CUSTOM_PERMISSION)
|
||||
|
||||
private fun isShareProcessStepIsNote(): Boolean = (shareProcessStep == SCREEN_TYPE_NOTE)
|
||||
|
||||
private fun isFolder(): Boolean = (file?.isFolder == true || share?.isFolder == true)
|
||||
|
||||
private fun canSetFileRequest(): Boolean = isFolder() && shareType.isPublicOrMail()
|
||||
|
||||
private fun canSetDownloadLimit(): Boolean =
|
||||
(isPublicShare() && capabilities.filesDownloadLimit.isTrue && share?.isFolder == false)
|
||||
|
||||
private fun isPublicShare(): Boolean = (shareType == ShareType.PUBLIC_LINK)
|
||||
// endregion
|
||||
}
|
||||
|
@ -10,22 +10,24 @@
|
||||
|
||||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.nextcloud.utils.extensions.OCShareExtensionsKt;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding;
|
||||
import com.owncloud.android.datamodel.QuickPermissionModel;
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermission;
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType;
|
||||
import com.owncloud.android.lib.resources.shares.OCShare;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter;
|
||||
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
|
||||
import com.owncloud.android.ui.fragment.util.SharePermissionManager;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
@ -36,7 +38,7 @@ import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSI
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG;
|
||||
|
||||
/**
|
||||
* File Details Quick Sharing permissions options {@link android.app.Dialog} styled as a bottom sheet for main actions.
|
||||
* File Details Quick Sharing permissions options {@link Dialog} styled as a bottom sheet for main actions.
|
||||
*/
|
||||
public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog {
|
||||
private QuickSharingPermissionsBottomSheetFragmentBinding binding;
|
||||
@ -44,16 +46,19 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog
|
||||
private final FileActivity fileActivity;
|
||||
private final OCShare ocShare;
|
||||
private final ViewThemeUtils viewThemeUtils;
|
||||
private final boolean encrypted;
|
||||
|
||||
public QuickSharingPermissionsBottomSheetDialog(FileActivity fileActivity,
|
||||
QuickPermissionSharingBottomSheetActions actions,
|
||||
OCShare ocShare,
|
||||
ViewThemeUtils viewThemeUtils) {
|
||||
ViewThemeUtils viewThemeUtils,
|
||||
boolean encrypted) {
|
||||
super(fileActivity);
|
||||
this.actions = actions;
|
||||
this.ocShare = ocShare;
|
||||
this.fileActivity = fileActivity;
|
||||
this.viewThemeUtils = viewThemeUtils;
|
||||
this.encrypted = encrypted;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,13 +81,19 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
List<QuickPermissionModel> quickPermissionModelList = getQuickPermissionList();
|
||||
List<QuickPermission> quickPermissionList = getQuickPermissionList();
|
||||
QuickSharingPermissionsAdapter adapter = new QuickSharingPermissionsAdapter(
|
||||
quickPermissionModelList,
|
||||
quickPermissionList,
|
||||
new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() {
|
||||
@Override
|
||||
public void onCustomPermissionSelected() {
|
||||
dismiss();
|
||||
actions.openShareDetailWithCustomPermissions(ocShare);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionChanged(int position) {
|
||||
handlePermissionChanged(quickPermissionModelList, position);
|
||||
handlePermissionChanged(quickPermissionList, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -98,60 +109,35 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog
|
||||
}
|
||||
|
||||
/**
|
||||
* handle permission changed on click of selected permission
|
||||
* @param quickPermissionModelList
|
||||
* @param position
|
||||
* Handle permission changed on click of selected permission
|
||||
*/
|
||||
private void handlePermissionChanged(List<QuickPermissionModel> quickPermissionModelList, int position) {
|
||||
if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string.link_share_allow_upload_and_editing))
|
||||
|| quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string.link_share_editing))) {
|
||||
if (ocShare.isFolder()) {
|
||||
actions.onQuickPermissionChanged(ocShare,
|
||||
MAXIMUM_PERMISSIONS_FOR_FOLDER);
|
||||
} else {
|
||||
actions.onQuickPermissionChanged(ocShare,
|
||||
MAXIMUM_PERMISSIONS_FOR_FILE);
|
||||
}
|
||||
} else if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string
|
||||
.link_share_view_only))) {
|
||||
actions.onQuickPermissionChanged(ocShare,
|
||||
READ_PERMISSION_FLAG);
|
||||
private void handlePermissionChanged(List<QuickPermission> quickPermissionList, int position) {
|
||||
final var permissionName = quickPermissionList.get(position).getType().getText(getContext());
|
||||
final var res = fileActivity.getResources();
|
||||
|
||||
} else if (quickPermissionModelList.get(position).getPermissionName().equalsIgnoreCase(fileActivity.getResources().getString(R.string
|
||||
.link_share_file_drop))) {
|
||||
actions.onQuickPermissionChanged(ocShare,
|
||||
CREATE_PERMISSION_FLAG);
|
||||
int permissionFlag = 0;
|
||||
if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_can_edit)) || permissionName.equalsIgnoreCase(res.getString(R.string.link_share_editing))) {
|
||||
permissionFlag = ocShare.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER : MAXIMUM_PERMISSIONS_FOR_FILE;
|
||||
} else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_view_only))) {
|
||||
permissionFlag = READ_PERMISSION_FLAG;
|
||||
} else if (permissionName.equalsIgnoreCase(res.getString(R.string.share_permission_file_request))) {
|
||||
permissionFlag = CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG;
|
||||
}
|
||||
|
||||
actions.onQuickPermissionChanged(ocShare, permissionFlag);
|
||||
|
||||
dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare the list of permissions needs to be displayed on recyclerview
|
||||
* @return
|
||||
* Prepare the list of permissions needs to be displayed on recyclerview
|
||||
*/
|
||||
private List<QuickPermissionModel> getQuickPermissionList() {
|
||||
|
||||
String[] permissionArray;
|
||||
if (ocShare.isFolder()) {
|
||||
permissionArray =
|
||||
fileActivity.getResources().getStringArray(R.array.folder_share_permission_dialog_values);
|
||||
} else {
|
||||
permissionArray =
|
||||
fileActivity.getResources().getStringArray(R.array.file_share_permission_dialog_values);
|
||||
}
|
||||
//get the checked item position
|
||||
int checkedItem = SharingMenuHelper.getPermissionCheckedItem(fileActivity, ocShare, permissionArray);
|
||||
|
||||
|
||||
final List<QuickPermissionModel> quickPermissionModelList = new ArrayList<>(permissionArray.length);
|
||||
for (int i = 0; i < permissionArray.length; i++) {
|
||||
QuickPermissionModel quickPermissionModel = new QuickPermissionModel(permissionArray[i], checkedItem == i);
|
||||
quickPermissionModelList.add(quickPermissionModel);
|
||||
}
|
||||
return quickPermissionModelList;
|
||||
private List<QuickPermission> getQuickPermissionList() {
|
||||
final var selectedType = SharePermissionManager.INSTANCE.getSelectedType(ocShare, encrypted);
|
||||
final var hasFileRequestPermission = OCShareExtensionsKt.hasFileRequestPermission(ocShare);
|
||||
return QuickPermissionType.Companion.getAvailablePermissions(hasFileRequestPermission, selectedType);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
@ -160,5 +146,7 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog
|
||||
|
||||
public interface QuickPermissionSharingBottomSheetActions {
|
||||
void onQuickPermissionChanged(OCShare share, int permission);
|
||||
|
||||
void openShareDetailWithCustomPermissions(OCShare share);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.fragment.util
|
||||
|
||||
import com.owncloud.android.datamodel.quickPermission.QuickPermissionType
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
import com.owncloud.android.lib.resources.shares.OCShare
|
||||
import com.owncloud.android.lib.resources.shares.attributes.ShareAttributes
|
||||
import com.owncloud.android.lib.resources.shares.attributes.ShareAttributesJsonHandler
|
||||
import com.owncloud.android.lib.resources.shares.attributes.getDownloadAttribute
|
||||
import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment.Companion.TAG
|
||||
|
||||
object SharePermissionManager {
|
||||
|
||||
// region Permission change
|
||||
fun togglePermission(isChecked: Boolean, permission: Int, permissionFlag: Int): Int {
|
||||
Log_OC.d(TAG, "togglePermission before: $permission")
|
||||
|
||||
if (!isPermissionValid(permission)) {
|
||||
Log_OC.d(TAG, "permission is not valid, togglePermission cancelled")
|
||||
return permission
|
||||
}
|
||||
|
||||
val result = if (isChecked) {
|
||||
permission or permissionFlag
|
||||
} else {
|
||||
permission and permissionFlag.inv()
|
||||
}
|
||||
|
||||
Log_OC.d(TAG, "togglePermission after: $result")
|
||||
|
||||
return result
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Permission check
|
||||
fun hasPermission(permission: Int, permissionFlag: Int): Boolean {
|
||||
return permission != OCShare.NO_PERMISSION && (permission and permissionFlag) == permissionFlag
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
private fun isPermissionValid(permission: Int): Boolean {
|
||||
// Must have at least READ or CREATE permission.
|
||||
if (!hasPermission(permission, OCShare.READ_PERMISSION_FLAG) &&
|
||||
!hasPermission(permission, OCShare.CREATE_PERMISSION_FLAG)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Must have READ permission if have UPDATE or DELETE.
|
||||
if (!hasPermission(permission, OCShare.READ_PERMISSION_FLAG) &&
|
||||
(
|
||||
hasPermission(permission, OCShare.UPDATE_PERMISSION_FLAG) ||
|
||||
hasPermission(permission, OCShare.DELETE_PERMISSION_FLAG)
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region DownloadAttribute
|
||||
fun toggleAllowDownloadAndSync(isChecked: Boolean, share: OCShare?): String? {
|
||||
val shareAttributes = getShareAttributes(share)?.toMutableList()
|
||||
if (shareAttributes == null) {
|
||||
val downloadAttribute = ShareAttributes.createDownloadAttributes(isChecked)
|
||||
val updatedShareAttributes = listOf(downloadAttribute)
|
||||
return ShareAttributesJsonHandler.toJson(updatedShareAttributes)
|
||||
}
|
||||
|
||||
val downloadAttributeIndex = shareAttributes.indexOf(shareAttributes.getDownloadAttribute())
|
||||
if (downloadAttributeIndex >= 0) {
|
||||
val updatedAttribute = shareAttributes[downloadAttributeIndex].copy(value = isChecked)
|
||||
shareAttributes[downloadAttributeIndex] = updatedAttribute
|
||||
}
|
||||
|
||||
return ShareAttributesJsonHandler.toJson(shareAttributes)
|
||||
}
|
||||
|
||||
fun isAllowDownloadAndSyncEnabled(share: OCShare?): Boolean {
|
||||
return getShareAttributes(share).getDownloadAttribute()?.value == true
|
||||
}
|
||||
|
||||
private fun getShareAttributes(share: OCShare?): List<ShareAttributes>? {
|
||||
return share?.attributes?.let { ShareAttributesJsonHandler.toList(it) }
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Helper Methods
|
||||
fun canEdit(share: OCShare?): Boolean {
|
||||
if (share == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
return hasPermission(share.permissions, getMaximumPermission(share.isFolder))
|
||||
}
|
||||
|
||||
fun isViewOnly(share: OCShare?): Boolean {
|
||||
return share?.permissions != OCShare.NO_PERMISSION && share?.permissions == OCShare.READ_PERMISSION_FLAG
|
||||
}
|
||||
|
||||
fun isFileRequest(share: OCShare?): Boolean {
|
||||
if (share?.isFolder == false) {
|
||||
return false
|
||||
}
|
||||
|
||||
return share?.permissions != OCShare.NO_PERMISSION && share?.permissions == OCShare.CREATE_PERMISSION_FLAG
|
||||
}
|
||||
|
||||
fun isSecureFileDrop(share: OCShare?): Boolean {
|
||||
if (share == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
return hasPermission(share.permissions, OCShare.CREATE_PERMISSION_FLAG + OCShare.READ_PERMISSION_FLAG)
|
||||
}
|
||||
|
||||
fun canReshare(share: OCShare?): Boolean {
|
||||
if (share == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (share.permissions and OCShare.Companion.SHARE_PERMISSION_FLAG) > 0
|
||||
}
|
||||
|
||||
fun getSelectedType(share: OCShare?, encrypted: Boolean): QuickPermissionType {
|
||||
return if (canEdit(share)) {
|
||||
QuickPermissionType.CAN_EDIT
|
||||
} else if (encrypted && isSecureFileDrop(share)) {
|
||||
QuickPermissionType.SECURE_FILE_DROP
|
||||
} else if (isFileRequest(share)) {
|
||||
QuickPermissionType.FILE_REQUEST
|
||||
} else if (isViewOnly(share)) {
|
||||
QuickPermissionType.VIEW_ONLY
|
||||
} else if (isCustomPermission(share)) {
|
||||
QuickPermissionType.CUSTOM_PERMISSIONS
|
||||
} else {
|
||||
QuickPermissionType.NONE
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
fun isCustomPermission(share: OCShare?): Boolean {
|
||||
if (share == null) return false
|
||||
val permissions = share.permissions
|
||||
if (permissions == OCShare.NO_PERMISSION) return false
|
||||
|
||||
val hasRead = hasPermission(permissions, OCShare.READ_PERMISSION_FLAG)
|
||||
if (!hasRead) return false
|
||||
|
||||
val hasCreate = hasPermission(permissions, OCShare.CREATE_PERMISSION_FLAG)
|
||||
val hasUpdate = hasPermission(permissions, OCShare.UPDATE_PERMISSION_FLAG)
|
||||
val hasDelete = hasPermission(permissions, OCShare.DELETE_PERMISSION_FLAG)
|
||||
val hasShare = hasPermission(permissions, OCShare.SHARE_PERMISSION_FLAG)
|
||||
|
||||
return when {
|
||||
share.isFolder -> hasCreate || hasUpdate || hasDelete || hasShare
|
||||
else -> hasUpdate || hasShare
|
||||
}
|
||||
}
|
||||
|
||||
fun getMaximumPermission(isFolder: Boolean): Int {
|
||||
return if (isFolder) {
|
||||
OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER
|
||||
} else {
|
||||
OCShare.MAXIMUM_PERMISSIONS_FOR_FILE
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author TSI-mc
|
||||
* Copyright (C) 2018 Andy Scherzinger
|
||||
* Copyright (C) 2021 TSI-mc
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.fragment.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.resources.shares.OCShare;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG;
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE;
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER;
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION;
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG;
|
||||
import static com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG;
|
||||
|
||||
/**
|
||||
* Helper calls for visibility logic of the sharing menu.
|
||||
*/
|
||||
public final class SharingMenuHelper {
|
||||
|
||||
private SharingMenuHelper() {
|
||||
// utility class -> private constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets checked/visibility state on the given {@link MenuItem} based on the given criteria.
|
||||
*
|
||||
* @param menuItem the {@link MenuItem} to be setup
|
||||
*/
|
||||
public static void setupHideFileDownload(MenuItem menuItem,
|
||||
boolean hideFileDownload,
|
||||
boolean isFileDrop) {
|
||||
if (isFileDrop) {
|
||||
menuItem.setVisible(false);
|
||||
} else {
|
||||
menuItem.setVisible(true);
|
||||
menuItem.setChecked(hideFileDownload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets up the password {@link MenuItem}'s title based on the fact if a password is present.
|
||||
*
|
||||
* @param password the password {@link MenuItem}
|
||||
* @param isPasswordProtected flag is a password is present
|
||||
*/
|
||||
public static void setupPasswordMenuItem(MenuItem password, boolean isPasswordProtected) {
|
||||
if (isPasswordProtected) {
|
||||
password.setTitle(R.string.share_password_title);
|
||||
} else {
|
||||
password.setTitle(R.string.share_no_password_title);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets up the expiration date {@link MenuItem}'s title based on the fact if an expiration date is present.
|
||||
*
|
||||
* @param expirationDate the expiration date {@link MenuItem}
|
||||
* @param expirationDateValue the expiration date
|
||||
* @param res Resources to load the corresponding strings.
|
||||
*/
|
||||
public static void setupExpirationDateMenuItem(MenuItem expirationDate, long expirationDateValue, Resources res) {
|
||||
if (expirationDateValue > 0) {
|
||||
expirationDate.setTitle(res.getString(
|
||||
R.string.share_expiration_date_label,
|
||||
SimpleDateFormat.getDateInstance().format(new Date(expirationDateValue))
|
||||
));
|
||||
} else {
|
||||
expirationDate.setTitle(R.string.share_no_expiration_date_label);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isUploadAndEditingAllowed(OCShare share) {
|
||||
if (share.getPermissions() == NO_PERMISSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (share.getPermissions() & (share.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER :
|
||||
MAXIMUM_PERMISSIONS_FOR_FILE)) == (share.isFolder() ? MAXIMUM_PERMISSIONS_FOR_FOLDER :
|
||||
MAXIMUM_PERMISSIONS_FOR_FILE);
|
||||
}
|
||||
|
||||
public static boolean isReadOnly(OCShare share) {
|
||||
if (share.getPermissions() == NO_PERMISSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == READ_PERMISSION_FLAG;
|
||||
}
|
||||
|
||||
public static boolean isFileDrop(OCShare share) {
|
||||
if (share.getPermissions() == NO_PERMISSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG;
|
||||
}
|
||||
|
||||
public static boolean isSecureFileDrop(OCShare share) {
|
||||
if (share.getPermissions() == NO_PERMISSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG + READ_PERMISSION_FLAG;
|
||||
}
|
||||
|
||||
public static String getPermissionName(Context context, OCShare share) {
|
||||
if (SharingMenuHelper.isUploadAndEditingAllowed(share)) {
|
||||
return context.getResources().getString(R.string.share_permission_can_edit);
|
||||
} else if (SharingMenuHelper.isReadOnly(share)) {
|
||||
return context.getResources().getString(R.string.share_permission_view_only);
|
||||
} else if (SharingMenuHelper.isSecureFileDrop(share)) {
|
||||
return context.getResources().getString(R.string.share_permission_secure_file_drop);
|
||||
} else if (SharingMenuHelper.isFileDrop(share)) {
|
||||
return context.getResources().getString(R.string.share_permission_file_drop);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* method to get the current checked index from the list of permissions
|
||||
*
|
||||
*/
|
||||
public static int getPermissionCheckedItem(Context context, OCShare share, String[] permissionArray) {
|
||||
if (SharingMenuHelper.isUploadAndEditingAllowed(share)) {
|
||||
if (share.isFolder()) {
|
||||
return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_allow_upload_and_editing);
|
||||
} else {
|
||||
return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_editing);
|
||||
}
|
||||
} else if (SharingMenuHelper.isReadOnly(share)) {
|
||||
return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_view_only);
|
||||
} else if (SharingMenuHelper.isFileDrop(share)) {
|
||||
return getPermissionIndexFromArray(context, permissionArray, R.string.link_share_file_drop);
|
||||
}
|
||||
return 0;//default first item selected
|
||||
}
|
||||
|
||||
private static int getPermissionIndexFromArray(Context context, String[] permissionArray, int permissionName) {
|
||||
for (int i = 0; i < permissionArray.length; i++) {
|
||||
if (permissionArray[i].equalsIgnoreCase(context.getResources().getString(permissionName))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean canReshare(OCShare share) {
|
||||
return (share.getPermissions() & SHARE_PERMISSION_FLAG) > 0;
|
||||
}
|
||||
}
|
@ -534,6 +534,7 @@ public class FileOperationsHelper {
|
||||
String password,
|
||||
long expirationTimeInMillis,
|
||||
String note,
|
||||
String attributes,
|
||||
String label,
|
||||
boolean showLoadingDialog) {
|
||||
if (file != null) {
|
||||
@ -555,6 +556,7 @@ public class FileOperationsHelper {
|
||||
service.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
|
||||
service.putExtra(OperationsService.EXTRA_SHARE_NOTE, (note == null) ? "" : note);
|
||||
service.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label);
|
||||
service.putExtra(OperationsService.EXTRA_SHARE_ATTRIBUTES, attributes);
|
||||
|
||||
mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
|
||||
|
||||
@ -588,16 +590,13 @@ public class FileOperationsHelper {
|
||||
*
|
||||
* @param file The file to unshare.
|
||||
*/
|
||||
public void unshareShare(OCFile file, OCShare share) {
|
||||
|
||||
// Unshare the file: Create the intent
|
||||
Intent unshareService = new Intent(fileActivity, OperationsService.class);
|
||||
unshareService.setAction(OperationsService.ACTION_UNSHARE);
|
||||
unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
|
||||
unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
|
||||
unshareService.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
|
||||
|
||||
queueShareIntent(unshareService);
|
||||
public void unShareShare(OCFile file, OCShare share) {
|
||||
Intent intent = new Intent(fileActivity, OperationsService.class);
|
||||
intent.setAction(OperationsService.ACTION_UNSHARE);
|
||||
intent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
|
||||
intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
|
||||
intent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
|
||||
queueShareIntent(intent);
|
||||
}
|
||||
|
||||
private void queueShareIntent(Intent shareIntent) {
|
||||
@ -751,18 +750,33 @@ public class FileOperationsHelper {
|
||||
* leaving the link unrestricted. Zero makes no change.
|
||||
* @param label new label
|
||||
*/
|
||||
public void updateShareInformation(OCShare share, int permissions,
|
||||
boolean hideFileDownload, String password, long expirationTimeInMillis,
|
||||
public void updateShareInformation(OCShare share,
|
||||
int permissions,
|
||||
boolean hideFileDownload,
|
||||
String password,
|
||||
long expirationTimeInMillis,
|
||||
String label) {
|
||||
final var id = share.getId();
|
||||
final var attributes = share.getAttributes();
|
||||
|
||||
Log_OC.i(TAG, "-----AFTER UPDATE SHARE-----");
|
||||
Log_OC.i(TAG, "ID: " + id);
|
||||
Log_OC.i(TAG, "Permission: " + permissions);
|
||||
Log_OC.i(TAG, "Hide File Download: " + hideFileDownload);
|
||||
Log_OC.i(TAG, "Label: " + label);
|
||||
Log_OC.i(TAG, "Attributes: " + attributes);
|
||||
|
||||
|
||||
Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
|
||||
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE_INFO);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, id);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, permissions);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_HIDE_FILE_DOWNLOAD, hideFileDownload);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_LABEL, (label == null) ? "" : label);
|
||||
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ATTRIBUTES, attributes);
|
||||
queueShareIntent(updateShareIntent);
|
||||
}
|
||||
|
||||
|
16
app/src/main/res/drawable/ic_custom_permissions.xml
Normal file
16
app/src/main/res/drawable/ic_custom_permissions.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2018-2025 Google LLC
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M440,840L440,600L520,600L520,680L840,680L840,760L520,760L520,840L440,840ZM120,760L120,680L360,680L360,760L120,760ZM280,600L280,520L120,520L120,440L280,440L280,360L360,360L360,600L280,600ZM440,520L440,440L840,440L840,520L440,520ZM600,360L600,120L680,120L680,200L840,200L840,280L680,280L680,360L600,360ZM120,280L120,200L520,200L520,280L120,280Z" />
|
||||
</vector>
|
18
app/src/main/res/drawable/ic_eye.xml
Normal file
18
app/src/main/res/drawable/ic_eye.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2018-2025 Google LLC
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" />
|
||||
|
||||
</vector>
|
16
app/src/main/res/drawable/ic_file_request.xml
Normal file
16
app/src/main/res/drawable/ic_file_request.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2018-2025 Google LLC
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M202,895L146,838L264,720L174,720L174,640L400,640L400,866L320,866L320,777L202,895ZM480,880L480,560L160,560L160,160Q160,127 183.5,103.5Q207,80 240,80L560,80L800,320L800,800Q800,833 776.5,856.5Q753,880 720,880L480,880ZM520,360L720,360L520,160L720,360L520,160L520,360Z" />
|
||||
</vector>
|
@ -39,52 +39,112 @@
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/share_process_permission_radio_group"
|
||||
android:id="@+id/share_radio_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/share_process_permission_read_only"
|
||||
android:id="@+id/view_only_radio_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/link_share_view_only" />
|
||||
android:text="@string/share_permission_view_only" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/share_process_permission_upload_editing"
|
||||
android:id="@+id/can_edit_radio_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/link_share_allow_upload_and_editing" />
|
||||
android:text="@string/share_permission_can_edit" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/share_process_permission_file_drop"
|
||||
android:id="@+id/file_request_radio_button"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/share_permission_file_request" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/custom_permission_radio_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/link_share_file_drop" />
|
||||
android:text="@string/share_custom_permission" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/share_process_advance_permission_title"
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_allow_download_and_sync_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:text="@string/advanced_settings"
|
||||
android:textColor="@color/primary"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_process_allow_resharing_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/allow_resharing"
|
||||
android:visibility="gone"
|
||||
android:text="@string/share_allow_download_and_sync_permission"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/custom_permission_layout"
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/share_custom_permissions_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:text="@string/share_custom_permission"
|
||||
android:textColor="@color/primary"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_read_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:enabled="false"
|
||||
android:text="@string/share_read_permission"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_create_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/share_create_permission"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_edit_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/share_edit_permission"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/share_re_share_permission"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/share_delete_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/minimum_size_for_touchable_area"
|
||||
android:text="@string/share_delete_permission"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/share_process_set_password_switch"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -2,41 +2,23 @@
|
||||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2021 TSI-mc
|
||||
~ SPDX-FileCopyrightText: 2021 Nextcloud GmbH
|
||||
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
||||
-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
~ SPDX-FileCopyrightText: 2025 Alper Ozturk <alper.ozturk@nextcloud.com>
|
||||
~ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:id="@+id/quickPermissionButton"
|
||||
android:textColor="@color/text_color"
|
||||
app:iconTint="@color/text_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingStart="@dimen/standard_padding"
|
||||
android:paddingEnd="@dimen/standard_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/tv_quick_share_check_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_baseline_check_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="@color/primary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_quick_share_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/bottom_sheet_text_start_margin"
|
||||
android:text="@string/link_share_view_only"
|
||||
android:textColor="@color/text_color"
|
||||
android:textSize="@dimen/bottom_sheet_text_size"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/tv_quick_share_check_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minHeight="56dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="12dp" />
|
@ -787,7 +787,7 @@
|
||||
<string name="screenshot_05_autoUpload_heading">Automatisk upload</string>
|
||||
<string name="screenshot_05_autoUpload_subline">for dine billeder og videoer</string>
|
||||
<string name="screenshot_06_davdroid_heading">Kalender og kontakter</string>
|
||||
<string name="screenshot_06_davdroid_subline">Synk med DAVx⁵</string>
|
||||
<string name="screenshot_06_davdroid_subline">Synkronisér med DAVx⁵ </string>
|
||||
<string name="search_error">Fejl ved indhenting af søgeresultater</string>
|
||||
<string name="secure_share_not_set_up">Sikker deling er ikke sat op for denne bruger</string>
|
||||
<string name="secure_share_search">Sikker deling...</string>
|
||||
@ -1119,12 +1119,12 @@
|
||||
<item quantity="other">%d sekunder siden</item>
|
||||
</plurals>
|
||||
<plurals name="time_minutes_ago">
|
||||
<item quantity="one">%d minut sidenago</item>
|
||||
<item quantity="one">%d minut siden</item>
|
||||
<item quantity="other">%d minutter siden</item>
|
||||
</plurals>
|
||||
<plurals name="time_hours_ago">
|
||||
<item quantity="one">%d time sidenago</item>
|
||||
<item quantity="other">%d timer sidenago</item>
|
||||
<item quantity="one">%d time siden</item>
|
||||
<item quantity="other">%d timer siden</item>
|
||||
</plurals>
|
||||
<plurals name="sync_fail_in_favourites_content">
|
||||
<item quantity="one">Kunne ikke synkronisere %1$d fil (konflikter: %2$d)</item>
|
||||
|
@ -269,6 +269,7 @@
|
||||
<string name="file_name_validator_current_path_is_invalid">Pašreizējais mapes nosaukums ir nederīgs, lūgums pārdēvēt mapi. Pārvirza uz sākumu...</string>
|
||||
<string name="file_name_validator_rename_before_move_or_copy">%s. Lūgums pirms pārvietošanas vai kopēšanas pārdēvēt datni</string>
|
||||
<string name="file_not_found">Datne nav atrasta</string>
|
||||
<string name="file_not_synced">Datni nevarēja sinhronizēt. Rāda pēdējo pieejamo versiju.</string>
|
||||
<string name="file_rename">Pārdēvēt</string>
|
||||
<string name="filedetails_details">Detaļas</string>
|
||||
<string name="filedetails_download">Lejupielādēt</string>
|
||||
|
@ -26,16 +26,6 @@
|
||||
<item>@string/pref_instant_name_collision_policy_entries_cancel</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="folder_share_permission_dialog_values" translatable="false">
|
||||
<item>@string/link_share_view_only</item>
|
||||
<item>@string/link_share_allow_upload_and_editing</item>
|
||||
<item>@string/link_share_file_drop</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="file_share_permission_dialog_values" translatable="false">
|
||||
<item>@string/link_share_view_only</item>
|
||||
<item>@string/link_share_editing</item>
|
||||
</string-array>
|
||||
<string-array name="sub_folder_rule_values" translatable="false">
|
||||
<item>@string/sub_folder_rule_month</item>
|
||||
<item>@string/sub_folder_rule_year</item>
|
||||
|
@ -616,12 +616,10 @@
|
||||
|
||||
<string name="share_dialog_title">Sharing</string>
|
||||
<string name="share_file">Share %1$s</string>
|
||||
<string name="share_expiration_date_label">Expires %1$s</string>
|
||||
<string name="share_expiration_date_format">%1$s</string>
|
||||
<string name="share_no_expiration_date_label">Set expiration date</string>
|
||||
<string name="share_via_link_section_title">Share link</string>
|
||||
<string name="share_via_link_send_link_label">Send link</string>
|
||||
<string name="share_password_title">Password-protected</string>
|
||||
<string name="share_no_password_title">Set password</string>
|
||||
<string name="share_with_title">Share with…</string>
|
||||
<string name="share_via_link_unset_password">Unset</string>
|
||||
@ -838,6 +836,7 @@
|
||||
<string name="drawer_header_background">Background image of drawer header</string>
|
||||
<string name="account_icon">Account icon</string>
|
||||
<string name="file_detail_sharing_fragment_no_contact_app_message">No app available to select contacts</string>
|
||||
<string name="file_detail_share_already_active">You cannot create a share, sharing is already active from this user.</string>
|
||||
|
||||
<string name="end_to_end_encryption_certificate_verification_failed">Failed to verify public key</string>
|
||||
<string name="end_to_end_encryption_server_public_key_unavailable">Unable to retrieve public key</string>
|
||||
@ -1073,6 +1072,11 @@
|
||||
<string name="create_new">New</string>
|
||||
<string name="editor_placeholder" translatable="false">%1$s %2$s</string>
|
||||
|
||||
<string name="share_permission_file_request">File request</string>
|
||||
<string name="share_permission_view_only">View only</string>
|
||||
<string name="share_permission_can_edit">Can edit</string>
|
||||
<string name="share_permission_secure_file_drop">Secure file drop</string>
|
||||
|
||||
<string name="sync_not_enough_space_dialog_action_choose">Choose what to sync</string>
|
||||
<string name="sync_not_enough_space_dialog_action_free_space">Free up space</string>
|
||||
<string name="sync_not_enough_space_dialog_placeholder">%1$s is %2$s, but there is only %3$s available on device.</string>
|
||||
@ -1092,11 +1096,17 @@
|
||||
<string name="public_share_name">New name</string>
|
||||
<string name="share_link_with_label">Share link (%1$s)</string>
|
||||
<string name="share_link">Share link</string>
|
||||
<string name="allow_resharing">Allow resharing</string>
|
||||
<string name="link_share_view_only">View only</string>
|
||||
<string name="share_custom_permission">Custom permissions</string>
|
||||
<string name="share_read_permission">Read</string>
|
||||
<string name="file_not_found_cannot_share">File not found. Unable to create a share.</string>
|
||||
<string name="share_cannot_update_empty_note">We couldn’t update the share. Please add a note and try again.</string>
|
||||
<string name="share_option_required">Please select at least one sharing option before continuing.</string>
|
||||
<string name="share_allow_download_and_sync_permission">Allow download and sync</string>
|
||||
<string name="share_create_permission">Create</string>
|
||||
<string name="share_edit_permission">Edit</string>
|
||||
<string name="share_re_share_permission">Share</string>
|
||||
<string name="share_delete_permission">Delete</string>
|
||||
<string name="link_share_editing">Editing</string>
|
||||
<string name="link_share_allow_upload_and_editing">Allow upload and editing</string>
|
||||
<string name="link_share_file_drop">File drop (upload only)</string>
|
||||
<string name="could_not_retrieve_shares">Could not retrieve shares</string>
|
||||
<string name="failed_update_ui">Failed to update UI</string>
|
||||
<string name="email_pick_failed">Failed to pick email address.</string>
|
||||
@ -1162,12 +1172,7 @@
|
||||
<string name="create">Create</string>
|
||||
<string name="select_one_template">Please select one template</string>
|
||||
<string name="choose_template_helper_text">Please choose a template and enter a file name.</string>
|
||||
<string name="share_permission_view_only">View only</string>
|
||||
<string name="share_permission_can_edit">Can edit</string>
|
||||
<string name="share_permission_file_drop">File drop</string>
|
||||
<string name="share_permission_secure_file_drop">Secure file drop</string>
|
||||
<string name="share_permissions">Share permissions</string>
|
||||
<string name="advanced_settings">Advanced settings</string>
|
||||
<string name="common_next">Next</string>
|
||||
<string name="send_share">Send share</string>
|
||||
<string name="no_share_permission_selected">Please select at least one permission to share.</string>
|
||||
@ -1330,6 +1335,7 @@
|
||||
<string name="re_enable_auto_upload_desc">Due to new restrictions imposed by Google, we have been forced to remove an important permission. We are currently working with Google to resolve this issue and restore full functionality.\n\nTo re-enable auto upload for new photos and videos:\nSelect \"Allow all\" in the following dialogue or the system settings.\nAllow media location when prompted, as this allows Nextcloud to store location data when uploading images.\n\nThe permissions dialogue is only displayed when necessary. If in doubt, check the system settings.\n\nAuto upload will only be able to upload image and video files when using the Google Play version of the Nextcloud app.\n\nPlease check for any files that may not have been uploaded since December 2024.</string>
|
||||
<string name="click_to_learn_how_to_re_enable_auto_uploads">Manual intervention required to re-enable auto-upload</string>
|
||||
<string name="share_download_limit">Set download limit</string>
|
||||
<string name="set_download_limit_failed">Unable to set download limit. Please check capabilities.</string>
|
||||
<string name="download_limit">Download limit</string>
|
||||
<plurals name="share_download_limit_description">
|
||||
<item quantity="one">%1$d download remaining</item>
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
buildscript {
|
||||
ext {
|
||||
androidLibraryVersion ="13fb6e486d82696073cc1a56a8ff8371bba690de"
|
||||
androidLibraryVersion ="d862794d794a7e8d8b53da98aa801753e684bf52"
|
||||
androidCommonLibraryVersion = "0.25.0"
|
||||
androidPluginVersion = "8.9.2"
|
||||
androidxMediaVersion = "1.5.1"
|
||||
|
@ -11279,6 +11279,14 @@
|
||||
<sha256 value="b14de6c6ed598b5b31cb8842b41f1cbb03313bf4bc29eaaa9dfd17f07b6dd8f0" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="3ff8fea794d165afc1b3be698ad04bdee59e37c1">
|
||||
<artifact name="android-library-3ff8fea794d165afc1b3be698ad04bdee59e37c1.aar">
|
||||
<sha256 value="43888bc29328b621703ca813bee857853e41af6979aeaa44578beef2477ce314" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="android-library-3ff8fea794d165afc1b3be698ad04bdee59e37c1.module">
|
||||
<sha256 value="cba548d2fbfd1c6e1b2261017c71f9a09884d3ac20558378524051f532b989de" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="406b50853375215998190d661110ae8c881a054e">
|
||||
<artifact name="android-library-406b50853375215998190d661110ae8c881a054e.aar">
|
||||
<sha256 value="b29e961d64d5f9e6e2e04cac07a23d50a5df0769f76550702cd8a1a29684f23d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
@ -11583,12 +11591,12 @@
|
||||
<sha256 value="6907f3626be02ec7508a98ea912529780445a0336dc4fc665c96af007c5d6c49" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="a2ed4ca78486906086bacf873080d0046272c294">
|
||||
<artifact name="android-library-a2ed4ca78486906086bacf873080d0046272c294.aar">
|
||||
<sha256 value="e22b38a2e7e9ec9461af2005c573f7c3bf097651f0bda27367fb355f82ef217d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
<component group="com.github.nextcloud" name="android-library" version="a07602d104">
|
||||
<artifact name="android-library-a07602d104.aar">
|
||||
<sha256 value="b4f29732f325849d974c2547fb182322dff615ae29f8da29f56f1dfa8e64b09d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="android-library-a2ed4ca78486906086bacf873080d0046272c294.module">
|
||||
<sha256 value="ff8218520b3451a48d646b217d7c5bcfda75193cb11b92bffeb0bd698d494a45" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
<artifact name="android-library-a07602d104.module">
|
||||
<sha256 value="c310576fd498cdc27dbcbf15532d78cd3c9cca1e30708b7e23001b7d53633d15" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="a4d86ef9d1">
|
||||
@ -11655,6 +11663,14 @@
|
||||
<sha256 value="29e4ea50d4197b79bdfefe7e0ce41a58cda967cd8c4307981d34f37c4c901cd8" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="bfca7ddb5e">
|
||||
<artifact name="android-library-bfca7ddb5e.aar">
|
||||
<sha256 value="7686a3588271fe4f90bf9708b13aab800abb89889d6e04d4a85bc24621968364" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="android-library-bfca7ddb5e.module">
|
||||
<sha256 value="bb68aa824d8769dbe93875da75891dc3794519fdd13c60a7c2bd45c1353634d8" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="c219388da22028f36219acff61ae2d722a63f408">
|
||||
<artifact name="android-library-c219388da22028f36219acff61ae2d722a63f408.aar">
|
||||
<sha256 value="c253a126ca3c32dd5b373ab1c64668e4603305b3113b052fc0fc5e3c833a913c" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
@ -11743,6 +11759,14 @@
|
||||
<sha256 value="d7c4c3c4f9458f2de9a63ebac3c80e99c04e358c4aef347c499b52690d761c86" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="d862794d794a7e8d8b53da98aa801753e684bf52">
|
||||
<artifact name="android-library-d862794d794a7e8d8b53da98aa801753e684bf52.aar">
|
||||
<sha256 value="d82be01cadecc9c51d68ed1ef50b98cf19266bdf1c1f781a696b958d94fc4184" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="android-library-d862794d794a7e8d8b53da98aa801753e684bf52.module">
|
||||
<sha256 value="01b31ce0b551f0537aa939e6d316e66d7b7ba11e81e170a58e2ceb2ff0e1939f" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="d8c46b28ff7f268af5dfad7075f390d8eac434cd">
|
||||
<artifact name="android-library-d8c46b28ff7f268af5dfad7075f390d8eac434cd.aar">
|
||||
<sha256 value="c253a126ca3c32dd5b373ab1c64668e4603305b3113b052fc0fc5e3c833a913c" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
@ -11791,6 +11815,14 @@
|
||||
<sha256 value="8e3efc498a87a7538eb6e4281c1c8a8ea22e0a0c38a584a10c4ca7b9fd0009e8" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="efceb970c7">
|
||||
<artifact name="android-library-efceb970c7.aar">
|
||||
<sha256 value="3c708625831efefa7a6dba0572b93f81dd537ee16a4b5c5e0436c744e857427b" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="android-library-efceb970c7.module">
|
||||
<sha256 value="06b7cbe7980a6d07b30ac093c623a6153463ce6ff28515d004efd117acd2f5cd" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud" name="android-library" version="f174c1ee78">
|
||||
<artifact name="android-library-f174c1ee78.aar">
|
||||
<sha256 value="8f62a8bb0b9699dfbfcdf58493d0386e6b91113e3ba2157421249ab3cbc55d8f" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user