Merge commit 'c95615aeaa7090c5b4e6e07fdd6e790af31a5b00'

This commit is contained in:
drone 2020-09-23 06:14:57 +00:00
commit b516eaf657
56 changed files with 1777 additions and 1152 deletions

View file

@ -63,7 +63,7 @@ ext {
markwonVersion = "4.6.0" markwonVersion = "4.6.0"
prismVersion = "2.0.0" prismVersion = "2.0.0"
butterknifeVersion = "10.2.3" butterknifeVersion = "10.2.3"
androidLibraryVersion = "master-SNAPSHOT" androidLibraryVersion = "sharingPart2-SNAPSHOT"
mockitoVersion = "3.5.11" mockitoVersion = "3.5.11"
byteBuddyVersion = "1.10.15" byteBuddyVersion = "1.10.15"
espressoVersion = "3.3.0" espressoVersion = "3.3.0"

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,2 +1,2 @@
DO NOT TOUCH; GENERATED BY DRONE DO NOT TOUCH; GENERATED BY DRONE
<span class="mdl-layout-title">Lint Report: 81 warnings</span> <span class="mdl-layout-title">Lint Report: 80 warnings</span>

View file

@ -97,7 +97,7 @@ public class FileDisplayActivityIT extends AbstractOnServerIT {
"users", "users",
false, false,
"", "",
OCShare.DEFAULT_PERMISSION) OCShare.NO_PERMISSION)
.execute(client).isSuccess()); .execute(client).isSuccess());
// share folder to circle // share folder to circle

View file

@ -58,6 +58,7 @@ import androidx.test.runner.lifecycle.Stage;
import static androidx.test.InstrumentationRegistry.getInstrumentation; import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -96,7 +97,7 @@ public abstract class AbstractIT {
Account temp = new Account("test@https://server.com", MainApp.getAccountType(targetContext)); Account temp = new Account("test@https://server.com", MainApp.getAccountType(targetContext));
platformAccountManager.addAccountExplicitly(temp, "password", null); platformAccountManager.addAccountExplicitly(temp, "password", null);
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_BASE_URL, "https://server.com"); platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_BASE_URL, "https://server.com");
platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_USER_ID, "test"); platformAccountManager.setUserData(temp, KEY_USER_ID, "test");
final UserAccountManager userAccountManager = UserAccountManagerImpl.fromContext(targetContext); final UserAccountManager userAccountManager = UserAccountManagerImpl.fromContext(targetContext);
account = userAccountManager.getAccountByName("test@https://server.com"); account = userAccountManager.getAccountByName("test@https://server.com");
@ -381,4 +382,8 @@ public abstract class AbstractIT {
return name; return name;
} }
public static String getUserId(User user) {
return AccountManager.get(targetContext).getUserData(user.toPlatformAccount(), KEY_USER_ID);
}
} }

View file

@ -88,7 +88,6 @@ public class OCFileUnitTest {
mFile.setEtag(ETAG); mFile.setEtag(ETAG);
mFile.setSharedViaLink(true); mFile.setSharedViaLink(true);
mFile.setSharedWithSharee(true); mFile.setSharedWithSharee(true);
mFile.setPublicLink(PUBLIC_LINK);
mFile.setPermissions(PERMISSIONS); mFile.setPermissions(PERMISSIONS);
mFile.setRemoteId(REMOTE_ID); mFile.setRemoteId(REMOTE_ID);
mFile.setUpdateThumbnailNeeded(true); mFile.setUpdateThumbnailNeeded(true);
@ -122,7 +121,6 @@ public class OCFileUnitTest {
assertThat(fileReadFromParcel.getEtag(), is(ETAG)); assertThat(fileReadFromParcel.getEtag(), is(ETAG));
assertThat(fileReadFromParcel.isSharedViaLink(), is(true)); assertThat(fileReadFromParcel.isSharedViaLink(), is(true));
assertThat(fileReadFromParcel.isSharedWithSharee(), is(true)); assertThat(fileReadFromParcel.isSharedWithSharee(), is(true));
assertThat(fileReadFromParcel.getPublicLink(), is(PUBLIC_LINK));
assertThat(fileReadFromParcel.getPermissions(), is(PERMISSIONS)); assertThat(fileReadFromParcel.getPermissions(), is(PERMISSIONS));
assertThat(fileReadFromParcel.getRemoteId(), is(REMOTE_ID)); assertThat(fileReadFromParcel.getRemoteId(), is(REMOTE_ID));
assertThat(fileReadFromParcel.isUpdateThumbnailNeeded(), is(true)); assertThat(fileReadFromParcel.isUpdateThumbnailNeeded(), is(true));

View file

@ -172,7 +172,7 @@ class FileDetailFragmentStaticServerIT : AbstractIT() {
@Test @Test
@ScreenshotTest @ScreenshotTest
fun showDetails_Sharing() { fun showDetailsSharing() {
val sut = testActivityRule.launchActivity(null) val sut = testActivityRule.launchActivity(null)
sut.addFragment(FileDetailFragment.newInstance(file, user, 1)) sut.addFragment(FileDetailFragment.newInstance(file, user, 1))

View file

@ -0,0 +1,630 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.fragment
import android.Manifest
import android.widget.ImageView
import androidx.appcompat.widget.PopupMenu
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.rule.GrantPermissionRule
import com.nextcloud.client.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.resources.shares.OCShare
import com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG
import com.owncloud.android.lib.resources.shares.OCShare.DELETE_PERMISSION_FLAG
import com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FILE
import com.owncloud.android.lib.resources.shares.OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER
import com.owncloud.android.lib.resources.shares.OCShare.NO_PERMISSION
import com.owncloud.android.lib.resources.shares.OCShare.READ_PERMISSION_FLAG
import com.owncloud.android.lib.resources.shares.OCShare.SHARE_PERMISSION_FLAG
import com.owncloud.android.lib.resources.shares.ShareType
import com.owncloud.android.utils.ScreenshotTest
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
class FileDetailSharingFragmentIT : AbstractIT() {
@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)
@get:Rule
val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
lateinit var file: OCFile
lateinit var folder: OCFile
lateinit var activity: TestActivity
@Before
fun before() {
activity = testActivityRule.launchActivity(null)
file = OCFile("/test.md").apply {
parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId
permissions = OCFile.PERMISSION_CAN_RESHARE
}
folder = OCFile("/test").apply {
setFolder()
parentId = activity.storageManager.getFileByEncryptedRemotePath("/").fileId
permissions = OCFile.PERMISSION_CAN_RESHARE
}
}
@Test
@ScreenshotTest
fun listSharesFileNone() {
show(file)
}
@Test
@ScreenshotTest
fun listSharesFileResharingNotAllowed() {
file.permissions = ""
show(file)
}
@Test
@ScreenshotTest
@Suppress("MagicNumber")
fun listSharesFileAllShareTypes() {
OCShare(file.decryptedRemotePath).apply {
remoteId = 1
shareType = ShareType.USER
sharedWithDisplayName = "Admin"
permissions = MAXIMUM_PERMISSIONS_FOR_FILE
userId = getUserId(user)
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 2
shareType = ShareType.GROUP
sharedWithDisplayName = "Group"
permissions = MAXIMUM_PERMISSIONS_FOR_FILE
userId = getUserId(user)
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 3
shareType = ShareType.EMAIL
sharedWithDisplayName = "admin@nextcloud.server.com"
userId = getUserId(user)
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 4
shareType = ShareType.PUBLIC_LINK
sharedWithDisplayName = "Customer"
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 5
shareType = ShareType.PUBLIC_LINK
sharedWithDisplayName = "Colleagues"
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 6
shareType = ShareType.FEDERATED
sharedWithDisplayName = "admin@nextcloud.remoteserver.com"
permissions = OCShare.FEDERATED_PERMISSIONS_FOR_FILE
userId = getUserId(user)
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 7
shareType = ShareType.CIRCLE
sharedWithDisplayName = "Private circle"
permissions = SHARE_PERMISSION_FLAG
userId = getUserId(user)
activity.storageManager.saveShare(this)
}
OCShare(file.decryptedRemotePath).apply {
remoteId = 8
shareType = ShareType.ROOM
sharedWithDisplayName = "Meeting"
permissions = SHARE_PERMISSION_FLAG
userId = getUserId(user)
activity.storageManager.saveShare(this)
}
show(file)
}
private fun show(file: OCFile) {
val fragment = FileDetailSharingFragment.newInstance(file, user)
activity.addFragment(fragment)
waitForIdleSync()
screenshot(activity)
}
@Test
@Suppress("MagicNumber")
// public link and email are handled the same way
fun publicLinkOptionMenuFolder() {
val sut = FileDetailSharingFragment.newInstance(file, user)
activity.addFragment(sut)
shortSleep()
sut.refreshCapabilitiesFromDB()
val overflowMenuShareLink = ImageView(targetContext)
val popup = PopupMenu(targetContext, overflowMenuShareLink)
popup.inflate(R.menu.fragment_file_detail_sharing_public_link)
val publicShare = OCShare().apply {
isFolder = true
shareType = ShareType.PUBLIC_LINK
permissions = 17
}
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
// check if items are visible
assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible)
assertTrue(popup.menu.findItem(R.id.action_password).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_send_link).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible)
assertTrue(popup.menu.findItem(R.id.action_edit_label).isVisible)
assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible)
assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible)
// read-only
assertTrue(popup.menu.findItem(R.id.link_share_read_only).isChecked)
assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked)
assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked)
// upload and editing
publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked)
assertTrue(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked)
assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isChecked)
// file drop
publicShare.permissions = 4
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertFalse(popup.menu.findItem(R.id.link_share_read_only).isChecked)
assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isChecked)
assertTrue(popup.menu.findItem(R.id.link_share_file_drop).isChecked)
// password protection
publicShare.shareWith = "someValue"
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_password_title)
)
publicShare.shareWith = ""
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_no_password_title)
)
// hide download
publicShare.isHideFileDownload = true
publicShare.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked)
publicShare.isHideFileDownload = false
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked)
publicShare.expirationDate = 1582019340000
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_share_expiration_date).title
.startsWith(targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])
)
publicShare.expirationDate = 0
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_share_expiration_date).title ==
targetContext.getString(R.string.share_no_expiration_date_label)
)
// file
publicShare.isFolder = false
publicShare.permissions = READ_PERMISSION_FLAG
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
// check if items are visible
assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible)
assertTrue(popup.menu.findItem(R.id.action_password).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_send_link).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible)
assertTrue(popup.menu.findItem(R.id.action_edit_label).isVisible)
assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible)
assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible)
assertFalse(popup.menu.findItem(R.id.link_share_read_only).isVisible)
assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isVisible)
assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isVisible)
assertTrue(popup.menu.findItem(R.id.allow_editing).isVisible)
// allow editing
publicShare.permissions = 17 // from server
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked)
publicShare.permissions = 19 // from server
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked)
// hide download
publicShare.isHideFileDownload = true
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked)
publicShare.isHideFileDownload = false
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked)
// password protection
publicShare.isPasswordProtected = true
publicShare.shareWith = "someValue"
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_password_title)
)
publicShare.isPasswordProtected = false
publicShare.shareWith = ""
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_no_password_title)
)
// expires
publicShare.expirationDate = 1582019340
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_share_expiration_date).title
.startsWith(targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])
)
publicShare.expirationDate = 0
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_share_expiration_date).title ==
targetContext.getString(R.string.share_no_expiration_date_label)
)
}
@Test
@Suppress("MagicNumber")
// public link and email are handled the same way
fun publicLinkOptionMenuFile() {
val sut = FileDetailSharingFragment.newInstance(file, user)
activity.addFragment(sut)
shortSleep()
sut.refreshCapabilitiesFromDB()
val overflowMenuShareLink = ImageView(targetContext)
val popup = PopupMenu(targetContext, overflowMenuShareLink)
popup.inflate(R.menu.fragment_file_detail_sharing_public_link)
val publicShare = OCShare().apply {
isFolder = false
shareType = ShareType.PUBLIC_LINK
permissions = 17
}
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
// check if items are visible
assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isVisible)
assertTrue(popup.menu.findItem(R.id.action_password).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_expiration_date).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_send_link).isVisible)
assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible)
assertTrue(popup.menu.findItem(R.id.action_edit_label).isVisible)
assertTrue(popup.menu.findItem(R.id.action_unshare).isVisible)
assertTrue(popup.menu.findItem(R.id.action_add_another_public_share_link).isVisible)
assertFalse(popup.menu.findItem(R.id.link_share_read_only).isVisible)
assertFalse(popup.menu.findItem(R.id.link_share_allow_upload_and_editing).isVisible)
assertFalse(popup.menu.findItem(R.id.link_share_file_drop).isVisible)
assertTrue(popup.menu.findItem(R.id.allow_editing).isVisible)
// password protection
publicShare.shareWith = "someValue"
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_password_title)
)
publicShare.shareWith = ""
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_password).title == targetContext.getString(R.string.share_no_password_title)
)
// hide download
publicShare.isHideFileDownload = true
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(popup.menu.findItem(R.id.action_hide_file_download).isChecked)
publicShare.isHideFileDownload = false
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertFalse(popup.menu.findItem(R.id.action_hide_file_download).isChecked)
// expiration date
publicShare.expirationDate = 1582019340000
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_share_expiration_date).title
.startsWith(targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])
)
publicShare.expirationDate = 0
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(
popup.menu.findItem(R.id.action_share_expiration_date).title ==
targetContext.getString(R.string.share_no_expiration_date_label)
)
publicShare.isFolder = false
publicShare.permissions = READ_PERMISSION_FLAG
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
// allow editing
publicShare.permissions = 17 // from server
assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked)
publicShare.permissions = 19 // from server
sut.prepareLinkOptionsMenu(popup.menu, publicShare)
assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked)
}
@Test
@Suppress("MagicNumber")
// also applies for
// group
// conversation
// circle
// federated share
fun userOptionMenuFile() {
val sut = FileDetailSharingFragment.newInstance(file, user)
activity.addFragment(sut)
shortSleep()
sut.refreshCapabilitiesFromDB()
val overflowMenuShareLink = ImageView(targetContext)
val popup = PopupMenu(targetContext, overflowMenuShareLink)
popup.inflate(R.menu.item_user_sharing_settings)
val userShare = OCShare().apply {
isFolder = false
shareType = ShareType.USER
permissions = 17
}
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertFalse(popup.menu.findItem(R.id.allow_creating).isVisible)
assertFalse(popup.menu.findItem(R.id.allow_deleting).isVisible)
// allow editing
userShare.permissions = 17 // from server
assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked)
userShare.permissions = 19 // from server
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked)
// allow reshare
userShare.permissions = 1 // from server
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertFalse(popup.menu.findItem(R.id.allow_resharing).isChecked)
userShare.permissions = 17 // from server
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(popup.menu.findItem(R.id.allow_resharing).isChecked)
// set expiration date
userShare.expirationDate = 1582019340000
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(
popup.menu.findItem(R.id.action_expiration_date).title
.startsWith(targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])
)
userShare.expirationDate = 0
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(
popup.menu.findItem(R.id.action_expiration_date).title ==
targetContext.getString(R.string.share_no_expiration_date_label)
)
// note
assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible)
}
@Test
@Suppress("MagicNumber")
// also applies for
// group
// conversation
// circle
// federated share
fun userOptionMenuFolder() {
val sut = FileDetailSharingFragment.newInstance(file, user)
activity.addFragment(sut)
shortSleep()
sut.refreshCapabilitiesFromDB()
val overflowMenuShareLink = ImageView(targetContext)
val popup = PopupMenu(targetContext, overflowMenuShareLink)
popup.inflate(R.menu.item_user_sharing_settings)
val userShare = OCShare().apply {
isFolder = true
shareType = ShareType.USER
permissions = 17
}
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(popup.menu.findItem(R.id.allow_creating).isVisible)
assertTrue(popup.menu.findItem(R.id.allow_deleting).isVisible)
// allow editing
userShare.permissions = 17 // from server
assertFalse(popup.menu.findItem(R.id.allow_editing).isChecked)
userShare.permissions = 19 // from server
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(popup.menu.findItem(R.id.allow_editing).isChecked)
// allow reshare
userShare.permissions = 1 // from server
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertFalse(popup.menu.findItem(R.id.allow_resharing).isChecked)
userShare.permissions = 17 // from server
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(popup.menu.findItem(R.id.allow_resharing).isChecked)
// set expiration date
userShare.expirationDate = 1582019340000
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(
popup.menu.findItem(R.id.action_expiration_date).title
.startsWith(targetContext.getString(R.string.share_expiration_date_label).split(" ")[0])
)
userShare.expirationDate = 0
sut.prepareUserOptionsMenu(popup.menu, userShare)
assertTrue(
popup.menu.findItem(R.id.action_expiration_date).title ==
targetContext.getString(R.string.share_no_expiration_date_label)
)
// note
assertTrue(popup.menu.findItem(R.id.action_share_send_note).isVisible)
}
@Test
fun testUploadAndEditingSharePermissions() {
val sut = FileDetailSharingFragment()
val share = OCShare().apply {
permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER
}
assertTrue(sut.isUploadAndEditingAllowed(share))
share.permissions = NO_PERMISSION
assertFalse(sut.isUploadAndEditingAllowed(share))
share.permissions = READ_PERMISSION_FLAG
assertFalse(sut.isUploadAndEditingAllowed(share))
share.permissions = CREATE_PERMISSION_FLAG
assertFalse(sut.isUploadAndEditingAllowed(share))
share.permissions = DELETE_PERMISSION_FLAG
assertFalse(sut.isUploadAndEditingAllowed(share))
share.permissions = SHARE_PERMISSION_FLAG
assertFalse(sut.isUploadAndEditingAllowed(share))
}
@Test
@Suppress("MagicNumber")
fun testReadOnlySharePermissions() {
val sut = FileDetailSharingFragment()
val share = OCShare().apply {
permissions = 17
}
assertTrue(sut.isReadOnly(share))
share.permissions = NO_PERMISSION
assertFalse(sut.isReadOnly(share))
share.permissions = READ_PERMISSION_FLAG
assertTrue(sut.isReadOnly(share))
share.permissions = CREATE_PERMISSION_FLAG
assertFalse(sut.isReadOnly(share))
share.permissions = DELETE_PERMISSION_FLAG
assertFalse(sut.isReadOnly(share))
share.permissions = SHARE_PERMISSION_FLAG
assertFalse(sut.isReadOnly(share))
share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER
assertFalse(sut.isReadOnly(share))
share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE
assertFalse(sut.isReadOnly(share))
}
@Test
@Suppress("MagicNumber")
fun testFileDropSharePermissions() {
val sut = FileDetailSharingFragment()
val share = OCShare().apply {
permissions = 4
}
assertTrue(sut.isFileDrop(share))
share.permissions = NO_PERMISSION
assertFalse(sut.isFileDrop(share))
share.permissions = READ_PERMISSION_FLAG
assertFalse(sut.isFileDrop(share))
share.permissions = CREATE_PERMISSION_FLAG
assertTrue(sut.isFileDrop(share))
share.permissions = DELETE_PERMISSION_FLAG
assertFalse(sut.isFileDrop(share))
share.permissions = SHARE_PERMISSION_FLAG
assertFalse(sut.isFileDrop(share))
share.permissions = MAXIMUM_PERMISSIONS_FOR_FOLDER
assertFalse(sut.isFileDrop(share))
share.permissions = MAXIMUM_PERMISSIONS_FOR_FILE
assertFalse(sut.isFileDrop(share))
}
@After
fun after() {
activity.storageManager.cleanShares()
}
}

