diff --git a/app/src/main/java/com/nextcloud/client/account/UserAccountManager.java b/app/src/main/java/com/nextcloud/client/account/UserAccountManager.java index 89fb27b2e1f5..09b7a4fe170f 100644 --- a/app/src/main/java/com/nextcloud/client/account/UserAccountManager.java +++ b/app/src/main/java/com/nextcloud/client/account/UserAccountManager.java @@ -12,6 +12,7 @@ import android.content.Context; import android.content.Intent; +import com.nextcloud.android.common.core.utils.AccountNameUtils; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -142,8 +143,7 @@ public interface UserAccountManager extends CurrentAccountProvider { * @return User name (without domain) or null, if name cannot be extracted. */ static String getUsername(User user) { - final String name = user.getAccountName(); - return name.substring(0, name.lastIndexOf('@')); + return AccountNameUtils.getUserPart(user.getAccountName()); } @Nullable diff --git a/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java b/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java index 8b941d9f70e6..9c4f4a9cd05f 100644 --- a/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java +++ b/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java @@ -19,6 +19,7 @@ import android.preference.PreferenceManager; import android.text.TextUtils; +import com.nextcloud.android.common.core.utils.AccountNameUtils; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.common.NextcloudClient; import com.nextcloud.utils.extensions.AccountExtensionsKt; @@ -130,52 +131,20 @@ public boolean exists(Account account) { return false; } - int lastAtPos = account.name.lastIndexOf('@'); - if (lastAtPos == -1) { - Log_OC.d(TAG, "lastAtPos cannot be found"); - return false; - } - - boolean isLastAtPosInBoundsForHostAndPort = lastAtPos + 1 < account.name.length(); - if (!isLastAtPosInBoundsForHostAndPort) { - Log_OC.d(TAG, "lastAtPos not in bounds"); - return false; - } - - String hostAndPort = account.name.substring(lastAtPos + 1); - - String username = account.name.substring(0, lastAtPos); + String username = AccountNameUtils.getUserPart(account.name); + String hostAndPort = AccountNameUtils.getServerPart(account.name); if (hostAndPort.isEmpty() || username.isEmpty()) { Log_OC.d(TAG, "hostAndPort or username is empty"); return false; } - String otherHostAndPort; - String otherUsername; - for (Account otherAccount : nextcloudAccounts) { - // Skip null accounts or accounts with null names if (otherAccount == null || otherAccount.name.isEmpty()) { continue; } - lastAtPos = otherAccount.name.lastIndexOf('@'); - - // Skip invalid account names - if (lastAtPos == -1) { - continue; - } - - boolean isLastAtPosInBoundsForOtherHostAndPort = lastAtPos + 1 < otherAccount.name.length(); - if (!isLastAtPosInBoundsForOtherHostAndPort) { - continue; - } - otherHostAndPort = otherAccount.name.substring(lastAtPos + 1); - - otherUsername = otherAccount.name.substring(0, lastAtPos); - - if (otherHostAndPort.equals(hostAndPort) && - otherUsername.equalsIgnoreCase(username)) { + if (hostAndPort.equals(AccountNameUtils.getServerPart(otherAccount.name)) && + username.equalsIgnoreCase(AccountNameUtils.getUserPart(otherAccount.name))) { return true; } } @@ -396,7 +365,16 @@ public void resetOwnCloudAccount() { @Override public boolean accountOwnsFile(OCFile file, Account account) { final String ownerId = file.getOwnerId(); - return TextUtils.isEmpty(ownerId) || account.name.split("@")[0].equalsIgnoreCase(ownerId); + if (TextUtils.isEmpty(ownerId)) { + return true; + } + + String userId = accountManager.getUserData(account, AccountUtils.Constants.KEY_USER_ID); + if (TextUtils.isEmpty(userId)) { + return !file.isSharedWithMe(); + } + + return ownerId.equalsIgnoreCase(userId); } @Override diff --git a/app/src/main/java/com/nextcloud/client/files/DeepLinkHandler.kt b/app/src/main/java/com/nextcloud/client/files/DeepLinkHandler.kt index a7cc8114dc7f..df2d53052116 100644 --- a/app/src/main/java/com/nextcloud/client/files/DeepLinkHandler.kt +++ b/app/src/main/java/com/nextcloud/client/files/DeepLinkHandler.kt @@ -7,6 +7,7 @@ package com.nextcloud.client.files import android.net.Uri +import com.nextcloud.android.common.core.utils.AccountNameUtils import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager @@ -53,5 +54,5 @@ class DeepLinkHandler(private val userAccountManager: UserAccountManager) { } private fun getMatchingUsers(serverBaseUrl: String): List = - userAccountManager.allUsers.filter { it.server.uri.toString() == serverBaseUrl } + userAccountManager.allUsers.filter { AccountNameUtils.isSameServer(it.server.uri.toString(), serverBaseUrl) } } diff --git a/app/src/main/java/com/nextcloud/utils/avatar/AvatarRequest.kt b/app/src/main/java/com/nextcloud/utils/avatar/AvatarRequest.kt index 1861529273c7..43623546c4eb 100644 --- a/app/src/main/java/com/nextcloud/utils/avatar/AvatarRequest.kt +++ b/app/src/main/java/com/nextcloud/utils/avatar/AvatarRequest.kt @@ -7,12 +7,13 @@ package com.nextcloud.utils.avatar +import com.nextcloud.android.common.core.utils.AccountNameUtils import com.nextcloud.client.account.User data class AvatarRequest(val user: User, val userId: String, val displayName: String?, val avatarRadius: Float) { - val serverName: String = user.accountName.substringAfterLast('@') + val serverName: String = AccountNameUtils.getServerPart(user.accountName) - val accountName: String = "$userId@$serverName" + val accountName: String = AccountNameUtils.build(userId, serverName) fun cacheKey(eTag: String): String = "a_${userId}_${serverName}_$eTag" } diff --git a/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java b/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java index ef8df0f9c355..427e1178d9f2 100644 --- a/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java @@ -27,6 +27,7 @@ import android.util.Log; import android.widget.Toast; +import com.nextcloud.android.common.core.utils.AccountNameUtils; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.owncloud.android.R; @@ -293,10 +294,9 @@ private Cursor searchForUsersOrGroups(Uri uri) { displayName = name; subline = getContext().getString(R.string.remote); } else { - String[] uriSplitted = shareWith.split("@"); displayName = name; subline = getContext().getString(R.string.share_known_remote_on_clarification, - uriSplitted[uriSplitted.length - 1]); + AccountNameUtils.getServerPart(shareWith)); } } break; @@ -311,10 +311,9 @@ private Cursor searchForUsersOrGroups(Uri uri) { subline = getContext().getString(R.string.remote); subline = ""; } else { - String[] uriSplitted = shareWith.split("@"); displayName = name; subline = getContext().getString(R.string.share_known_remote_on_clarification, - uriSplitted[uriSplitted.length - 1]); + AccountNameUtils.getServerPart(shareWith)); } } break; @@ -404,9 +403,10 @@ public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) thr String userId = uri.getQueryParameter("shareWith"); String displayName = uri.getQueryParameter("displayName"); String accountName = accountManager.getUser().getAccountName(); - String serverName = accountName.substring(accountName.lastIndexOf('@') + 1); + String serverName = AccountNameUtils.getServerPart(accountName); - String eTag = arbitraryDataProvider.getValue(userId + "@" + serverName, ThumbnailsCacheManager.AVATAR); + String eTag = arbitraryDataProvider.getValue(AccountNameUtils.build(userId, serverName), + ThumbnailsCacheManager.AVATAR); String avatarKey = "a_" + userId + "_" + serverName + "_" + eTag; StatusType status = StatusType.valueOf(uri.getQueryParameter("status")); diff --git a/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt b/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt index 41f523208b36..07da8fb29132 100644 --- a/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt +++ b/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.kt @@ -17,6 +17,7 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.core.view.updateLayoutParams import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.nextcloud.android.common.core.utils.AccountNameUtils import com.nextcloud.client.account.User import com.nextcloud.utils.GlideHelper.loadCircularBitmapIntoImageView import com.nextcloud.utils.avatar.AvatarGenerationListener @@ -81,7 +82,7 @@ class AvatarGroupLayout @JvmOverloads constructor( val avatarCount = sharees.size.coerceAtMost(MAX_AVATAR_COUNT) val hasOverflow = sharees.size > MAX_AVATAR_COUNT - val serverName = user.accountName.substringAfterLast('@') + val serverName = AccountNameUtils.getServerPart(user.accountName) repeat(avatarCount) { index -> val avatar = addAvatarView(index) @@ -130,7 +131,7 @@ class AvatarGroupLayout @JvmOverloads constructor( else -> { val userId = checkNotNull(sharee.userId) - avatar.tag = "$userId@$serverName" + avatar.tag = AccountNameUtils.build(userId, serverName) avatarGenerator.setUserAvatar( userId, this, @@ -145,9 +146,8 @@ class AvatarGroupLayout @JvmOverloads constructor( } private fun showFederatedShareAvatar(federatedId: String, avatar: ImageView, viewThemeUtils: ViewThemeUtils) { - val parts = federatedId.split("@") - val userId = parts.first() - val url = parts.getOrNull(1)?.let { server -> + val userId = AccountNameUtils.getUserPart(federatedId) + val url = AccountNameUtils.getServerPart(federatedId).ifEmpty { null }?.let { server -> "https://$server/index.php/avatar/$userId/${resources.getInteger(R.integer.file_avatar_px)}" } val placeholder = createFederatedPlaceholder(userId, viewThemeUtils) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 7c962148087d..e286236ad015 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -3123,34 +3123,32 @@ class FileDisplayActivity : val intentData = intent.data if (userName == null && fileId == null && intentData != null) { openDeepLink(intentData) - } else { - val optionalUser = if (userName == null) user else userAccountManager.getUser(userName) - if (optionalUser.isPresent) { - if (!TextUtils.isEmpty(fileId)) { - openFile(optionalUser.get(), fileId) - } else if (!TextUtils.isEmpty(filePath)) { - openFileByPath(optionalUser.get(), filePath) - } else { - accountClicked(optionalUser.get()) - } - } else { - SnackbarUtil.show(this, getString(R.string.associated_account_not_found)) - } + return + } + + val optionalUser = if (userName == null) user else userAccountManager.getUser(userName) + val targetUser = optionalUser.orElse(null) ?: run { + SnackbarUtil.show(this, getString(R.string.associated_account_not_found)) + return + } + + when { + !fileId.isNullOrEmpty() -> openFile(targetUser, fileId) + !filePath.isNullOrEmpty() -> openFileByPath(targetUser, filePath) + else -> accountClicked(targetUser) } } private fun openDeepLink(uri: Uri) { - val linkHandler = DeepLinkHandler(userAccountManager) - val match = linkHandler.parseDeepLink(uri) - - if (match == null) { + val match = DeepLinkHandler(userAccountManager).parseDeepLink(uri) ?: run { handleDeepLink(uri) - } else if (match.users.isEmpty()) { - SnackbarUtil.show(this, getString(R.string.associated_account_not_found)) - } else if (match.users.size == SINGLE_USER_SIZE) { - openFile(match.users[0], match.fileId) - } else { - selectUserAndOpenFile(match.users.toMutableList(), match.fileId) + return + } + + when { + match.users.isEmpty() -> SnackbarUtil.show(this, getString(R.string.associated_account_not_found)) + match.users.size == SINGLE_USER_SIZE -> openFile(match.users.first(), match.fileId) + else -> selectUserAndOpenFile(match.users.toMutableList(), match.fileId) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.kt index 174b135dd841..62b5e5df60b0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.kt @@ -17,6 +17,7 @@ import android.view.LayoutInflater import android.view.ViewGroup import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.android.common.core.utils.AccountNameUtils import com.nextcloud.client.account.User import com.nextcloud.utils.avatar.AvatarGenerationListener import com.nextcloud.utils.avatar.AvatarGenerator @@ -156,7 +157,7 @@ class ShareeListAdapter( override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean { if (callContext is ImageView) { // needs to be changed once federated users have avatars - return callContext.tag.toString() == tag?.substringBefore('@') + return callContext.tag.toString() == tag?.let(AccountNameUtils::getUserPart) } return false } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt index cf2484ae7a4e..f8dbf5ce44ce 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt @@ -28,6 +28,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.button.MaterialButton import com.nextcloud.android.lib.resources.profile.Action import com.nextcloud.android.lib.resources.profile.HoverCard +import com.nextcloud.android.common.core.utils.AccountNameUtils import com.nextcloud.client.account.User import com.nextcloud.client.utils.IntentUtil import com.nextcloud.utils.avatar.AvatarGenerationListener @@ -188,7 +189,7 @@ class ProfileBottomSheetDialog( override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean { if (callContext is ImageView) { // needs to be changed once federated users have avatars - return callContext.tag.toString() == tag!!.split("@").toTypedArray()[0] + return callContext.tag.toString() == tag?.let(AccountNameUtils::getUserPart) } return false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 26fc6ba0b207..0a55fdc5964d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later [versions] -androidCommonLibraryVersion = "0.34.0" +androidCommonLibraryVersion = "f6515c1c36" androidGifDrawableVersion = "1.2.32" androidImageCropperVersion = "4.7.0" androidLibraryVersion ="a15346847d3f03c8b17932bc4acf2124a2f82b81" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 09fd71ac6d84..73a86593cd29 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -24290,6 +24290,14 @@ + + + + + + + + @@ -24590,6 +24598,14 @@ + + + + + + + + @@ -24886,6 +24902,14 @@ + + + + + + + + @@ -29766,6 +29790,11 @@ + + + + +