View file

@ -68,6 +68,7 @@ import java.util.Set;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
public class FileDataStorageManager { public class FileDataStorageManager {
@ -230,7 +231,6 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, ocFile.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, ocFile.getEtagOnServer());
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, ocFile.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, ocFile.isSharedViaLink() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, ocFile.isSharedWithSharee() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, ocFile.isSharedWithSharee() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, ocFile.getPublicLink());
cv.put(ProviderTableMeta.FILE_PERMISSIONS, ocFile.getPermissions()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, ocFile.getPermissions());
cv.put(ProviderTableMeta.FILE_REMOTE_ID, ocFile.getRemoteId()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, ocFile.getRemoteId());
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, ocFile.isUpdateThumbnailNeeded()); cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, ocFile.isUpdateThumbnailNeeded());
@ -485,7 +485,6 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, folder.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, folder.getEtagOnServer());
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
cv.put(ProviderTableMeta.FILE_FAVORITE, folder.isFavorite()); cv.put(ProviderTableMeta.FILE_FAVORITE, folder.isFavorite());
@ -520,7 +519,6 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded()); cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded());
@ -1006,7 +1004,6 @@ public class FileDataStorageManager {
ocFile.setEtagOnServer(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_ETAG_ON_SERVER))); ocFile.setEtagOnServer(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_ETAG_ON_SERVER)));
ocFile.setSharedViaLink(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1); ocFile.setSharedViaLink(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1);
ocFile.setSharedWithSharee(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_SHARED_WITH_SHAREE)) == 1); ocFile.setSharedWithSharee(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_SHARED_WITH_SHAREE)) == 1);
ocFile.setPublicLink(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
ocFile.setPermissions(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS))); ocFile.setPermissions(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS)));
ocFile.setRemoteId(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID))); ocFile.setRemoteId(cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
ocFile.setUpdateThumbnailNeeded(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1); ocFile.setUpdateThumbnailNeeded(cursor.getInt(cursor.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1);
@ -1296,7 +1293,6 @@ public class FileDataStorageManager {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE);
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE);
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] whereArgs = new String[]{account.name}; String[] whereArgs = new String[]{account.name};
@ -1316,7 +1312,6 @@ public class FileDataStorageManager {
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE); contentValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE);
contentValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE); contentValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE);
contentValues.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PARENT + " = ?"; String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PARENT + " = ?";
String[] whereArgs = new String[]{account.name, String.valueOf(folder.getFileId())}; String[] whereArgs = new String[]{account.name, String.valueOf(folder.getFileId())};
@ -1336,7 +1331,6 @@ public class FileDataStorageManager {
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE); contentValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, Boolean.FALSE);
contentValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE); contentValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, Boolean.FALSE);
contentValues.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + " = ?"; String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + " = ?";
String[] whereArgs = new String[]{account.name, filePath}; String[] whereArgs = new String[]{account.name, filePath};
@ -1352,7 +1346,8 @@ public class FileDataStorageManager {
} }
} }
private void cleanShares() { @VisibleForTesting
public void cleanShares() {
String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"; String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
String[] whereArgs = new String[]{account.name}; String[] whereArgs = new String[]{account.name};
@ -1447,7 +1442,6 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer()); cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite()); cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite());

View file

@ -47,7 +47,8 @@ import third_parties.daveKoeller.AlphanumComparator;
public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterface { public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterface {
private final static String PERMISSION_SHARED_WITH_ME = "S"; private final static String PERMISSION_SHARED_WITH_ME = "S";
private final static String PERMISSION_CAN_RESHARE = "R"; @VisibleForTesting
public final static String PERMISSION_CAN_RESHARE = "R";
private final static String PERMISSION_CAN_WRITE = "CK"; private final static String PERMISSION_CAN_WRITE = "CK";
public static final String PATH_SEPARATOR = "/"; public static final String PATH_SEPARATOR = "/";
@ -75,7 +76,6 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
private String etag; private String etag;
private String etagOnServer; private String etagOnServer;
private boolean sharedViaLink; private boolean sharedViaLink;
private String publicLink;
private String permissions; private String permissions;
private String remoteId; // The fileid namespaced by the instance fileId, globally unique private String remoteId; // The fileid namespaced by the instance fileId, globally unique
private boolean updateThumbnailNeeded; private boolean updateThumbnailNeeded;
@ -150,7 +150,6 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
etag = source.readString(); etag = source.readString();
etagOnServer = source.readString(); etagOnServer = source.readString();
sharedViaLink = source.readInt() == 1; sharedViaLink = source.readInt() == 1;
publicLink = source.readString();
permissions = source.readString(); permissions = source.readString();
remoteId = source.readString(); remoteId = source.readString();
updateThumbnailNeeded = source.readInt() == 1; updateThumbnailNeeded = source.readInt() == 1;
@ -184,7 +183,6 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
dest.writeString(etag); dest.writeString(etag);
dest.writeString(etagOnServer); dest.writeString(etagOnServer);
dest.writeInt(sharedViaLink ? 1 : 0); dest.writeInt(sharedViaLink ? 1 : 0);
dest.writeString(publicLink);
dest.writeString(permissions); dest.writeString(permissions);
dest.writeString(remoteId); dest.writeString(remoteId);
dest.writeInt(updateThumbnailNeeded ? 1 : 0); dest.writeInt(updateThumbnailNeeded ? 1 : 0);
@ -450,7 +448,6 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
etag = null; etag = null;
etagOnServer = null; etagOnServer = null;
sharedViaLink = false; sharedViaLink = false;
publicLink = null;
permissions = null; permissions = null;
remoteId = null; remoteId = null;
updateThumbnailNeeded = false; updateThumbnailNeeded = false;
@ -646,10 +643,6 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
return this.sharedViaLink; return this.sharedViaLink;
} }
public String getPublicLink() {
return this.publicLink;
}
public String getPermissions() { public String getPermissions() {
return this.permissions; return this.permissions;
} }
@ -758,10 +751,6 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
this.sharedViaLink = sharedViaLink; this.sharedViaLink = sharedViaLink;
} }
public void setPublicLink(String publicLink) {
this.publicLink = publicLink;
}
public void setPermissions(String permissions) { public void setPermissions(String permissions) {
this.permissions = permissions; this.permissions = permissions;
} }

View file

@ -102,7 +102,6 @@ public class ProviderMeta {
public static final String FILE_ETAG_ON_SERVER = "etag_on_server"; public static final String FILE_ETAG_ON_SERVER = "etag_on_server";
public static final String FILE_SHARED_VIA_LINK = "share_by_link"; public static final String FILE_SHARED_VIA_LINK = "share_by_link";
public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users"; public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users";
public static final String FILE_PUBLIC_LINK = "public_link";
public static final String FILE_PERMISSIONS = "permissions"; public static final String FILE_PERMISSIONS = "permissions";
public static final String FILE_REMOTE_ID = "remote_id"; public static final String FILE_REMOTE_ID = "remote_id";
public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail"; public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail";
@ -137,7 +136,6 @@ public class ProviderMeta {
FILE_ETAG_ON_SERVER, FILE_ETAG_ON_SERVER,
FILE_SHARED_VIA_LINK, FILE_SHARED_VIA_LINK,
FILE_SHARED_WITH_SHAREE, FILE_SHARED_WITH_SHAREE,
FILE_PUBLIC_LINK,
FILE_PERMISSIONS, FILE_PERMISSIONS,
FILE_REMOTE_ID, FILE_REMOTE_ID,
FILE_UPDATE_THUMBNAIL, FILE_UPDATE_THUMBNAIL,

View file

@ -426,7 +426,7 @@ public class FileUploader extends Service
createdBy, createdBy,
file, file,
disableRetries disableRetries
); );
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
@ -455,7 +455,7 @@ public class FileUploader extends Service
int createdBy, int createdBy,
OCFile file, OCFile file,
boolean disableRetries boolean disableRetries
) { ) {
OCUpload ocUpload = new OCUpload(file, user.toPlatformAccount()); OCUpload ocUpload = new OCUpload(file, user.toPlatformAccount());
ocUpload.setFileSize(file.getFileLength()); ocUpload.setFileSize(file.getFileLength());
ocUpload.setNameCollisionPolicy(nameCollisionPolicy); ocUpload.setNameCollisionPolicy(nameCollisionPolicy);
@ -975,7 +975,7 @@ public class FileUploader extends Service
OCFile existingFile, OCFile existingFile,
Integer behaviour, Integer behaviour,
NameCollisionPolicy nameCollisionPolicy NameCollisionPolicy nameCollisionPolicy
) { ) {
uploadUpdateFile(context, account, new OCFile[]{existingFile}, behaviour, nameCollisionPolicy, true); uploadUpdateFile(context, account, new OCFile[]{existingFile}, behaviour, nameCollisionPolicy, true);
} }
@ -989,7 +989,7 @@ public class FileUploader extends Service
Integer behaviour, Integer behaviour,
NameCollisionPolicy nameCollisionPolicy, NameCollisionPolicy nameCollisionPolicy,
boolean disableRetries boolean disableRetries
) { ) {
uploadUpdateFile(context, account, new OCFile[]{existingFile}, behaviour, nameCollisionPolicy, disableRetries); uploadUpdateFile(context, account, new OCFile[]{existingFile}, behaviour, nameCollisionPolicy, disableRetries);
} }
@ -1003,7 +1003,7 @@ public class FileUploader extends Service
Integer behaviour, Integer behaviour,
NameCollisionPolicy nameCollisionPolicy, NameCollisionPolicy nameCollisionPolicy,
boolean disableRetries boolean disableRetries
) { ) {
Intent intent = new Intent(context, FileUploader.class); Intent intent = new Intent(context, FileUploader.class);
intent.putExtra(FileUploader.KEY_ACCOUNT, account); intent.putExtra(FileUploader.KEY_ACCOUNT, account);

View file

@ -52,7 +52,7 @@ public class CreateShareViaLinkOperation extends SyncOperation {
"", "",
false, false,
password, password,
OCShare.DEFAULT_PERMISSION); OCShare.NO_PERMISSION);
createOp.setGetShareDetails(true); createOp.setGetShareDetails(true);
RemoteOperationResult result = createOp.execute(client); RemoteOperationResult result = createOp.execute(client);
@ -88,7 +88,6 @@ public class CreateShareViaLinkOperation extends SyncOperation {
// Update OCFile with data from share: ShareByLink and publicLink // Update OCFile with data from share: ShareByLink and publicLink
OCFile file = getStorageManager().getFileByEncryptedRemotePath(path); OCFile file = getStorageManager().getFileByEncryptedRemotePath(path);
if (file != null) { if (file != null) {
file.setPublicLink(share.getShareLink());
file.setSharedViaLink(true); file.setSharedViaLink(true);
getStorageManager().saveFile(file); getStorageManager().saveFile(file);
} }

View file

@ -576,7 +576,6 @@ public class RefreshFolderOperation extends RemoteOperation {
Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server"); Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
} }
updatedFile.setPublicLink(localFile.getPublicLink());
updatedFile.setSharedViaLink(localFile.isSharedViaLink()); updatedFile.setSharedViaLink(localFile.isSharedViaLink());
updatedFile.setSharedWithSharee(localFile.isSharedWithSharee()); updatedFile.setSharedWithSharee(localFile.isSharedWithSharee());
} else { } else {

View file

@ -360,7 +360,6 @@ public class SynchronizeFolderOperation extends SyncOperation {
updatedFile.setUpdateThumbnailNeeded(true); updatedFile.setUpdateThumbnailNeeded(true);
Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server"); Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
} }
updatedFile.setPublicLink(localFile.getPublicLink());
updatedFile.setSharedViaLink(localFile.isSharedViaLink()); updatedFile.setSharedViaLink(localFile.isSharedViaLink());
updatedFile.setSharedWithSharee(localFile.isSharedWithSharee()); updatedFile.setSharedWithSharee(localFile.isSharedWithSharee());
updatedFile.setEtagInConflict(localFile.getEtagInConflict()); updatedFile.setEtagInConflict(localFile.getEtagInConflict());

View file

@ -68,7 +68,6 @@ public class UnshareOperation extends SyncOperation {
if (ShareType.PUBLIC_LINK.equals(share.getShareType())) { if (ShareType.PUBLIC_LINK.equals(share.getShareType())) {
file.setSharedViaLink(false); file.setSharedViaLink(false);
file.setPublicLink("");
} else if (ShareType.USER.equals(share.getShareType()) || ShareType.GROUP.equals(share.getShareType()) } else if (ShareType.USER.equals(share.getShareType()) || ShareType.GROUP.equals(share.getShareType())
|| ShareType.FEDERATED.equals(share.getShareType())) { || ShareType.FEDERATED.equals(share.getShareType())) {
// Check if it is the last share // Check if it is the last share

View file

@ -34,10 +34,6 @@ import com.owncloud.android.operations.common.SyncOperation;
*/ */
public class UpdateShareViaLinkOperation extends SyncOperation { public class UpdateShareViaLinkOperation extends SyncOperation {
private String password; private String password;
/**
* Enable upload permissions to update in Share resource.
*/
private boolean publicUpload;
private Boolean hideFileDownload; private Boolean hideFileDownload;
private long expirationDateInMillis; private long expirationDateInMillis;
private long shareId; private long shareId;
@ -58,12 +54,6 @@ public class UpdateShareViaLinkOperation extends SyncOperation {
updateOp.setHideFileDownload(hideFileDownload); updateOp.setHideFileDownload(hideFileDownload);
updateOp.setLabel(label); updateOp.setLabel(label);
if (publicShare.isFolder()) {
updateOp.setPublicUploadOnFolder(publicUpload);
} else {
updateOp.setPublicUploadOnFile(publicUpload);
}
RemoteOperationResult result = updateOp.execute(client); RemoteOperationResult result = updateOp.execute(client);
if (result.isSuccess()) { if (result.isSuccess()) {
@ -87,10 +77,6 @@ public class UpdateShareViaLinkOperation extends SyncOperation {
this.password = password; this.password = password;
} }
public void setPublicUpload(boolean publicUpload) {
this.publicUpload = publicUpload;
}
public void setHideFileDownload(Boolean hideFileDownload) { public void setHideFileDownload(Boolean hideFileDownload) {
this.hideFileDownload = hideFileDownload; this.hideFileDownload = hideFileDownload;
} }

View file

@ -207,8 +207,8 @@ public class UploadFileOperation extends SyncOperation {
} }
if (TextUtils.isEmpty(upload.getLocalPath())) { if (TextUtils.isEmpty(upload.getLocalPath())) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Illegal file in UploadFileOperation; storage path invalid: " "Illegal file in UploadFileOperation; storage path invalid: "
+ upload.getLocalPath()); + upload.getLocalPath());
} }
this.uploadsStorageManager = uploadsStorageManager; this.uploadsStorageManager = uploadsStorageManager;

View file

@ -708,7 +708,6 @@ public class FileContentProvider extends ContentProvider {
+ ProviderTableMeta.FILE_ETAG + TEXT + ProviderTableMeta.FILE_ETAG + TEXT
+ ProviderTableMeta.FILE_ETAG_ON_SERVER + TEXT + ProviderTableMeta.FILE_ETAG_ON_SERVER + TEXT
+ ProviderTableMeta.FILE_SHARED_VIA_LINK + INTEGER + ProviderTableMeta.FILE_SHARED_VIA_LINK + INTEGER
+ ProviderTableMeta.FILE_PUBLIC_LINK + TEXT
+ ProviderTableMeta.FILE_PERMISSIONS + " TEXT null," + ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
+ ProviderTableMeta.FILE_REMOTE_ID + " TEXT null," + ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
+ ProviderTableMeta.FILE_UPDATE_THUMBNAIL + INTEGER //boolean + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + INTEGER //boolean
@ -1148,10 +1147,6 @@ public class FileContentProvider extends ContentProvider {
ADD_COLUMN + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER " + ADD_COLUMN + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER " +
" DEFAULT 0"); " DEFAULT 0");
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
ADD_COLUMN + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " +
" DEFAULT NULL");
// Create table OCShares // Create table OCShares
createOCSharesTable(db); createOCSharesTable(db);

View file

@ -89,12 +89,10 @@ public class OperationsService extends Service {
public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_ACCOUNT = "ACCOUNT";
public static final String EXTRA_SERVER_URL = "SERVER_URL"; public static final String EXTRA_SERVER_URL = "SERVER_URL";
public static final String EXTRA_OAUTH2_QUERY_PARAMETERS = "OAUTH2_QUERY_PARAMETERS";
public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
public static final String EXTRA_NEWNAME = "NEWNAME"; public static final String EXTRA_NEWNAME = "NEWNAME";
public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY"; public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY";
public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS"; public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS";
public static final String EXTRA_RESULT = "RESULT";
public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH"; public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
public static final String EXTRA_FILE = "FILE"; public static final String EXTRA_FILE = "FILE";
public static final String EXTRA_FILE_VERSION = "FILE_VERSION"; public static final String EXTRA_FILE_VERSION = "FILE_VERSION";
@ -103,7 +101,6 @@ public class OperationsService extends Service {
public static final String EXTRA_SHARE_WITH = "SHARE_WITH"; public static final String EXTRA_SHARE_WITH = "SHARE_WITH";
public static final String EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS = "SHARE_EXPIRATION_YEAR"; public static final String EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS = "SHARE_EXPIRATION_YEAR";
public static final String EXTRA_SHARE_PERMISSIONS = "SHARE_PERMISSIONS"; public static final String EXTRA_SHARE_PERMISSIONS = "SHARE_PERMISSIONS";
public static final String EXTRA_SHARE_PUBLIC_UPLOAD = "SHARE_PUBLIC_UPLOAD";
public static final String EXTRA_SHARE_PUBLIC_LABEL = "SHARE_PUBLIC_LABEL"; public static final String EXTRA_SHARE_PUBLIC_LABEL = "SHARE_PUBLIC_LABEL";
public static final String EXTRA_SHARE_HIDE_FILE_DOWNLOAD = "HIDE_FILE_DOWNLOAD"; public static final String EXTRA_SHARE_HIDE_FILE_DOWNLOAD = "HIDE_FILE_DOWNLOAD";
public static final String EXTRA_SHARE_ID = "SHARE_ID"; public static final String EXTRA_SHARE_ID = "SHARE_ID";
@ -384,9 +381,7 @@ public class OperationsService extends Service {
* Created with the Looper of a new thread, started in {@link OperationsService#onCreate()}. * Created with the Looper of a new thread, started in {@link OperationsService#onCreate()}.
*/ */
private static class ServiceHandler extends Handler { private static class ServiceHandler extends Handler {
// don't make it a final class, and don't remove the static ; lint will warn about a p // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
// ossible memory leak
OperationsService mService; OperationsService mService;
@ -428,7 +423,7 @@ public class OperationsService extends Service {
if (next != null) { if (next != null) {
mCurrentOperation = next.second; mCurrentOperation = next.second;
RemoteOperationResult result = null; RemoteOperationResult result;
try { try {
/// prepare client object to send the request to the ownCloud server /// prepare client object to send the request to the ownCloud server
if (mLastTarget == null || !mLastTarget.equals(next.first)) { if (mLastTarget == null || !mLastTarget.equals(next.first)) {
@ -553,9 +548,9 @@ public class OperationsService extends Service {
false); false);
updateLinkOperation.setHideFileDownload(hideFileDownload); updateLinkOperation.setHideFileDownload(hideFileDownload);
if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_UPLOAD)) { // if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_UPLOAD)) {
updateLinkOperation.setPublicUpload(true); // updateLinkOperation.setPublicUpload(true);
} // }
if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_LABEL)) { if (operationIntent.hasExtra(EXTRA_SHARE_PUBLIC_LABEL)) {
updateLinkOperation.setLabel(operationIntent.getStringExtra(EXTRA_SHARE_PUBLIC_LABEL)); updateLinkOperation.setLabel(operationIntent.getStringExtra(EXTRA_SHARE_PUBLIC_LABEL));
@ -698,7 +693,7 @@ public class OperationsService extends Service {
} }
if (operation != null) { if (operation != null) {
return new Pair<Target, RemoteOperation>(target, operation); return new Pair<>(target, operation);
} else { } else {
return null; return null;
} }

View file

@ -746,7 +746,6 @@ public abstract class FileActivity extends DrawerActivity
if (result.isSuccess()) { if (result.isSuccess()) {
if (sharingFragment != null) { if (sharingFragment != null) {
sharingFragment.refreshPublicShareFromDB();
sharingFragment.onUpdateShareInformation(result, getFile()); sharingFragment.onUpdateShareInformation(result, getFile());
} }
} else { } else {
@ -761,7 +760,6 @@ public abstract class FileActivity extends DrawerActivity
if (result.isSuccess()) { if (result.isSuccess()) {
updateFileFromDB(); updateFileFromDB();
if (sharingFragment != null) { if (sharingFragment != null) {
sharingFragment.refreshPublicShareFromDB();
sharingFragment.onUpdateShareInformation(result, getFile()); sharingFragment.onUpdateShareInformation(result, getFile());
} }
} else if (sharingFragment != null && sharingFragment.getView() != null) { } else if (sharingFragment != null && sharingFragment.getView() != null) {
@ -807,7 +805,6 @@ public abstract class FileActivity extends DrawerActivity
copyAndShareFileLink(this, file, link); copyAndShareFileLink(this, file, link);
if (sharingFragment != null) { if (sharingFragment != null) {
sharingFragment.refreshPublicShareFromDB();
sharingFragment.onUpdateShareInformation(result, getFile()); sharingFragment.onUpdateShareInformation(result, getFile());
} }
} else { } else {
@ -828,7 +825,7 @@ public abstract class FileActivity extends DrawerActivity
} else { } else {
if (sharingFragment != null) { if (sharingFragment != null) {
sharingFragment.refreshPublicShareFromDB(); sharingFragment.refreshSharesFromDB();
} }
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
ErrorMessageAdapter.getErrorCauseMessage(result, ErrorMessageAdapter.getErrorCauseMessage(result,
@ -899,8 +896,8 @@ public abstract class FileActivity extends DrawerActivity
if (getFile().isSharedWithMe()) { if (getFile().isSharedWithMe()) {
return OCShare.READ_PERMISSION_FLAG; // minimum permissions return OCShare.READ_PERMISSION_FLAG; // minimum permissions
} else if (ShareType.FEDERATED.equals(shareType)) { } else if (ShareType.FEDERATED.equals(shareType)) {
return getFile().isFolder() ? OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9 : return getFile().isFolder() ? OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER :
OCShare.FEDERATED_PERMISSIONS_FOR_FILE_AFTER_OC9; OCShare.FEDERATED_PERMISSIONS_FOR_FILE;
} else { } else {
return getFile().isFolder() ? OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER : return getFile().isFolder() ? OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER :
OCShare.MAXIMUM_PERMISSIONS_FOR_FILE; OCShare.MAXIMUM_PERMISSIONS_FOR_FILE;

View file

@ -145,8 +145,7 @@ public class ShareActivity extends FileActivity {
if (shareFileFragment != null if (shareFileFragment != null
&& shareFileFragment.isAdded()) { // only if added to the view hierarchy!! && shareFileFragment.isAdded()) { // only if added to the view hierarchy!!
shareFileFragment.refreshCapabilitiesFromDB(); shareFileFragment.refreshCapabilitiesFromDB();
//shareFileFragment.refrefreshUsersOrGroupsListFromDB(); shareFileFragment.refreshSharesFromDB();
shareFileFragment.refreshPublicShareFromDB();
} }
} }

View file

@ -0,0 +1,74 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.graphics.PorterDuff;
import android.view.View;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsShareInternalShareLinkBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.recyclerview.widget.RecyclerView;
class InternalShareViewHolder extends RecyclerView.ViewHolder {
private FileDetailsShareInternalShareLinkBinding binding;
private Context context;
public InternalShareViewHolder(@NonNull View itemView) {
super(itemView);
}
public InternalShareViewHolder(FileDetailsShareInternalShareLinkBinding binding, Context context) {
this(binding.getRoot());
this.binding = binding;
this.context = context;
}
public void bind(OCShare share, ShareeListAdapterListener listener) {
binding.copyInternalLinkIcon
.getBackground()
.setColorFilter(ResourcesCompat.getColor(context.getResources(),
R.color.grey_db,
null),
PorterDuff.Mode.SRC_IN);
binding.copyInternalLinkIcon
.getDrawable()
.mutate()
.setColorFilter(ResourcesCompat.getColor(context.getResources(),
R.color.black,
null),
PorterDuff.Mode.SRC_IN);
if (share.isFolder()) {
binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_folder_text));
} else {
binding.shareInternalLinkText.setText(context.getString(R.string.share_internal_link_to_file_text));
}
binding.copyInternalContainer.setOnClickListener(l -> listener.copyInternalLink());
}
}

View file

@ -0,0 +1,74 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.utils.ThemeUtils;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.recyclerview.widget.RecyclerView;
class LinkShareViewHolder extends RecyclerView.ViewHolder {
private FileDetailsShareLinkShareItemBinding binding;
private Context context;
public LinkShareViewHolder(@NonNull View itemView) {
super(itemView);
}
public LinkShareViewHolder(FileDetailsShareLinkShareItemBinding binding, Context context) {
this(binding.getRoot());
this.binding = binding;
this.context = context;
}
public void bind(OCShare publicShare, ShareeListAdapterListener listener) {
if (ShareType.EMAIL == publicShare.getShareType()) {
binding.name.setText(publicShare.getSharedWithDisplayName());
binding.icon.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
R.drawable.ic_email,
null));
binding.copyLink.setVisibility(View.GONE);
} 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 {
binding.name.setText(R.string.share_link);
}
}
ThemeUtils.colorIconImageViewWithBackground(binding.icon, context);
binding.copyLink.setOnClickListener(v -> listener.copyLink(publicShare));
binding.overflowMenu.setOnClickListener(v -> listener.showLinkOverflowMenu(publicShare, binding.overflowMenu));
}
}

View file

@ -22,41 +22,26 @@
package com.owncloud.android.ui.adapter; package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding; import com.owncloud.android.databinding.FileDetailsSharePublicLinkAddNewItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.utils.ThemeUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
class PublicShareViewHolder extends RecyclerView.ViewHolder { class NewLinkShareViewHolder extends RecyclerView.ViewHolder {
private FileDetailsSharePublicLinkItemBinding binding; private FileDetailsSharePublicLinkAddNewItemBinding binding;
private Context context;
public PublicShareViewHolder(@NonNull View itemView) { public NewLinkShareViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
} }
public PublicShareViewHolder(FileDetailsSharePublicLinkItemBinding binding, Context context) { public NewLinkShareViewHolder(FileDetailsSharePublicLinkAddNewItemBinding binding) {
this(binding.getRoot()); this(binding.getRoot());
this.binding = binding; this.binding = binding;
this.context = context;
} }
public void bind(OCShare publicShare, PublicShareInterface listener) { public void bind(ShareeListAdapterListener listener) {
if (!TextUtils.isEmpty(publicShare.getLabel())) { binding.addNewPublicShareLink.setOnClickListener(v -> listener.createPublicShareLink());
binding.publicShareLabel.setText(publicShare.getLabel());
}
ThemeUtils.colorIconImageViewWithBackground(binding.copyInternalLinkIcon, context);
binding.shareLinkCopyIcon.setOnClickListener(v -> listener.copyLink(publicShare));
binding.overflowMenuShareLink.setOnClickListener(
v -> listener.showLinkOverflowMenu(publicShare, binding.overflowMenuShareLink));
} }
} }

View file

@ -1,68 +0,0 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.owncloud.android.databinding.FileDetailsSharePublicLinkItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class PublicShareListAdapter extends RecyclerView.Adapter<PublicShareViewHolder> {
private Context context;
private List<OCShare> shares;
private PublicShareInterface listener;
public PublicShareListAdapter(Context context, List<OCShare> shares, PublicShareInterface listener) {
this.context = context;
this.shares = shares;
this.listener = listener;
}
@NonNull
@Override
public PublicShareViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
FileDetailsSharePublicLinkItemBinding binding =
FileDetailsSharePublicLinkItemBinding.inflate(LayoutInflater.from(context), parent, false);
return new PublicShareViewHolder(binding, context);
}
@Override
public void onBindViewHolder(@NonNull PublicShareViewHolder holder, int position) {
OCShare share = shares.get(position);
holder.bind(share, listener);
}
@Override
public int getItemCount() {
return shares.size();
}
}

View file

@ -0,0 +1,102 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsShareShareItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.ui.TextDrawable;
import java.security.NoSuchAlgorithmException;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
class ShareViewHolder extends RecyclerView.ViewHolder {
private FileDetailsShareShareItemBinding binding;
private float avatarRadiusDimension;
private Context context;
public ShareViewHolder(@NonNull View itemView) {
super(itemView);
}
public ShareViewHolder(FileDetailsShareShareItemBinding binding, Context context) {
this(binding.getRoot());
this.binding = binding;
this.context = context;
}
public void bind(OCShare share,
ShareeListAdapterListener listener,
String userId,
float avatarRadiusDimension) {
this.avatarRadiusDimension = avatarRadiusDimension;
String name = share.getSharedWithDisplayName();
switch (share.getShareType()) {
case GROUP:
name = context.getString(R.string.share_group_clarification, name);
setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_group);
break;
case ROOM:
name = context.getString(R.string.share_room_clarification, name);
setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_chat_bubble);
break;
case CIRCLE:
binding.icon.setImageResource(R.drawable.ic_circles);
break;
case FEDERATED:
name = context.getString(R.string.share_remote_clarification, name);
setImage(binding.icon, share.getSharedWithDisplayName(), R.drawable.ic_user);
break;
default:
setImage(binding.icon, name, R.drawable.ic_user);
break;
}
binding.name.setText(name);
if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
binding.overflowMenu.setVisibility(View.VISIBLE);
// bind listener to edit privileges
binding.overflowMenu.setOnClickListener(v -> listener.showUserOverflowMenu(share, binding.overflowMenu));
} else {
binding.overflowMenu.setVisibility(View.GONE);
}
}
private void setImage(ImageView avatar, String name, @DrawableRes int fallback) {
try {
avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension));
} catch (NoSuchAlgorithmException | StringIndexOutOfBoundsException e) {
avatar.setImageResource(fallback);
}
}
}

View file

@ -25,132 +25,108 @@
package com.owncloud.android.ui.adapter; package com.owncloud.android.ui.adapter;
import android.accounts.Account;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.databinding.FileDetailsShareInternalShareLinkBinding;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding;
import com.owncloud.android.databinding.FileDetailsSharePublicLinkAddNewItemBinding;
import com.owncloud.android.databinding.FileDetailsShareShareItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.TextDrawable;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.ui.dialog.NoteDialogFragment;
import com.owncloud.android.ui.fragment.util.SharingMenuHelper;
import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ThemeUtils;
import java.security.NoSuchAlgorithmException; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
/** /**
* Adapter to show a user/group/email/remote in Sharing list in file details view. * Adapter to show a user/group/email/remote in Sharing list in file details view.
*/ */
public class ShareeListAdapter extends RecyclerView.Adapter<ShareeListAdapter.UserViewHolder> public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements DisplayUtils.AvatarGenerationListener { implements DisplayUtils.AvatarGenerationListener {
private ShareeListAdapterListener listener; private ShareeListAdapterListener listener;
private OCCapability capabilities;
private FragmentManager fragmentManager;
private Context context; private Context context;
private int accentColor;
private List<OCShare> shares; private List<OCShare> shares;
private float avatarRadiusDimension; private float avatarRadiusDimension;
private OCFile file;
private String userId; private String userId;
public ShareeListAdapter(FragmentManager fragmentManager, Context context, List<OCShare> shares, Account account, public ShareeListAdapter(Context context,
OCFile file, ShareeListAdapterListener listener, String userId) { List<OCShare> shares,
ShareeListAdapterListener listener,
String userId) {
this.context = context; this.context = context;
this.fragmentManager = fragmentManager;
this.shares = shares; this.shares = shares;
this.listener = listener; this.listener = listener;
this.file = file;
this.userId = userId; this.userId = userId;
accentColor = ThemeUtils.primaryAccentColor(context);
capabilities = new FileDataStorageManager(account, context.getContentResolver()).getCapability(account.name);
avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius); avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius);
sortShares();
}
@Override
public int getItemViewType(int position) {
return shares.get(position).getShareType().getValue();
} }
@NonNull @NonNull
@Override @Override
public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.file_details_share_user_item, parent, false); switch (ShareType.fromValue(viewType)) {
return new UserViewHolder(v); case PUBLIC_LINK:
} case EMAIL:
return new LinkShareViewHolder(
@Override FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(context),
public void onBindViewHolder(@NonNull UserViewHolder holder, int position) { parent,
if (shares != null && shares.size() > position) { false),
final OCShare share = shares.get(position); context);
case NEW_PUBLIC_LINK:
String name = share.getSharedWithDisplayName(); return new NewLinkShareViewHolder(
FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(context),
switch (share.getShareType()) { parent,
case GROUP: false)
name = context.getString(R.string.share_group_clarification, name); );
setImage(holder, name, R.drawable.ic_group); case INTERNAL:
break; return new InternalShareViewHolder(
case EMAIL: FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(context), parent, false),
name = context.getString(R.string.share_email_clarification, name); context);
setImage(holder, name, R.drawable.ic_email); default:
break; return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(context),
case ROOM: parent,
name = context.getString(R.string.share_room_clarification, name); false),
setImage(holder, name, R.drawable.ic_chat_bubble); context);
break;
case CIRCLE:
holder.avatar.setImageResource(R.drawable.ic_circles);
break;
default:
setImage(holder, name, R.drawable.ic_user);
break;
}
holder.name.setText(name);
if (share.getShareWith().equalsIgnoreCase(userId) || share.getUserId().equalsIgnoreCase(userId)) {
holder.allowEditing.setVisibility(View.VISIBLE);
holder.editShareButton.setVisibility(View.VISIBLE);
ThemeUtils.tintCheckbox(holder.allowEditing, accentColor);
holder.allowEditing.setChecked(canEdit(share));
holder.allowEditing.setOnClickListener(v -> allowEditClick(holder.allowEditing, share));
// bind listener to edit privileges
holder.editShareButton.setOnClickListener(v -> onOverflowIconClicked(v, holder.allowEditing, share));
} else {
holder.allowEditing.setVisibility(View.GONE);
holder.editShareButton.setVisibility(View.GONE);
}
} }
} }
private void setImage(UserViewHolder holder, String name, @DrawableRes int fallback) { @Override
try { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
holder.avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension)); if (shares == null || shares.size() <= position) {
} catch (NoSuchAlgorithmException e) { return;
holder.avatar.setImageResource(fallback); }
final OCShare share = shares.get(position);
if (holder instanceof LinkShareViewHolder) {
LinkShareViewHolder publicShareViewHolder = (LinkShareViewHolder) holder;
publicShareViewHolder.bind(share, listener);
} else if (holder instanceof InternalShareViewHolder) {
InternalShareViewHolder internalShareViewHolder = (InternalShareViewHolder) holder;
internalShareViewHolder.bind(share, listener);
} else if (holder instanceof NewLinkShareViewHolder) {
NewLinkShareViewHolder newLinkShareViewHolder = (NewLinkShareViewHolder) holder;
newLinkShareViewHolder.bind(listener);
} else {
ShareViewHolder userViewHolder = (ShareViewHolder) holder;
userViewHolder.bind(share, listener, userId, avatarRadiusDimension);
} }
} }
@ -164,204 +140,10 @@ public class ShareeListAdapter extends RecyclerView.Adapter<ShareeListAdapter.Us
return shares.size(); return shares.size();
} }
private void allowEditClick(AppCompatCheckBox checkBox, @NonNull OCShare share) { public void addShares(List<OCShare> sharesToAdd) {
if (!share.isFolder()) { shares.addAll(sharesToAdd);
share.setPermissions(listener.updatePermissionsToShare( sortShares();
share, notifyDataSetChanged();
canReshare(share),
checkBox.isChecked(),
false,
false,
false
));
} else {
share.setPermissions(listener.updatePermissionsToShare(
share,
canReshare(share),
checkBox.isChecked(),
checkBox.isChecked(),
checkBox.isChecked(),
checkBox.isChecked()
));
}
}
private void onOverflowIconClicked(View view, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
// use grey as fallback for elements where custom theming is not available
if (ThemeUtils.themingEnabled(context)) {
context.getTheme().applyStyle(R.style.FallbackThemingTheme, true);
}
PopupMenu popup = new PopupMenu(context, view);
popup.inflate(R.menu.item_user_sharing_settings);
prepareOptionsMenu(popup.getMenu(), share);
popup.setOnMenuItemClickListener(item -> optionsItemSelected(popup.getMenu(), item, allowEditsCheckBox, share));
popup.show();
}
/**
* Updates the sharee's menu with the current permissions of the {@link OCShare}
*
* @param menu the menu of the sharee/shared file
* @param share the shared file
*/
private void prepareOptionsMenu(Menu menu, OCShare share) {
MenuItem editCreateItem = menu.findItem(R.id.action_can_edit_create);
MenuItem editChangeItem = menu.findItem(R.id.action_can_edit_change);
MenuItem editDeleteItem = menu.findItem(R.id.action_can_edit_delete);
MenuItem hideFileListingItem = menu.findItem(R.id.action_hide_file_listing);
MenuItem passwordItem = menu.findItem(R.id.action_password);
MenuItem expirationDateItem = menu.findItem(R.id.action_expiration_date);
MenuItem reshareItem = menu.findItem(R.id.action_can_reshare);
MenuItem sendNoteItem = menu.findItem(R.id.action_share_send_note);
if (isReshareForbidden(share)) {
reshareItem.setVisible(false);
}
reshareItem.setChecked(canReshare(share));
if (share.getShareType() == ShareType.EMAIL) {
SharingMenuHelper.setupHideFileListingMenuItem(
hideFileListingItem,
file.isFolder(),
canEdit(share),
share.getPermissions()
);
SharingMenuHelper.setupPasswordMenuItem(passwordItem, share.isPasswordProtected());
reshareItem.setVisible(false);
editCreateItem.setVisible(false);
editChangeItem.setVisible(false);
editDeleteItem.setVisible(false);
} else {
if (file.isFolder() && isEditOptionsAvailable(share)) {
/// TODO change areEditOptionsAvailable in order to delete !isFederated
editCreateItem.setChecked(canCreate(share));
editChangeItem.setChecked(canUpdate(share));
editDeleteItem.setChecked(canDelete(share));
} else {
editCreateItem.setVisible(false);
editChangeItem.setVisible(false);
editDeleteItem.setVisible(false);
}
hideFileListingItem.setVisible(false);
passwordItem.setVisible(false);
if (!capabilities.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_18)) {
expirationDateItem.setVisible(false);
}
}
SharingMenuHelper.setupExpirationDateMenuItem(
menu.findItem(R.id.action_expiration_date), share.getExpirationDate(), context.getResources());
sendNoteItem.setVisible(capabilities.getVersion().isNoteOnShareSupported());
}
private boolean isEditOptionsAvailable(OCShare share) {
return !ShareType.FEDERATED.equals(share.getShareType());
}
private boolean isReshareForbidden(OCShare share) {
return ShareType.FEDERATED.equals(share.getShareType()) ||
(capabilities != null && capabilities.getFilesSharingResharing().isFalse());
}
private boolean canEdit(OCShare share) {
return (share.getPermissions() &
(OCShare.CREATE_PERMISSION_FLAG | OCShare.UPDATE_PERMISSION_FLAG | OCShare.DELETE_PERMISSION_FLAG)) > 0;
}
private boolean canCreate(OCShare share) {
return (share.getPermissions() & OCShare.CREATE_PERMISSION_FLAG) > 0;
}
private boolean canUpdate(OCShare share) {
return (share.getPermissions() & OCShare.UPDATE_PERMISSION_FLAG) > 0;
}
private boolean canDelete(OCShare share) {
return (share.getPermissions() & OCShare.DELETE_PERMISSION_FLAG) > 0;
}
private boolean canReshare(OCShare share) {
return (share.getPermissions() & OCShare.SHARE_PERMISSION_FLAG) > 0;
}
private boolean optionsItemSelected(Menu menu, MenuItem item, AppCompatCheckBox allowEditsCheckBox, OCShare share) {
switch (item.getItemId()) {
case R.id.action_can_edit_create:
case R.id.action_can_edit_change:
case R.id.action_can_edit_delete: {
item.setChecked(!item.isChecked());
if (item.isChecked() && !allowEditsCheckBox.isChecked()) {
allowEditsCheckBox.setChecked(true);
}
share.setPermissions(
updatePermissionsToShare(
share,
menu.findItem(R.id.action_can_reshare).isChecked(),
allowEditsCheckBox.isChecked(),
menu.findItem(R.id.action_can_edit_create).isChecked(),
menu.findItem(R.id.action_can_edit_change).isChecked(),
menu.findItem(R.id.action_can_edit_delete).isChecked())
);
return true;
}
case R.id.action_can_reshare: {
item.setChecked(!item.isChecked());
share.setPermissions(
updatePermissionsToShare(
share,
menu.findItem(R.id.action_can_reshare).isChecked(),
allowEditsCheckBox.isChecked(),
menu.findItem(R.id.action_can_edit_create).isChecked(),
menu.findItem(R.id.action_can_edit_change).isChecked(),
menu.findItem(R.id.action_can_edit_delete).isChecked())
);
return true;
}
case R.id.action_unshare: {
listener.unshareWith(share);
shares.remove(share);
notifyDataSetChanged();
return true;
}
case R.id.action_password: {
listener.requestPasswordForShare(share, false);
return true;
}
case R.id.action_expiration_date: {
ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment
.newInstance(share, share.getExpirationDate());
dialog.show(fragmentManager, ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG);
return true;
}
case R.id.action_share_send_note:
NoteDialogFragment dialog = NoteDialogFragment.newInstance(share);
dialog.show(fragmentManager, NoteDialogFragment.NOTE_FRAGMENT);
return true;
default:
return true;
}
}
private int updatePermissionsToShare(OCShare share, boolean canReshare, boolean canEdit, boolean canEditCreate,
boolean canEditChange, boolean canEditDelete) {
return listener.updatePermissionsToShare(
share,
canReshare,
canEdit,
canEditCreate,
canEditChange,
canEditDelete
);
} }
@Override @Override
@ -381,53 +163,46 @@ public class ShareeListAdapter extends RecyclerView.Adapter<ShareeListAdapter.Us
return false; return false;
} }
class UserViewHolder extends RecyclerView.ViewHolder { public void remove(OCShare share) {
@BindView(R.id.avatar) shares.remove(share);
ImageView avatar; notifyDataSetChanged();
@BindView(R.id.name) }
TextView name;
@BindView(R.id.allowEditing)
AppCompatCheckBox allowEditing;
@BindView(R.id.editShareButton)
ImageView editShareButton;
UserViewHolder(View itemView) { /**
super(itemView); * sort all by creation time, then email/link shares on top
ButterKnife.bind(this, itemView); */
protected final void sortShares() {
List<OCShare> links = new ArrayList<>();
List<OCShare> users = new ArrayList<>();
for (OCShare share : shares) {
if (ShareType.PUBLIC_LINK == share.getShareType() || ShareType.EMAIL == share.getShareType()) {
links.add(share);
} else if (share.getShareType() != ShareType.INTERNAL) {
users.add(share);
}
}
Collections.sort(links, (o1, o2) -> Long.compare(o2.getSharedDate(), o1.getSharedDate()));
Collections.sort(users, (o1, o2) -> Long.compare(o2.getSharedDate(), o1.getSharedDate()));
shares = links;
shares.addAll(users);
// add internal share link at end
shares.add(new OCShare().setShareType(ShareType.INTERNAL));
}
public List<OCShare> getShares() {
return shares;
}
public void removeNewPublicShare() {
for (OCShare share : shares) {
if (share.getShareType() == ShareType.NEW_PUBLIC_LINK) {
shares.remove(share);
break;
}
} }
} }
public interface ShareeListAdapterListener {
/**
* unshare with given sharee {@link OCShare}.
*
* @param share the share
*/
void unshareWith(OCShare share);
/**
* Updates the permissions of the {@link OCShare}.
*
* @param share the share to be updated
* @param canReshare reshare permission
* @param canEdit edit permission
* @param canEditCreate create permission (folders only)
* @param canEditChange change permission (folders only)
* @param canEditDelete delete permission (folders only)
* @return permissions value set
*/
int updatePermissionsToShare(OCShare share,
boolean canReshare,
boolean canEdit,
boolean canEditCreate,
boolean canEditChange,
boolean canEditDelete);
/**
* Starts a dialog that requests a password to the user to protect a share.
*
* @param share the share for which a password shall be configured/removed
*/
void requestPasswordForShare(OCShare share, boolean askForPassword);
}
} }

View file

@ -26,8 +26,16 @@ import android.widget.ImageView;
import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.OCShare;
public interface PublicShareInterface { public interface ShareeListAdapterListener {
void copyLink(OCShare share); void copyLink(OCShare share);
void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink); void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink);
void showUserOverflowMenu(OCShare share, ImageView overflowMenu);
void copyInternalLink();
void createPublicShareLink();
void requestPasswordForShare(OCShare share, boolean askForPassword);
} }

View file

@ -716,7 +716,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
/** /**
* Load upload items from {@link UploadsStorageManager}. * Load upload items from {@link UploadsStorageManager}.
*/ */
public void loadUploadItemsFromDb() { public final void loadUploadItemsFromDb() {
Log_OC.d(TAG, "loadUploadItemsFromDb"); Log_OC.d(TAG, "loadUploadItemsFromDb");
for (UploadGroup group : uploadGroups) { for (UploadGroup group : uploadGroups) {

View file

@ -27,13 +27,12 @@ import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.databinding.PasswordDialogBinding;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileActivity;
@ -41,7 +40,6 @@ import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ThemeUtils; import com.owncloud.android.utils.ThemeUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
@ -58,6 +56,7 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
private static final String ARG_ASK_FOR_PASSWORD = "ASK_FOR_PASSWORD"; private static final String ARG_ASK_FOR_PASSWORD = "ASK_FOR_PASSWORD";
public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT"; public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT";
private PasswordDialogBinding binding;
private OCFile file; private OCFile file;
private OCShare share; private OCShare share;
private boolean createShare; private boolean createShare;
@ -122,12 +121,6 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
return frag; return frag;
} }
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
@ -137,17 +130,18 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
askForPassword = getArguments().getBoolean(ARG_ASK_FOR_PASSWORD, false); askForPassword = getArguments().getBoolean(ARG_ASK_FOR_PASSWORD, false);
// Inflate the layout for the dialog // Inflate the layout for the dialog
LayoutInflater inflater = getActivity().getLayoutInflater(); LayoutInflater inflater = requireActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.password_dialog, null); binding = PasswordDialogBinding.inflate(inflater, null, false);
View view = binding.getRoot();
// Setup layout // Setup layout
EditText inputText = v.findViewById(R.id.share_password); EditText inputText = binding.sharePassword;
inputText.getBackground().setColorFilter( inputText.setHighlightColor(ThemeUtils.primaryColor(getActivity()));
ThemeUtils.primaryAccentColor(getContext()),
PorterDuff.Mode.SRC_ATOP
);
inputText.setText(""); inputText.setText("");
ThemeUtils.themeEditText(getContext(), inputText, false);
inputText.requestFocus(); inputText.requestFocus();
inputText.getBackground().setColorFilter(ThemeUtils.primaryAccentColor(getContext()),
PorterDuff.Mode.SRC_ATOP);
int title; int title;
if (askForPassword) { if (askForPassword) {
@ -157,10 +151,9 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
} }
// Build the dialog // Build the dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
R.style.Theme_ownCloud_Dialog_NoButtonBarStyle);
builder.setView(v) builder.setView(view)
.setPositiveButton(R.string.common_ok, this) .setPositiveButton(R.string.common_ok, this)
.setNegativeButton(R.string.common_cancel, this) .setNegativeButton(R.string.common_cancel, this)
.setNeutralButton(R.string.common_delete, this) .setNeutralButton(R.string.common_delete, this)
@ -178,11 +171,10 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) { if (which == AlertDialog.BUTTON_POSITIVE) {
String password = ((TextView) (getDialog().findViewById(R.id.share_password))).getText().toString(); String password = binding.sharePassword.getText().toString();
if (!askForPassword && TextUtils.isEmpty(password)) { if (!askForPassword && TextUtils.isEmpty(password)) {
DisplayUtils.showSnackMessage(getActivity().findViewById(android.R.id.content), DisplayUtils.showSnackMessage(binding.getRoot(), R.string.share_link_empty_password);
R.string.share_link_empty_password);
return; return;
} }
@ -217,4 +209,10 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo
private void setPassword(OCShare share, String password) { private void setPassword(OCShare share, String password) {
((FileActivity) getActivity()).getFileOperationsHelper().setPasswordToShare(share, password); ((FileActivity) getActivity()).getFileOperationsHelper().setPasswordToShare(share, password);
} }
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
} }

View file

@ -27,7 +27,6 @@ import android.accounts.AccountManager;
import android.app.SearchManager; import android.app.SearchManager;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.text.InputType; import android.text.InputType;
@ -38,13 +37,12 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.nextcloud.client.account.User; import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.di.Injectable; import com.nextcloud.client.di.Injectable;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsSharingFragmentBinding;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudAccount;
@ -53,11 +51,11 @@ import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder; import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder;
import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.adapter.PublicShareInterface;
import com.owncloud.android.ui.adapter.PublicShareListAdapter;
import com.owncloud.android.ui.adapter.ShareeListAdapter; import com.owncloud.android.ui.adapter.ShareeListAdapter;
import com.owncloud.android.ui.adapter.ShareeListAdapterListener;
import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration; import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment; import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.ui.dialog.NoteDialogFragment; import com.owncloud.android.ui.dialog.NoteDialogFragment;
@ -70,25 +68,29 @@ import com.owncloud.android.utils.ClipboardUtil;
import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ThemeUtils; import com.owncloud.android.utils.ThemeUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
public class FileDetailSharingFragment extends Fragment implements ShareeListAdapter.ShareeListAdapterListener, import static com.owncloud.android.lib.resources.shares.OCShare.CREATE_PERMISSION_FLAG;
import static com.owncloud.android.lib.resources.shares.OCShare.DELETE_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;
import static com.owncloud.android.lib.resources.shares.OCShare.UPDATE_PERMISSION_FLAG;
public class FileDetailSharingFragment extends Fragment implements ShareeListAdapterListener,
DisplayUtils.AvatarGenerationListener, DisplayUtils.AvatarGenerationListener,
PublicShareInterface,
Injectable { Injectable {
private static final String ARG_FILE = "FILE"; private static final String ARG_FILE = "FILE";
@ -103,40 +105,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
private FileActivity fileActivity; private FileActivity fileActivity;
private FileDataStorageManager fileDataStorageManager; private FileDataStorageManager fileDataStorageManager;
private Unbinder unbinder; private FileDetailsSharingFragmentBinding binding;
@BindView(R.id.searchView)
SearchView searchView;
@BindView(R.id.shareUsersList)
RecyclerView usersList;
@BindView(R.id.publicShareList)
RecyclerView publicShareList;
@BindView(R.id.new_public_share)
View addPublicShare;
@BindView(R.id.shared_with_you_container)
LinearLayout sharedWithYouContainer;
@BindView(R.id.shared_with_you_avatar)
ImageView sharedWithYouAvatar;
@BindView(R.id.shared_with_you_username)
TextView sharedWithYouUsername;
@BindView(R.id.shared_with_you_note_container)
View sharedWithYouNoteContainer;
@BindView(R.id.shared_with_you_note)
TextView sharedWithYouNote;
@BindView(R.id.copy_internal_link_icon)
ImageView internalLinkIcon;
@BindView(R.id.shareInternalLinkText)
TextView internalLinkText;
@Inject UserAccountManager accountManager; @Inject UserAccountManager accountManager;
@ -184,38 +153,37 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
refreshCapabilitiesFromDB(); refreshCapabilitiesFromDB();
refreshPublicShareFromDB(); refreshSharesFromDB();
} }
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.file_details_sharing_fragment, container, false); binding = FileDetailsSharingFragmentBinding.inflate(inflater, container, false);
unbinder = ButterKnife.bind(this, view); View view = binding.getRoot();
fileOperationsHelper = fileActivity.getFileOperationsHelper(); fileOperationsHelper = fileActivity.getFileOperationsHelper();
fileDataStorageManager = fileActivity.getStorageManager(); fileDataStorageManager = fileActivity.getStorageManager();
AccountManager accountManager = AccountManager.get(getContext());
String userId = accountManager.getUserData(user.toPlatformAccount(),
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
binding.sharesList.setAdapter(new ShareeListAdapter(fileActivity,
new ArrayList<>(),
this,
userId));
binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext()));
binding.sharesList.addItemDecoration(new SimpleListItemDividerDecoration(getContext()));
setupView(); setupView();
// todo extract
internalLinkIcon.getBackground().setColorFilter(getResources().getColor(R.color.grey_db),
PorterDuff.Mode.SRC_IN);
internalLinkIcon.getDrawable().mutate().setColorFilter(getResources().getColor(R.color.black),
PorterDuff.Mode.SRC_IN);
if (file.isFolder()) {
internalLinkText.setText(getString(R.string.share_internal_link_to_folder_text));
} else {
internalLinkText.setText(getString(R.string.share_internal_link_to_file_text));
}
return view; return view;
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
unbinder.unbind(); binding = null;
} }
@Override @Override
@ -230,16 +198,17 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
setShareWithYou(); setShareWithYou();
FileDetailSharingFragmentHelper.setupSearchView( FileDetailSharingFragmentHelper.setupSearchView(
(SearchManager) fileActivity.getSystemService(Context.SEARCH_SERVICE), searchView, (SearchManager) fileActivity.getSystemService(Context.SEARCH_SERVICE),
binding.searchView,
fileActivity.getComponentName()); fileActivity.getComponentName());
ThemeUtils.themeSearchView(searchView, requireContext()); ThemeUtils.themeSearchView(binding.searchView, requireContext());
if (file.canReshare()) { if (file.canReshare()) {
setShareWithUserInfo(); binding.searchView.setQueryHint(getResources().getString(R.string.share_search));
} else { } else {
searchView.setQueryHint(getResources().getString(R.string.reshare_not_allowed)); binding.searchView.setQueryHint(getResources().getString(R.string.reshare_not_allowed));
searchView.setInputType(InputType.TYPE_NULL); binding.searchView.setInputType(InputType.TYPE_NULL);
disableSearchView(searchView); disableSearchView(binding.searchView);
} }
} }
@ -257,52 +226,32 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
private void setShareWithYou() { private void setShareWithYou() {
if (accountManager.userOwnsFile(file, user)) { if (accountManager.userOwnsFile(file, user)) {
sharedWithYouContainer.setVisibility(View.GONE); binding.sharedWithYouContainer.setVisibility(View.GONE);
} else { } else {
sharedWithYouUsername.setText( binding.sharedWithYouUsername.setText(
String.format(getString(R.string.shared_with_you_by), file.getOwnerDisplayName())); String.format(getString(R.string.shared_with_you_by), file.getOwnerDisplayName()));
DisplayUtils.setAvatar(user, file.getOwnerId(), this, getResources().getDimension( DisplayUtils.setAvatar(user,
R.dimen.file_list_item_avatar_icon_radius), getResources(), sharedWithYouAvatar, file.getOwnerId(),
getContext()); this,
sharedWithYouAvatar.setVisibility(View.VISIBLE); getResources().getDimension(
R.dimen.file_list_item_avatar_icon_radius),
getResources(),
binding.sharedWithYouAvatar,
getContext());
binding.sharedWithYouAvatar.setVisibility(View.VISIBLE);
String note = file.getNote(); String note = file.getNote();
if (!TextUtils.isEmpty(note)) { if (!TextUtils.isEmpty(note)) {
sharedWithYouNote.setText(file.getNote()); binding.sharedWithYouNote.setText(file.getNote());
sharedWithYouNoteContainer.setVisibility(View.VISIBLE); binding.sharedWithYouNoteContainer.setVisibility(View.VISIBLE);
} else { } else {
sharedWithYouNoteContainer.setVisibility(View.GONE); binding.sharedWithYouNoteContainer.setVisibility(View.GONE);
} }
} }
} }
private void setShareWithUserInfo() { @Override
// TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed
// to show share with users/groups info
List<OCShare> shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(),
user.toPlatformAccount().name);
if (shares.size() > 0) {
AccountManager accountManager = AccountManager.get(getContext());
String userId = accountManager.getUserData(user.toPlatformAccount(),
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
usersList.setVisibility(View.VISIBLE);
usersList.setAdapter(new ShareeListAdapter(fileActivity.getSupportFragmentManager(),
fileActivity,
shares,
user.toPlatformAccount(),
file,
this,
userId));
usersList.setLayoutManager(new LinearLayoutManager(getContext()));
usersList.addItemDecoration(new SimpleListItemDividerDecoration(getContext()));
} else {
usersList.setVisibility(View.GONE);
}
}
@OnClick(R.id.copy_internal_container)
public void copyInternalLink() { public void copyInternalLink() {
OwnCloudAccount account = accountManager.getCurrentOwnCloudAccount(); OwnCloudAccount account = accountManager.getCurrentOwnCloudAccount();
@ -318,7 +267,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
return account.getBaseUri() + "/index.php/f/" + file.getLocalId(); return account.getBaseUri() + "/index.php/f/" + file.getLocalId();
} }
private void createShareLink() { @Override
public void createPublicShareLink() {
if (capabilities != null && (capabilities.getFilesSharingPublicPasswordEnforced().isTrue() || if (capabilities != null && (capabilities.getFilesSharingPublicPasswordEnforced().isTrue() ||
capabilities.getFilesSharingPublicAskForOptionalPassword().isTrue())) { capabilities.getFilesSharingPublicAskForOptionalPassword().isTrue())) {
// password enforced by server, request to the user before trying to create // password enforced by server, request to the user before trying to create
@ -331,26 +281,80 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
} }
} }
private void showSendLinkTo() { private void showSendLinkTo(OCShare publicShare) {
if (file.isSharedViaLink()) { if (file.isSharedViaLink()) {
if (TextUtils.isEmpty(file.getPublicLink())) { if (TextUtils.isEmpty(publicShare.getShareLink())) {
fileOperationsHelper.getFileWithLink(file); fileOperationsHelper.getFileWithLink(file);
} else { } else {
FileDisplayActivity.showShareLinkDialog(fileActivity, file, file.getPublicLink()); FileDisplayActivity.showShareLinkDialog(fileActivity, file, publicShare.getShareLink());
} }
} }
} }
public void copyLink(OCShare share) { public void copyLink(OCShare share) {
if (file.isSharedViaLink()) { if (file.isSharedViaLink()) {
if (TextUtils.isEmpty(file.getPublicLink())) { if (TextUtils.isEmpty(share.getShareLink())) {
fileOperationsHelper.getFileWithLink(file); fileOperationsHelper.getFileWithLink(file);
} else { } else {
ClipboardUtil.copyToClipboard(getActivity(), file.getPublicLink()); ClipboardUtil.copyToClipboard(getActivity(), share.getShareLink());
} }
} }
} }
@Override
public void showUserOverflowMenu(OCShare share, ImageView overflowMenu) {
// use grey as fallback for elements where custom theming is not available
if (ThemeUtils.themingEnabled(requireContext())) {
requireContext().getTheme().applyStyle(R.style.FallbackThemingTheme, true);
}
PopupMenu popup = new PopupMenu(requireContext(), overflowMenu);
popup.inflate(R.menu.item_user_sharing_settings);
prepareUserOptionsMenu(popup.getMenu(), share);
popup.setOnMenuItemClickListener(item -> userOptionsItemSelected(popup.getMenu(), item, share));
popup.show();
}
/**
* Updates the sharee's menu with the current permissions of the {@link OCShare}
*
* @param menu the menu of the sharee/shared file
* @param share the shared file
*/
@VisibleForTesting
public void prepareUserOptionsMenu(Menu menu, OCShare share) {
MenuItem allowEditingItem = menu.findItem(R.id.allow_editing);
MenuItem allowCreatingItem = menu.findItem(R.id.allow_creating);
MenuItem allowDeletingItem = menu.findItem(R.id.allow_deleting);
MenuItem expirationDateItem = menu.findItem(R.id.action_expiration_date);
MenuItem reshareItem = menu.findItem(R.id.allow_resharing);
MenuItem sendNoteItem = menu.findItem(R.id.action_share_send_note);
allowEditingItem.setChecked(canEdit(share));
if (isReshareForbidden(share)) {
reshareItem.setVisible(false);
}
reshareItem.setChecked(canReshare(share));
if (file.isFolder() || share.isFolder()) {
allowCreatingItem.setChecked(canCreate(share));
allowDeletingItem.setChecked(canDelete(share));
} else {
allowCreatingItem.setVisible(false);
allowDeletingItem.setVisible(false);
}
if (!capabilities.getVersion().isNewerOrEqual(OwnCloudVersion.nextcloud_18)) {
expirationDateItem.setVisible(false);
}
SharingMenuHelper.setupExpirationDateMenuItem(menu.findItem(R.id.action_expiration_date),
share.getExpirationDate(),
getResources());
sendNoteItem.setVisible(capabilities.getVersion().isNoteOnShareSupported());
}
public void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink) { public void showLinkOverflowMenu(OCShare publicShare, ImageView overflowMenuShareLink) {
if (ThemeUtils.themingEnabled(requireContext())) { if (ThemeUtils.themingEnabled(requireContext())) {
// use grey as fallback for elements where custom theming is not available // use grey as fallback for elements where custom theming is not available
@ -358,21 +362,45 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
} }
PopupMenu popup = new PopupMenu(requireContext(), overflowMenuShareLink); PopupMenu popup = new PopupMenu(requireContext(), overflowMenuShareLink);
popup.inflate(R.menu.fragment_file_detail_sharing_link); if (ShareType.EMAIL == publicShare.getShareType()) {
prepareOptionsMenu(popup.getMenu(), publicShare); popup.inflate(R.menu.fragment_file_detail_sharing_email_link);
popup.setOnMenuItemClickListener(menuItem -> optionsItemSelected(menuItem, publicShare)); } else {
popup.inflate(R.menu.fragment_file_detail_sharing_public_link);
}
prepareLinkOptionsMenu(popup.getMenu(), publicShare);
popup.setOnMenuItemClickListener(menuItem -> linkOptionsItemSelected(menuItem, publicShare));
popup.show(); popup.show();
} }
private void prepareOptionsMenu(Menu menu, OCShare publicShare) { @VisibleForTesting
Resources res = requireContext().getResources(); public void prepareLinkOptionsMenu(Menu menu, OCShare publicShare) {
SharingMenuHelper.setupHideFileListingMenuItem(menu.findItem(R.id.action_hide_file_listing), if (publicShare.isFolder()) {
file.isFolder(), menu.setGroupVisible(R.id.folder_permission, true);
menu.findItem(R.id.action_allow_editing).isChecked(), menu.findItem(R.id.allow_editing).setVisible(false);
publicShare.getPermissions());
// read only / allow upload and editing / file drop
if (isUploadAndEditingAllowed(publicShare)) {
menu.findItem(R.id.link_share_allow_upload_and_editing).setChecked(true);
} else if (isFileDrop(publicShare)) {
menu.findItem(R.id.link_share_file_drop).setChecked(true);
} else if (isReadOnly(publicShare)) {
menu.findItem(R.id.link_share_read_only).setChecked(true);
}
} else {
menu.setGroupVisible(R.id.folder_permission, false);
menu.findItem(R.id.allow_editing).setVisible(true);
if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) {
menu.findItem(R.id.allow_editing).setChecked(true);
} else {
menu.findItem(R.id.allow_editing).setChecked(false);
}
}
Resources res = requireContext().getResources();
SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download), SharingMenuHelper.setupHideFileDownload(menu.findItem(R.id.action_hide_file_download),
publicShare.isHideFileDownload(), publicShare.isHideFileDownload(),
isFileDrop(publicShare),
capabilities); capabilities);
SharingMenuHelper.setupPasswordMenuItem(menu.findItem(R.id.action_password), SharingMenuHelper.setupPasswordMenuItem(menu.findItem(R.id.action_password),
@ -383,36 +411,104 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
res); res);
menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported()); menu.findItem(R.id.action_share_send_note).setVisible(capabilities.getVersion().isNoteOnShareSupported());
}
if (publicShare.getPermissions() > PERMISSION_EDITING_ALLOWED) { @VisibleForTesting
menu.findItem(R.id.action_allow_editing).setChecked(true); public boolean isUploadAndEditingAllowed(OCShare share) {
} else { if (share.getPermissions() == NO_PERMISSION) {
menu.findItem(R.id.action_allow_editing).setChecked(false); return false;
}
return (share.getPermissions() & MAXIMUM_PERMISSIONS_FOR_FOLDER) == MAXIMUM_PERMISSIONS_FOR_FOLDER;
}
@VisibleForTesting
public boolean isReadOnly(OCShare share) {
if (share.getPermissions() == NO_PERMISSION) {
return false;
}
return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == READ_PERMISSION_FLAG;
}
@VisibleForTesting
public boolean isFileDrop(OCShare share) {
if (share.getPermissions() == NO_PERMISSION) {
return false;
}
return (share.getPermissions() & ~SHARE_PERMISSION_FLAG) == CREATE_PERMISSION_FLAG;
}
private boolean userOptionsItemSelected(Menu menu, MenuItem item, OCShare share) {
switch (item.getItemId()) {
case R.id.allow_editing:
case R.id.allow_creating:
case R.id.allow_deleting:
case R.id.allow_resharing: {
item.setChecked(!item.isChecked());
share.setPermissions(updatePermissionsToShare(share,
menu.findItem(R.id.allow_resharing).isChecked(),
menu.findItem(R.id.allow_editing).isChecked(),
menu.findItem(R.id.allow_creating).isChecked(),
menu.findItem(R.id.allow_deleting).isChecked()));
return true;
}
case R.id.action_unshare: {
unshareWith(share);
ShareeListAdapter adapter = (ShareeListAdapter) binding.sharesList.getAdapter();
if (adapter == null) {
DisplayUtils.showSnackMessage(getView(), getString(R.string.failed_update_ui));
return true;
}
adapter.remove(share);
return true;
}
case R.id.action_expiration_date: {
ExpirationDatePickerDialogFragment dialog = ExpirationDatePickerDialogFragment
.newInstance(share, share.getExpirationDate());
dialog.show(fileActivity.getSupportFragmentManager(),
ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG);
return true;
}
case R.id.action_share_send_note:
NoteDialogFragment dialog = NoteDialogFragment.newInstance(share);
dialog.show(fileActivity.getSupportFragmentManager(), NoteDialogFragment.NOTE_FRAGMENT);
return true;
default:
return true;
} }
} }
public boolean optionsItemSelected(MenuItem item, OCShare publicShare) { public boolean linkOptionsItemSelected(MenuItem item, OCShare publicShare) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_allow_editing: case R.id.link_share_read_only:
item.setChecked(true);
fileOperationsHelper.setPermissionsToShare(publicShare, READ_PERMISSION_FLAG);
return true;
case R.id.link_share_allow_upload_and_editing:
item.setChecked(true);
if (publicShare.isFolder()) {
fileOperationsHelper.setPermissionsToShare(publicShare, MAXIMUM_PERMISSIONS_FOR_FOLDER);
} else {
fileOperationsHelper.setPermissionsToShare(publicShare, MAXIMUM_PERMISSIONS_FOR_FILE);
}
return true;
case R.id.link_share_file_drop: {
item.setChecked(true);
fileOperationsHelper.setPermissionsToShare(publicShare, CREATE_PERMISSION_FLAG);
return true;
}
case R.id.allow_editing:
if (file.isSharedViaLink()) { if (file.isSharedViaLink()) {
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked()); fileOperationsHelper.setUploadPermissionsToPublicShare(publicShare, item.isChecked());
} }
return true; return true;
case R.id.action_hide_file_listing: {
item.setChecked(!item.isChecked());
fileOperationsHelper.setHideFileListingPermissionsToPublicShare(publicShare, item.isChecked());
return true;
}
case R.id.action_hide_file_download: case R.id.action_hide_file_download:
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
fileOperationsHelper.setHideFileDownloadPermissionsToPublicShare(publicShare, item.isChecked()); fileOperationsHelper.setHideFileDownloadPermissionsToPublicShare(publicShare, item.isChecked());
return true;
case R.id.action_edit_label:
RenamePublicShareDialogFragment renameDialog = RenamePublicShareDialogFragment.newInstance(publicShare);
renameDialog.show(fileActivity.getSupportFragmentManager(),
RenamePublicShareDialogFragment.RENAME_PUBLIC_SHARE_FRAGMENT);
return true; return true;
case R.id.action_password: { case R.id.action_password: {
requestPasswordForShare(publicShare, requestPasswordForShare(publicShare,
@ -427,10 +523,10 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
return true; return true;
} }
case R.id.action_share_send_link: { case R.id.action_share_send_link: {
if (file.isSharedViaLink() && !TextUtils.isEmpty(file.getPublicLink())) { if (file.isSharedViaLink() && !TextUtils.isEmpty(publicShare.getShareLink())) {
FileDisplayActivity.showShareLinkDialog(fileActivity, file, file.getPublicLink()); FileDisplayActivity.showShareLinkDialog(fileActivity, file, publicShare.getShareLink());
} else { } else {
showSendLinkTo(); showSendLinkTo(publicShare);
} }
return true; return true;
} }
@ -438,12 +534,17 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
NoteDialogFragment noteDialog = NoteDialogFragment.newInstance(publicShare); NoteDialogFragment noteDialog = NoteDialogFragment.newInstance(publicShare);
noteDialog.show(fileActivity.getSupportFragmentManager(), NoteDialogFragment.NOTE_FRAGMENT); noteDialog.show(fileActivity.getSupportFragmentManager(), NoteDialogFragment.NOTE_FRAGMENT);
return true; return true;
case R.id.action_add_another_public_share_link: case R.id.action_edit_label:
createShareLink(); RenamePublicShareDialogFragment renameDialog = RenamePublicShareDialogFragment.newInstance(publicShare);
renameDialog.show(fileActivity.getSupportFragmentManager(),
RenamePublicShareDialogFragment.RENAME_PUBLIC_SHARE_FRAGMENT);
return true; return true;
case R.id.action_unshare: case R.id.action_unshare:
fileOperationsHelper.unshareShare(file, publicShare); fileOperationsHelper.unshareShare(file, publicShare);
return true; return true;
case R.id.action_add_another_public_share_link:
createPublicShareLink();
return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -469,28 +570,25 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
* Get {@link OCShare} instance from DB and updates the UI. * Get {@link OCShare} instance from DB and updates the UI.
*/ */
private void refreshUiFromDB() { private void refreshUiFromDB() {
refreshSharesFromDB();
// Updates UI with new state // Updates UI with new state
setupView(); setupView();
} }
@Override private void unshareWith(OCShare share) {
public void unshareWith(OCShare share) {
fileOperationsHelper.unshareShare(file, share); fileOperationsHelper.unshareShare(file, share);
} }
@Override private int updatePermissionsToShare(OCShare share,
public int updatePermissionsToShare(OCShare share, boolean canReshare,
boolean canReshare, boolean canEdit,
boolean canEdit, boolean canEditCreate,
boolean canEditCreate, boolean canEditDelete) {
boolean canEditChange,
boolean canEditDelete) {
SharePermissionsBuilder spb = new SharePermissionsBuilder(); SharePermissionsBuilder spb = new SharePermissionsBuilder();
spb.setSharePermission(canReshare); spb.setSharePermission(canReshare);
if (file.isFolder()) { if (file.isFolder()) {
spb.setUpdatePermission(canEditChange) spb.setCreatePermission(canEditCreate)
.setCreatePermission(canEditCreate)
.setDeletePermission(canEditDelete); .setDeletePermission(canEditDelete);
} else { } else {
spb.setUpdatePermission(canEdit); spb.setUpdatePermission(canEdit);
@ -531,38 +629,51 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
/** /**
* Get public link from the DB to fill in the "Share link" section in the UI. * Get public link from the DB to fill in the "Share link" section in the UI.
*
* Takes into account server capabilities before reading database. * Takes into account server capabilities before reading database.
*/ */
public void refreshPublicShareFromDB() { public void refreshSharesFromDB() {
ShareeListAdapter adapter = (ShareeListAdapter) binding.sharesList.getAdapter();
if (adapter == null) {
DisplayUtils.showSnackMessage(getView(), getString(R.string.could_not_retrieve_shares));
return;
}
adapter.getShares().clear();
// to show share with users/groups info
List<OCShare> shares = fileDataStorageManager.getSharesWithForAFile(file.getRemotePath(),
user.toPlatformAccount().name);
adapter.addShares(shares);
if (FileDetailSharingFragmentHelper.isPublicShareDisabled(capabilities) || !file.canReshare()) { if (FileDetailSharingFragmentHelper.isPublicShareDisabled(capabilities) || !file.canReshare()) {
publicShareList.setVisibility(View.GONE);
return; return;
} }
// Get public share // Get public share
List<OCShare> shares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(), List<OCShare> publicShares = fileDataStorageManager.getSharesByPathAndType(file.getRemotePath(),
ShareType.PUBLIC_LINK, ShareType.PUBLIC_LINK,
""); "");
if (shares.isEmpty()) {
addPublicShare.setVisibility(View.VISIBLE); if (publicShares.isEmpty() && containsNoNewPublicShare(adapter.getShares())) {
publicShareList.setVisibility(View.GONE); publicShares.add(new OCShare().setShareType(ShareType.NEW_PUBLIC_LINK));
ImageView icon = requireView().findViewById(R.id.copy_internal_link_icon);
icon.getBackground().setColorFilter(requireContext()
.getResources()
.getColor(R.color.primary_button_background_color),
PorterDuff.Mode.SRC_IN);
icon.getDrawable().mutate().setColorFilter(requireContext().getResources().getColor(R.color.black),
PorterDuff.Mode.SRC_IN);
requireView().findViewById(R.id.add_new_public_share_link).setOnClickListener(v -> createShareLink());
} else { } else {
addPublicShare.setVisibility(View.GONE); adapter.removeNewPublicShare();
publicShareList.setVisibility(View.VISIBLE);
publicShareList.setAdapter(new PublicShareListAdapter(getContext(), shares, this));
publicShareList.setLayoutManager(new LinearLayoutManager(getContext()));
publicShareList.addItemDecoration(new SimpleListItemDividerDecoration(getContext()));
} }
adapter.addShares(publicShares);
}
private boolean containsNoNewPublicShare(List<OCShare> shares) {
for (OCShare share : shares) {
if (share.getShareType() == ShareType.NEW_PUBLIC_LINK) {
return false;
}
}
return true;
} }
@Override @Override
@ -575,11 +686,33 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
@Override @Override
public void avatarGenerated(Drawable avatarDrawable, Object callContext) { public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
sharedWithYouAvatar.setImageDrawable(avatarDrawable); binding.sharedWithYouAvatar.setImageDrawable(avatarDrawable);
} }
@Override @Override
public boolean shouldCallGeneratedCallback(String tag, Object callContext) { public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
return false; return false;
} }
private boolean isReshareForbidden(OCShare share) {
return ShareType.FEDERATED.equals(share.getShareType()) ||
capabilities != null && capabilities.getFilesSharingResharing().isFalse();
}
private boolean canEdit(OCShare share) {
return (share.getPermissions() &
(CREATE_PERMISSION_FLAG | UPDATE_PERMISSION_FLAG | DELETE_PERMISSION_FLAG)) > 0;
}
private boolean canCreate(OCShare share) {
return (share.getPermissions() & CREATE_PERMISSION_FLAG) > 0;
}
private boolean canDelete(OCShare share) {
return (share.getPermissions() & DELETE_PERMISSION_FLAG) > 0;
}
private boolean canReshare(OCShare share) {
return (share.getPermissions() & SHARE_PERMISSION_FLAG) > 0;
}
} }

View file

@ -65,11 +65,15 @@ public final class SharingMenuHelper {
/** /**
* Sets checked/visibility state on the given {@link MenuItem} based on the given criteria. * Sets checked/visibility state on the given {@link MenuItem} based on the given criteria.
* @param menuItem the {@link MenuItem} to be setup *
* @param menuItem the {@link MenuItem} to be setup
* @param capabilities Capabilities of server to check if hide download is supported * @param capabilities Capabilities of server to check if hide download is supported
*/ */
public static void setupHideFileDownload(MenuItem menuItem, boolean hideFileDownload, OCCapability capabilities) { public static void setupHideFileDownload(MenuItem menuItem,
if (!capabilities.getVersion().isHideFileDownloadSupported()) { boolean hideFileDownload,
boolean isFileDrop,
OCCapability capabilities) {
if (!capabilities.getVersion().isHideFileDownloadSupported() || isFileDrop) {
menuItem.setVisible(false); menuItem.setVisible(false);
} else { } else {
menuItem.setVisible(true); menuItem.setVisible(true);

View file

@ -578,23 +578,6 @@ public class FileOperationsHelper {
fileActivity.startActivity(intent); fileActivity.startActivity(intent);
} }
/**
* Updates a public share on a file to set its password. Starts a request to do it in {@link OperationsService}
*
* @param password Password to set for the public link; null or empty string to clear the current password
*/
public void setPasswordToPublicShare(OCShare share, String password) {
// Set password updating share
Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, (password == null) ? "" : password);
queueShareIntent(updateShareIntent);
}
/** /**
* Updates a public share on a file to set its label. Starts a request to do it in {@link OperationsService} * Updates a public share on a file to set its label. Starts a request to do it in {@link OperationsService}
* *
@ -633,23 +616,6 @@ public class FileOperationsHelper {
} }
/**
* Updates a public share on a file to set its expiration date. Starts a request to do it in {@link
* OperationsService}
*
* @param share {@link OCShare} instance which permissions will be updated.
* @param expirationTimeInMillis Expiration date to set. A negative value clears the current expiration date,
* leaving the link unrestricted. Zero makes no change.
*/
public void setExpirationDateToPublicShare(OCShare share, long expirationTimeInMillis) {
Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DATE_IN_MILLIS, expirationTimeInMillis);
queueShareIntent(updateShareIntent);
}
/** /**
* Updates a public share on a file to set its expiration date. * Updates a public share on a file to set its expiration date.
* Starts a request to do it in {@link OperationsService} * Starts a request to do it in {@link OperationsService}
@ -693,31 +659,13 @@ public class FileOperationsHelper {
*/ */
public void setUploadPermissionsToPublicShare(OCShare share, boolean uploadPermission) { public void setUploadPermissionsToPublicShare(OCShare share, boolean uploadPermission) {
Intent updateShareIntent = new Intent(fileActivity, OperationsService.class); Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE); updateShareIntent.setAction(OperationsService.ACTION_UPDATE_USER_SHARE);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId()); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PUBLIC_UPLOAD, uploadPermission); if (uploadPermission) {
queueShareIntent(updateShareIntent); updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, 3);
}
/**
* Updates a public share on a folder to set its hide file listing permission.
* Starts a request to do it in {@link OperationsService}
*
* @param share {@link OCShare} instance which permissions will be updated.
* @param hideFileListing New state of the permission for editing the folder shared via link.
*/
public void setHideFileListingPermissionsToPublicShare(OCShare share, boolean hideFileListing) {
Intent updateShareIntent = new Intent(fileActivity, OperationsService.class);
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_PUBLIC_SHARE);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_ID, share.getId());
if (hideFileListing) {
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, OCShare.CREATE_PERMISSION_FLAG);
} else { } else {
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_PERMISSIONS, 1);
OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9);
} }
queueShareIntent(updateShareIntent); queueShareIntent(updateShareIntent);

View file

@ -1,23 +0,0 @@
<!--
@author Google LLC
Copyright (C) 2018 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#FFFFFF" android:pathData="M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z" />
</vector>

View file

@ -1,25 +0,0 @@
<!--
Nextcloud Android client application
Copyright (C) 2020 Nextcloud.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
License as published by the Free Software Foundation; either
version 3 of the License, or any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
You should have received a copy of the GNU Affero General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.
Icon provided by Android Material Library in Apache License 2.0
-->
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" 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>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/visible"
android:drawable="@drawable/ic_show"
android:state_checked="true" />
<item android:id="@+id/masked"
android:drawable="@drawable/ic_hide" />
</selector>

View file

@ -23,7 +23,6 @@
android:id="@+id/detail_container" android:id="@+id/detail_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout
@ -184,7 +183,7 @@
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="fill_parent" /> android:layout_height="match_parent" />
<include layout="@layout/empty_list" /> <include layout="@layout/empty_list" />
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?><!--
~
~ Nextcloud Android client application
~
~ @author Tobias Kaminsky
~ Copyright (C) 2020 Tobias Kaminsky
~ Copyright (C) 2020 Nextcloud GmbH
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<LinearLayout android:id="@+id/copy_internal_container"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:paddingBottom="@dimen/standard_half_padding"
android:paddingEnd="@dimen/standard_padding"
android:paddingStart="@dimen/zero"
android:paddingTop="@dimen/standard_half_padding"
android:layout_weight="1"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:background="@drawable/round_bgnd"
android:contentDescription="@string/share"
android:id="@+id/copy_internal_link_icon"
android:layout_gravity="top"
android:layout_height="@dimen/share_icon_size"
android:layout_marginEnd="@dimen/standard_margin"
android:layout_marginStart="@dimen/standard_margin"
android:layout_width="@dimen/share_icon_size"
android:padding="@dimen/standard_half_padding"
android:src="@drawable/ic_external" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_half_margin"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/shareInternalLink"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/share_internal_link"
android:textColor="@color/text_color" />
<TextView
android:id="@+id/shareInternalLinkText"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
tools:text="@string/share_internal_link_to_folder_text" />
</LinearLayout>
</LinearLayout>

View file

@ -25,11 +25,11 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/share_by_link_container" android:id="@+id/share_by_link_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/standard_list_item_size" android:layout_height="@dimen/sharee_list_item_size"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <ImageView
android:id="@+id/copy_internal_link_icon" android:id="@+id/icon"
android:layout_width="@dimen/share_icon_size" android:layout_width="@dimen/share_icon_size"
android:layout_height="@dimen/share_icon_size" android:layout_height="@dimen/share_icon_size"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
@ -41,28 +41,33 @@
android:src="@drawable/shared_via_link" /> android:src="@drawable/shared_via_link" />
<TextView <TextView
android:id="@+id/public_share_label" android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/share_via_link_section_title" />
<ImageView
android:id="@+id/share_link_copy_icon"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:textColor="@color/text_color"
android:ellipsize="end"
android:singleLine="true"
android:layout_weight="1" android:layout_weight="1"
android:gravity="center_vertical"
android:textSize="@dimen/file_details_username_text_size"
android:text="@string/share_via_link_section_title" />
<ImageView
android:id="@+id/copy_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/copy_link" android:contentDescription="@string/copy_link"
android:paddingStart="@dimen/standard_half_margin"
android:paddingTop="@dimen/standard_quarter_margin" android:paddingTop="@dimen/standard_quarter_margin"
android:paddingEnd="@dimen/standard_eighth_margin"
android:paddingBottom="@dimen/standard_quarter_margin" android:paddingBottom="@dimen/standard_quarter_margin"
android:scaleType="fitStart" android:scaleType="fitCenter"
android:paddingStart="@dimen/standard_padding"
android:paddingEnd="@dimen/standard_padding"
android:src="@drawable/ic_content_copy" /> android:src="@drawable/ic_content_copy" />
<ImageView <ImageView
android:id="@+id/overflow_menu_share_link" android:id="@+id/overflow_menu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:contentDescription="@string/overflow_menu" android:contentDescription="@string/overflow_menu"

View file

@ -23,11 +23,10 @@
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/new_public_share" android:id="@+id/add_public_share"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/standard_list_item_size" android:layout_height="@dimen/sharee_list_item_size"
android:orientation="horizontal" android:orientation="horizontal">
android:visibility="gone">
<ImageView <ImageView
android:layout_width="@dimen/share_icon_size" android:layout_width="@dimen/share_icon_size"

View file

@ -20,13 +20,13 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_height="@dimen/sharee_list_item_size"
android:weightSum="1" android:weightSum="1"
tools:ignore="UseCompoundDrawables"> tools:ignore="UseCompoundDrawables">
<ImageView <ImageView
android:id="@+id/avatar" android:id="@+id/icon"
android:layout_width="@dimen/user_icon_size" android:layout_width="@dimen/user_icon_size"
android:layout_height="@dimen/user_icon_size" android:layout_height="@dimen/user_icon_size"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
@ -39,37 +39,25 @@
android:contentDescription="@string/user_icon" android:contentDescription="@string/user_icon"
android:src="@drawable/ic_user" /> android:src="@drawable/ic_user" />
<TextView <TextView
android:id="@+id/name" android:id="@+id/name"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/standard_quarter_margin" android:layout_gravity="center_vertical"
android:layout_weight="1" android:textColor="@color/text_color"
android:ellipsize="end" android:ellipsize="end"
android:gravity="center_vertical" android:singleLine="true"
android:singleLine="true" android:layout_weight="1"
android:text="@string/username" android:gravity="center_vertical"
android:textColor="@color/text_color" android:textSize="@dimen/file_details_username_text_size"
android:textSize="@dimen/file_details_username_text_size" /> android:text="@string/username" />
<androidx.appcompat.widget.AppCompatCheckBox <ImageView
android:id="@+id/allowEditing" android:id="@+id/overflow_menu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_gravity="center_vertical" android:contentDescription="@string/overflow_menu"
android:textSize="16sp" android:paddingStart="@dimen/standard_padding"
android:text="@string/edit_permission_label" /> android:paddingEnd="@dimen/standard_padding"
android:src="@drawable/ic_dots_vertical" />
<ImageView
android:id="@+id/editShareButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/standard_half_margin"
android:layout_marginStart="@dimen/standard_half_margin"
android:layout_marginEnd="@dimen/standard_half_margin"
android:layout_marginRight="@dimen/standard_half_margin"
android:contentDescription="@string/overflow_menu"
android:padding="@dimen/standard_half_padding"
android:src="@drawable/ic_dots_vertical" />
</LinearLayout> </LinearLayout>

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<!--
Nextcloud Android client application Nextcloud Android client application
Copyright (C) 2018 Andy Scherzinger Copyright (C) 2018 Andy Scherzinger
@ -17,147 +16,87 @@
You should have received a copy of the GNU Affero General Public You should have received a copy of the GNU Affero General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>. License along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout android:id="@+id/shareContainer"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1"> android:layout_width="match_parent"
android:orientation="vertical"
android:paddingTop="@dimen/standard_eight_padding"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<androidx.appcompat.widget.SearchView
style="@style/ownCloud.SearchView"
android:hint="@string/share_search"
android:id="@+id/searchView"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/standard_margin"
android:layout_marginStart="@dimen/standard_quarter_margin"
android:layout_width="match_parent" />
<LinearLayout <LinearLayout
android:id="@+id/shareContainer" android:id="@+id/shared_with_you_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:layout_marginBottom="@dimen/standard_half_margin"
android:paddingTop="@dimen/standard_eigth_padding"> android:layout_width="match_parent"
android:orientation="horizontal"
android:paddingLeft="@dimen/standard_padding"
android:paddingRight="@dimen/standard_padding"
android:paddingTop="@dimen/standard_padding">
<androidx.appcompat.widget.SearchView <ImageView
android:id="@+id/searchView" android:contentDescription="@string/avatar"
style="@style/ownCloud.SearchView" android:id="@+id/shared_with_you_avatar"
android:layout_width="match_parent" android:layout_height="@dimen/user_icon_size"
android:layout_height="wrap_content" android:layout_width="@dimen/user_icon_size"
android:layout_marginStart="@dimen/standard_quarter_margin" android:src="@drawable/ic_user" />
android:layout_marginEnd="@dimen/standard_margin"
android:hint="@string/share_search" />
<LinearLayout <LinearLayout
android:id="@+id/shared_with_you_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/standard_half_margin" android:layout_width="match_parent"
android:orientation="horizontal" android:orientation="vertical"
android:paddingLeft="@dimen/standard_padding" android:paddingLeft="@dimen/standard_padding"
android:paddingTop="@dimen/standard_padding" android:paddingRight="@dimen/standard_padding"
android:paddingRight="@dimen/standard_padding"> android:paddingTop="@dimen/standard_half_padding">
<ImageView <TextView
android:id="@+id/shared_with_you_avatar" android:id="@+id/shared_with_you_username"
android:layout_width="@dimen/user_icon_size" android:layout_height="wrap_content"
android:layout_height="@dimen/user_icon_size" android:layout_width="match_parent"
android:contentDescription="@string/avatar" android:text="@string/shared_with_you_by"
android:src="@drawable/ic_user" /> android:textSize="16sp" />
<LinearLayout <LinearLayout
android:id="@+id/shared_with_you_note_container"
android:layout_height="match_parent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:orientation="horizontal"
android:orientation="vertical"
android:paddingLeft="@dimen/standard_padding"
android:paddingTop="@dimen/standard_half_padding" android:paddingTop="@dimen/standard_half_padding"
android:paddingRight="@dimen/standard_padding"> tools:ignore="UseCompoundDrawables">
<ImageView
android:contentDescription="@string/note_icon_hint"
android:layout_height="16dp"
android:layout_width="16dp"
android:src="@drawable/file_text" />
<TextView <TextView
android:id="@+id/shared_with_you_username" android:id="@+id/shared_with_you_note"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/shared_with_you_by" android:layout_weight="1"
android:layout_width="0dp"
android:paddingEnd="@dimen/standard_half_padding"
android:paddingStart="@dimen/standard_half_padding"
android:textSize="16sp" /> android:textSize="16sp" />
<LinearLayout
android:id="@+id/shared_with_you_note_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingTop="@dimen/standard_half_padding"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/file_text"
android:contentDescription="@string/note_icon_hint" />
<TextView
android:id="@+id/shared_with_you_note"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingStart="@dimen/standard_half_padding"
android:paddingEnd="@dimen/standard_half_padding"
android:textSize="16sp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/publicShareList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/divider"
android:dividerHeight="1dp" />
<include layout="@layout/file_details_share_public_link_add_new_item" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/shareUsersList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/divider"
android:dividerHeight="1dp" />
<LinearLayout
android:id="@+id/copy_internal_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/zero"
android:paddingTop="@dimen/standard_half_padding"
android:paddingEnd="@dimen/standard_padding"
android:paddingBottom="@dimen/standard_padding">
<ImageView
android:id="@+id/copy_internal_link_icon"
android:layout_width="@dimen/share_icon_size"
android:layout_height="@dimen/share_icon_size"
android:layout_gravity="top"
android:layout_marginStart="@dimen/standard_margin"
android:layout_marginEnd="@dimen/standard_margin"
android:background="@drawable/round_bgnd"
android:contentDescription="@string/share"
android:padding="@dimen/standard_half_padding"
android:src="@drawable/ic_external" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_half_margin"
android:orientation="vertical">
<TextView
android:id="@+id/shareInternalLink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/share_internal_link"
android:textColor="@color/text_color" />
<TextView
android:id="@+id/shareInternalLinkText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/share_internal_link_to_folder_text" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> <androidx.recyclerview.widget.RecyclerView
android:divider="@drawable/divider"
android:dividerHeight="1dp"
android:id="@+id/sharesList"
android:layout_height="match_parent"
android:layout_width="match_parent" />
</LinearLayout>

View file

@ -18,32 +18,20 @@
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:gravity="clip_horizontal"
android:orientation="vertical"
android:padding="@dimen/standard_padding">
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputEditText
android:id="@+id/share_password"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="@style/TextInputLayout" android:ems="10"
app:hintTextColor="@color/fg_inverse" android:hint="@string/hint_password"
app:passwordToggleDrawable="@drawable/password_visibility_selector" android:inputType="textPassword"
app:boxBackgroundColor="@color/bg_default" android:autofillHints="password"
app:boxStrokeColor="@color/bg_fallback_highlight"> android:textColorHint="@color/bg_fallback_highlight"></com.google.android.material.textfield.TextInputEditText>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/share_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/hint_password"
android:inputType="textPassword"
android:layout_margin="@dimen/standard_margin"
android:autofillHints="password"
android:textColorHint="@color/bg_fallback_highlight">
</com.google.android.material.textfield.TextInputEditText>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout> </LinearLayout>

View file

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
ownCloud Android client application
Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1"
android:longClickable="true">
<ImageView
android:layout_width="@dimen/file_details_user_icon_layout_width"
android:layout_height="@dimen/file_details_user_icon_layout_height"
android:id="@+id/icon"
android:src="@drawable/ic_user"
android:layout_gravity="center_vertical"
android:contentDescription="@string/user_icon"/>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textSize="@dimen/two_line_primary_text_size"
android:text="@string/username"
android:id="@+id/userOrGroupName"
android:layout_marginStart="@dimen/standard_half_margin"
android:textColor="@color/text_color"
android:singleLine="true"
android:ellipsize="middle"
android:gravity="center_vertical"/>
<ImageView
android:layout_width="@dimen/unshare_icon_size"
android:layout_height="@dimen/unshare_icon_size"
android:id="@+id/unshareButton"
android:src="@drawable/ic_action_delete_grey"
android:layout_gravity="center_vertical"
android:padding="@dimen/standard_half_padding"
android:contentDescription="@string/common_delete"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editShareButton"
android:src="@drawable/ic_dots_vertical"
android:padding="@dimen/standard_half_padding"
android:layout_gravity="center_vertical"
android:contentDescription="@string/overflow_menu"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/list_divider_background" />
</LinearLayout>

View file

@ -39,7 +39,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize" android:layout_marginTop="?attr/actionBarSize"
android:background="@color/bg_default" android:background="@color/bg_default"
android:paddingTop="@dimen/standard_eigth_padding" android:paddingTop="@dimen/standard_eight_padding"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?><!--
Nextcloud Android client application
Copyright (C) 2018 Andy Scherzinger
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
License as published by the Free Software Foundation; either
version 3 of the License, or any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
You should have received a copy of the GNU Affero General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource">
<group
android:id="@+id/folder_permission"
android:checkableBehavior="single">
<item
android:id="@+id/link_share_read_only"
android:title="@string/link_share_read_only" />
<item
android:id="@+id/link_share_allow_upload_and_editing"
android:title="@string/link_share_allow_upload_and_editing" />
<item
android:id="@+id/link_share_file_drop"
android:title="@string/link_share_file_drop" />
</group>
<item
android:id="@+id/allow_editing"
android:checkable="true"
android:showAsAction="never"
android:title="@string/allow_editing"
app:showAsAction="never" />
<item
android:id="@+id/action_hide_file_download"
android:checkable="true"
android:showAsAction="never"
android:title="@string/share_via_link_hide_download"
app:showAsAction="never" />
<item
android:id="@+id/action_password"
android:showAsAction="never"
android:title="@string/share_via_link_menu_password_label"
app:showAsAction="never" />
<item
android:id="@+id/action_share_expiration_date"
android:showAsAction="never"
android:title="@string/share_expiration_date_label"
app:showAsAction="never" />
<item
android:id="@+id/action_share_send_note"
android:showAsAction="never"
android:title="@string/share_send_note"
app:showAsAction="never" />
<item
android:id="@+id/action_unshare"
android:showAsAction="never"
android:title="@string/unshare"
app:showAsAction="never" />
</menu>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<!-- Nextcloud Android client application
Nesxtcloud Android client application
Copyright (C) 2018 Andy Scherzinger Copyright (C) 2018 Andy Scherzinger
@ -21,31 +20,30 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource"> tools:ignore="AppCompatResource">
<group
android:id="@+id/folder_permission"
android:checkableBehavior="single">
<item
android:id="@+id/link_share_read_only"
android:title="@string/link_share_read_only" />
<item
android:id="@+id/link_share_allow_upload_and_editing"
android:title="@string/link_share_allow_upload_and_editing" />
<item
android:id="@+id/link_share_file_drop"
android:title="@string/link_share_file_drop" />
</group>
<item <item
android:id="@+id/action_allow_editing" android:id="@+id/allow_editing"
android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/allow_editing" android:title="@string/allow_editing"
android:checkable="true"
android:textSize="16sp"
app:showAsAction="never" />
<item
android:id="@+id/action_hide_file_listing"
android:showAsAction="never"
android:title="@string/share_via_link_hide_file_listing_permission_label"
android:checkable="true"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_hide_file_download" android:id="@+id/action_hide_file_download"
android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_via_link_hide_download" android:title="@string/share_via_link_hide_download"
android:checkable="true"
app:showAsAction="never" />
<item
android:id="@+id/action_edit_label"
android:showAsAction="never"
android:title="@string/edit_label"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_password" android:id="@+id/action_password"
@ -67,6 +65,11 @@
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_send_note" android:title="@string/share_send_note"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_edit_label"
android:showAsAction="never"
android:title="@string/edit_label"
app:showAsAction="never" />
<item <item
android:id="@+id/action_unshare" android:id="@+id/action_unshare"
android:showAsAction="never" android:showAsAction="never"

View file

@ -21,41 +21,30 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource"> tools:ignore="AppCompatResource">
<item
android:id="@+id/allow_editing"
android:checkable="true"
android:showAsAction="never"
android:title="@string/allow_editing"
app:showAsAction="never" />
<item <item
android:id="@+id/action_can_edit_create" android:id="@+id/allow_creating"
android:checkable="true" android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_privilege_can_edit_create" android:title="@string/allow_creating"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_can_edit_change" android:id="@+id/allow_deleting"
android:checkable="true" android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_privilege_can_edit_change" android:title="@string/allow_deleting"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_can_edit_delete" android:id="@+id/allow_resharing"
android:checkable="true" android:checkable="true"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/share_privilege_can_edit_delete" android:title="@string/allow_resharing"
app:showAsAction="never" />
<item
android:id="@+id/action_can_reshare"
android:checkable="true"
android:showAsAction="never"
android:title="@string/share_privilege_can_share"
app:showAsAction="never" />
<item
android:id="@+id/action_hide_file_listing"
android:showAsAction="never"
android:title="@string/share_via_link_hide_file_listing_permission_label"
android:checkable="true"
app:showAsAction="never" />
<item
android:id="@+id/action_password"
android:showAsAction="never"
android:title="@string/share_via_link_menu_password_label"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_expiration_date" android:id="@+id/action_expiration_date"

View file

@ -31,7 +31,7 @@
<dimen name="standard_double_padding">32dp</dimen> <dimen name="standard_double_padding">32dp</dimen>
<dimen name="standard_half_padding">8dp</dimen> <dimen name="standard_half_padding">8dp</dimen>
<dimen name="standard_quarter_padding">4dp</dimen> <dimen name="standard_quarter_padding">4dp</dimen>
<dimen name="standard_eigth_padding">2dp</dimen> <dimen name="standard_eight_padding">2dp</dimen>
<dimen name="standard_margin">16dp</dimen> <dimen name="standard_margin">16dp</dimen>
<dimen name="standard_icon_list_horizontal_margin">24dp</dimen> <dimen name="standard_icon_list_horizontal_margin">24dp</dimen>
<dimen name="standard_double_margin">32dp</dimen> <dimen name="standard_double_margin">32dp</dimen>
@ -40,6 +40,7 @@
<dimen name="standard_eighth_margin">2dp</dimen> <dimen name="standard_eighth_margin">2dp</dimen>
<dimen name="min_list_item_size">56dp</dimen> <dimen name="min_list_item_size">56dp</dimen>
<dimen name="standard_list_item_size">72dp</dimen> <dimen name="standard_list_item_size">72dp</dimen>
<dimen name="sharee_list_item_size">56dp</dimen>
<dimen name="two_line_primary_text_size">16sp</dimen> <dimen name="two_line_primary_text_size">16sp</dimen>
<dimen name="two_line_secondary_text_size">12sp</dimen> <dimen name="two_line_secondary_text_size">12sp</dimen>
<dimen name="list_item_share_right_margin">12dp</dimen> <dimen name="list_item_share_right_margin">12dp</dimen>
@ -71,7 +72,6 @@
<dimen name="search_users_groups_layout_width">200dp</dimen> <dimen name="search_users_groups_layout_width">200dp</dimen>
<dimen name="search_users_groups_layout_list_view_margin">20dp</dimen> <dimen name="search_users_groups_layout_list_view_margin">20dp</dimen>
<dimen name="share_file_layout_text_size">12sp</dimen> <dimen name="share_file_layout_text_size">12sp</dimen>
<dimen name="unshare_icon_size">36dp</dimen>
<dimen name="ssl_untrusted_cert_layout_padding">20dp</dimen> <dimen name="ssl_untrusted_cert_layout_padding">20dp</dimen>
<dimen name="scroll_view_height">180dp</dimen> <dimen name="scroll_view_height">180dp</dimen>
<dimen name="upload_list_item_frame_layout_width">60dp</dimen> <dimen name="upload_list_item_frame_layout_width">60dp</dimen>
@ -102,8 +102,6 @@
<dimen name="empty_list_icon_layout_height">72dp</dimen> <dimen name="empty_list_icon_layout_height">72dp</dimen>
<dimen name="empty_list_progress_layout_width">72dp</dimen> <dimen name="empty_list_progress_layout_width">72dp</dimen>
<dimen name="empty_list_progress_layout_height">72dp</dimen> <dimen name="empty_list_progress_layout_height">72dp</dimen>
<dimen name="file_details_user_icon_layout_width">32dp</dimen>
<dimen name="file_details_user_icon_layout_height">32dp</dimen>
<dimen name="file_details_username_text_size">16sp</dimen> <dimen name="file_details_username_text_size">16sp</dimen>
<dimen name="grid_image_shared_icon_layout_top_margin">24dp</dimen> <dimen name="grid_image_shared_icon_layout_top_margin">24dp</dimen>
<dimen name="grid_image_local_file_indicator_layout_width">16dp</dimen> <dimen name="grid_image_local_file_indicator_layout_width">16dp</dimen>

View file

@ -469,8 +469,6 @@
<string name="share_via_link_send_link_label">Send link</string> <string name="share_via_link_send_link_label">Send link</string>
<string name="share_password_title">Password-protected</string> <string name="share_password_title">Password-protected</string>
<string name="share_no_password_title">Set password</string> <string name="share_no_password_title">Set password</string>
<string name="edit_permission_label">edit</string>
<string name="share_via_link_hide_file_listing_permission_label">Hide file listing</string>
<string name="share_with_title">Share with…</string> <string name="share_with_title">Share with…</string>
<string name="share_via_link_unset_password">Unset</string> <string name="share_via_link_unset_password">Unset</string>
@ -483,10 +481,6 @@
<string name="share_known_remote_clarification">%1$s ( at %2$s )</string> <string name="share_known_remote_clarification">%1$s ( at %2$s )</string>
<string name="share_privilege_unshare">Unshare</string> <string name="share_privilege_unshare">Unshare</string>
<string name="share_privilege_can_share">can share</string>
<string name="share_privilege_can_edit_create">can create</string>
<string name="share_privilege_can_edit_change">can change</string>
<string name="share_privilege_can_edit_delete">can delete</string>
<string name="action_clear_failed_uploads">Clear failed uploads</string> <string name="action_clear_failed_uploads">Clear failed uploads</string>
@ -905,7 +899,6 @@
<string name="failed_to_start_editor">Failed to start editor</string> <string name="failed_to_start_editor">Failed to start editor</string>
<string name="create_rich_workspace">Add folder info</string> <string name="create_rich_workspace">Add folder info</string>
<string name="creates_rich_workspace">creates folder info</string> <string name="creates_rich_workspace">creates folder info</string>
<string name="edit_rich_workspace">edit folder info</string>
<string name="uploader_upload_failed_sync_conflict_error">File upload conflict</string> <string name="uploader_upload_failed_sync_conflict_error">File upload conflict</string>
<string name="uploader_upload_failed_sync_conflict_error_content">Pick which version to keep of %1$s</string> <string name="uploader_upload_failed_sync_conflict_error_content">Pick which version to keep of %1$s</string>
<string name="upload_list_resolve_conflict">Resolve conflict</string> <string name="upload_list_resolve_conflict">Resolve conflict</string>
@ -933,4 +926,14 @@
<string name="add_new_public_share">Add new public share link</string> <string name="add_new_public_share">Add new public share link</string>
<string name="edit_label">Change name</string> <string name="edit_label">Change name</string>
<string name="public_share_name">New name</string> <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_creating">Allow creating</string>
<string name="allow_deleting">Allow deleting</string>
<string name="allow_resharing">Allow resharing</string>
<string name="link_share_read_only">Read only</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>
</resources> </resources>

View file

@ -236,13 +236,6 @@
<item name="colorAccent">@color/color_accent</item> <item name="colorAccent">@color/color_accent</item>
</style> </style>
<style name="Theme.ownCloud.Dialog.NoButtonBarStyle" parent="@style/Theme.MaterialComponents.DayNight.Dialog.Alert">
<item name="windowNoTitle">false</item>
<item name="colorAccent">@color/bg_fallback_highlight</item>
<item name="android:colorBackground">@color/bg_default</item>
<item name="colorControlActivated">@color/bg_fallback_highlight</item>
</style>
<style name="NavigationView_ItemTextAppearance"> <style name="NavigationView_ItemTextAppearance">
<item name="android:ellipsize">end</item> <item name="android:ellipsize">end</item>
<item name="android:listDivider">@color/transparent</item> <item name="android:listDivider">@color/transparent</item>

View file

@ -0,0 +1,101 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.content.res.Resources;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class ShareeListAdapterTest {
@Mock
private Context context;
@Test
public void testSorting() {
MockitoAnnotations.initMocks(this);
Resources resources = Mockito.mock(Resources.class);
Mockito.when(context.getResources()).thenReturn(resources);
List<OCShare> expectedSortOrder = new ArrayList<>();
expectedSortOrder.add(new OCShare("/1")
.setShareType(ShareType.EMAIL)
.setSharedDate(1004));
expectedSortOrder.add(new OCShare("/2")
.setShareType(ShareType.PUBLIC_LINK)
.setSharedDate(1003));
expectedSortOrder.add(new OCShare("/3")
.setShareType(ShareType.PUBLIC_LINK)
.setSharedDate(1001));
expectedSortOrder.add(new OCShare("/4")
.setShareType(ShareType.EMAIL)
.setSharedDate(1000));
expectedSortOrder.add(new OCShare("/5")
.setShareType(ShareType.USER)
.setSharedDate(80));
expectedSortOrder.add(new OCShare("/6")
.setShareType(ShareType.CIRCLE)
.setSharedDate(20));
List<OCShare> randomOrder = new ArrayList<>(expectedSortOrder);
Collections.shuffle(randomOrder);
ShareeListAdapter sut = new ShareeListAdapter(context, randomOrder, null, null);
sut.sortShares();
// compare
boolean compare = true;
for (int i = 0; i < expectedSortOrder.size() && compare; i++) {
compare = expectedSortOrder.get(i) == sut.getShares().get(i);
}
if (!compare) {
System.out.println("Expected:");
for (OCShare item : expectedSortOrder) {
System.out.println(item.getPath() + " " + item.getShareType() + " " + item.getSharedDate());
}
System.out.println();
System.out.println("Actual:");
for (OCShare item : sut.getShares()) {
System.out.println(item.getPath() + " " + item.getShareType() + " " + item.getSharedDate());
}
}
assertTrue(compare);
}
}