Skip to content

Commit

Permalink
Merge pull request #3851 from owncloud/spaces/main
Browse files Browse the repository at this point in the history
[SPACES] Main features
  • Loading branch information
JuancaG05 authored Mar 9, 2023
2 parents c6562a2 + 8b0478c commit 262cb56
Show file tree
Hide file tree
Showing 214 changed files with 6,218 additions and 1,346 deletions.
9 changes: 9 additions & 0 deletions changelog/unreleased/3851
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enhancement: Support for spaces

Spaces are now supported in oCIS accounts. A new tab has been added, which allows to list and
browse through all the available spaces for the current account. The supported operations
for files in spaces are: download, upload, remove, rename, create folder, copy and move. The
documents provider has been adapted as well to be able to browse through spaces and perform
the operations already mentioned.

https://github.com/owncloud/android/pull/3851
9 changes: 9 additions & 0 deletions changelog/unreleased/3945
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enhancement: Authenticated WebFinger

Authenticated WebFinger was introduced into the authentication flow.
Now, WebFinger is used to retrieve the OpenID Connect issuer and the available ownCloud instances.
For the moment, multiple oC instances are not supported, only the first available instance is used.

https://github.com/owncloud/android/issues/3943
https://github.com/owncloud/android/pull/3945
https://doc.owncloud.com/ocis/next/deployment/services/s-list/webfinger.html
7 changes: 7 additions & 0 deletions changelog/unreleased/3949
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Link in drawer menu

Customers will be able now to set a personalized label and link that will
appear in the drawer menu, together with the drawer logo as an icon.

https://github.com/owncloud/android/pull/3949
https://github.com/owncloud/android/issues/3907
2 changes: 1 addition & 1 deletion owncloud-android-library
Submodule owncloud-android-library updated 27 files
+10 −8 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CheckPathExistenceRemoteOperation.kt
+13 −9 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CopyRemoteFileOperation.kt
+5 −4 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CreateRemoteFolderOperation.kt
+4 −3 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/DownloadRemoteFileOperation.kt
+9 −4 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.kt
+15 −5 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.kt
+13 −6 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.kt
+22 −6 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFile.kt
+4 −4 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoveRemoteFileOperation.kt
+3 −2 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.kt
+5 −2 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/UploadFileFromFileSystemOperation.kt
+1 −2 ...mLibrary/src/main/java/com/owncloud/android/lib/resources/files/chunks/RemoveRemoteChunksFolderOperation.kt
+15 −6 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/FileService.kt
+34 −16 ...dComLibrary/src/main/java/com/owncloud/android/lib/resources/files/services/implementation/OCFileService.kt
+99 −0 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/spaces/GetRemoteSpacesOperation.kt
+126 −0 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/spaces/responses/SpacesResponse.kt
+34 −0 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/spaces/services/OCSpacesService.kt
+31 −0 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/spaces/services/SpacesService.kt
+1 −1 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteCapabilitiesOperation.kt
+37 −24 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt
+41 −25 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt
+16 −21 ...dComLibrary/src/main/java/com/owncloud/android/lib/resources/webfinger/GetInstancesViaWebFingerOperation.kt
+2 −2 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/webfinger/responses/WebFingerResponse.kt
+5 −4 owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/webfinger/services/WebFingerService.kt
+8 −12 ...ry/src/main/java/com/owncloud/android/lib/resources/webfinger/services/implementation/OCWebFingerService.kt
+59 −0 owncloudComLibrary/src/test/java/com/owncloud/android/lib/RemoteFileTest.kt
+3 −3 ...oudComLibrary/src/test/java/com/owncloud/android/lib/resources/webfinger/responses/WebFingerResponseTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package com.owncloud.android.authentication

import android.accounts.AccountManager.KEY_ACCOUNT_NAME
import android.accounts.AccountManager.KEY_ACCOUNT_TYPE
import android.app.Activity
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
Expand All @@ -46,18 +45,18 @@ import com.owncloud.android.domain.server.model.AuthenticationMethod
import com.owncloud.android.domain.server.model.ServerInfo
import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.parseError
import com.owncloud.android.presentation.common.UIResult
import com.owncloud.android.presentation.authentication.ACTION_UPDATE_EXPIRED_TOKEN
import com.owncloud.android.presentation.authentication.ACTION_UPDATE_TOKEN
import com.owncloud.android.presentation.authentication.AuthenticationViewModel
import com.owncloud.android.presentation.authentication.BASIC_TOKEN_TYPE
import com.owncloud.android.presentation.authentication.EXTRA_ACCOUNT
import com.owncloud.android.presentation.authentication.EXTRA_ACTION
import com.owncloud.android.presentation.authentication.KEY_AUTH_TOKEN_TYPE
import com.owncloud.android.presentation.authentication.LoginActivity
import com.owncloud.android.presentation.authentication.OAUTH_TOKEN_TYPE
import com.owncloud.android.presentation.settings.SettingsActivity
import com.owncloud.android.presentation.authentication.AuthenticationViewModel
import com.owncloud.android.presentation.authentication.oauth.OAuthViewModel
import com.owncloud.android.presentation.common.UIResult
import com.owncloud.android.presentation.settings.SettingsActivity
import com.owncloud.android.presentation.settings.SettingsViewModel
import com.owncloud.android.providers.ContextProvider
import com.owncloud.android.providers.MdmProvider
Expand Down Expand Up @@ -107,6 +106,7 @@ class LoginActivityTest {
private lateinit var serverInfoLiveData: MutableLiveData<Event<UIResult<ServerInfo>>>
private lateinit var supportsOauth2LiveData: MutableLiveData<Event<UIResult<Boolean>>>
private lateinit var baseUrlLiveData: MutableLiveData<Event<UIResult<String>>>
private lateinit var accountDiscoveryLiveData: MutableLiveData<Event<UIResult<Unit>>>

@Before
fun setUp() {
Expand All @@ -122,11 +122,13 @@ class LoginActivityTest {
serverInfoLiveData = MutableLiveData()
supportsOauth2LiveData = MutableLiveData()
baseUrlLiveData = MutableLiveData()
accountDiscoveryLiveData = MutableLiveData()

every { authenticationViewModel.loginResult } returns loginResultLiveData
every { authenticationViewModel.serverInfo } returns serverInfoLiveData
every { authenticationViewModel.supportsOAuth2 } returns supportsOauth2LiveData
every { authenticationViewModel.baseUrl } returns baseUrlLiveData
every { authenticationViewModel.accountDiscovery } returns accountDiscoveryLiveData
every { settingsViewModel.isThereAttachedAccount() } returns false

stopKoin()
Expand Down Expand Up @@ -527,8 +529,9 @@ class LoginActivityTest {
launchTest()

loginResultLiveData.postValue(Event(UIResult.Success(data = "Account_name")))
accountDiscoveryLiveData.postValue(Event(UIResult.Success()))

assertEquals(activityScenario.result.resultCode, Activity.RESULT_OK)
assertEquals(activityScenario.result.resultCode, RESULT_OK)
val accountName: String? = activityScenario.result?.resultData?.extras?.getString(KEY_ACCOUNT_NAME)
val accountType: String? = activityScenario.result?.resultData?.extras?.getString(KEY_ACCOUNT_TYPE)

Expand All @@ -543,8 +546,9 @@ class LoginActivityTest {
launchTest(accountType = "notOwnCloud")

loginResultLiveData.postValue(Event(UIResult.Success(data = "Account_name")))
accountDiscoveryLiveData.postValue(Event(UIResult.Success()))

assertEquals(activityScenario.result.resultCode, Activity.RESULT_OK)
assertEquals(activityScenario.result.resultCode, RESULT_OK)
val accountName: String? = activityScenario.result?.resultData?.extras?.getString(KEY_ACCOUNT_NAME)
val accountType: String? = activityScenario.result?.resultData?.extras?.getString(KEY_ACCOUNT_TYPE)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* @author Christian Schabesberger
* @author David González Verdugo
* @author Abel García de Prada
* @author Juan Carlos Garrote Gascón
*
* Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2020 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2023 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
Expand All @@ -28,10 +29,15 @@ import android.accounts.Account
import com.owncloud.android.domain.capabilities.model.OCCapability
import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase
import com.owncloud.android.domain.files.model.OCFile
import com.owncloud.android.domain.files.model.OCFile.Companion.ROOT_PATH
import com.owncloud.android.domain.files.usecases.GetFileByIdUseCase
import com.owncloud.android.domain.files.usecases.GetFileByRemotePathUseCase
import com.owncloud.android.domain.files.usecases.GetFolderContentUseCase
import com.owncloud.android.domain.files.usecases.GetFolderImagesUseCase
import com.owncloud.android.domain.files.usecases.GetPersonalRootFolderForAccountUseCase
import com.owncloud.android.domain.files.usecases.GetSharesRootFolderForAccount
import com.owncloud.android.domain.spaces.model.OCSpace
import com.owncloud.android.domain.spaces.usecases.GetSpaceWithSpecialsByIdForAccountUseCase
import com.owncloud.android.providers.CoroutinesDispatcherProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
Expand All @@ -43,17 +49,40 @@ class FileDataStorageManager(
val account: Account,
) : KoinComponent {

fun getFileByPath(remotePath: String): OCFile? = getFileByPathAndAccount(remotePath, account.name)
fun getFileByPath(remotePath: String, spaceId: String? = null): OCFile? =
if (remotePath == ROOT_PATH && spaceId == null) {
getRootPersonalFolder()
} else {
getFileByPathAndAccount(remotePath, account.name, spaceId)
}

private fun getFileByPathAndAccount(remotePath: String, accountName: String): OCFile? = runBlocking(CoroutinesDispatcherProvider().io) {
private fun getFileByPathAndAccount(remotePath: String, accountName: String, spaceId: String? = null): OCFile? = runBlocking(CoroutinesDispatcherProvider().io) {
val getFileByRemotePathUseCase: GetFileByRemotePathUseCase by inject()

val result = withContext(CoroutineScope(CoroutinesDispatcherProvider().io).coroutineContext) {
getFileByRemotePathUseCase.execute(GetFileByRemotePathUseCase.Params(accountName, remotePath))
getFileByRemotePathUseCase.execute(GetFileByRemotePathUseCase.Params(accountName, remotePath, spaceId))
}.getDataOrNull()
result
}

fun getRootPersonalFolder() = runBlocking(CoroutinesDispatcherProvider().io) {
val getPersonalRootFolderForAccountUseCase: GetPersonalRootFolderForAccountUseCase by inject()

val result = withContext(CoroutineScope(CoroutinesDispatcherProvider().io).coroutineContext) {
getPersonalRootFolderForAccountUseCase.execute(GetPersonalRootFolderForAccountUseCase.Params(account.name))
}
result
}

fun getRootSharesFolder() = runBlocking(CoroutinesDispatcherProvider().io) {
val getSharesRootFolderForAccount: GetSharesRootFolderForAccount by inject()

val result = withContext(CoroutineScope(CoroutinesDispatcherProvider().io).coroutineContext) {
getSharesRootFolderForAccount.execute(GetSharesRootFolderForAccount.Params(account.name))
}
result
}

// TODO: New_arch: Remove this and call usecase inside FilesViewModel
fun getFileById(id: Long): OCFile? = runBlocking(CoroutinesDispatcherProvider().io) {
val getFileByIdUseCase: GetFileByIdUseCase by inject()
Expand Down Expand Up @@ -105,7 +134,16 @@ class FileDataStorageManager(
capability
}

companion object {
const val ROOT_PARENT_ID = 0
fun getSpace(spaceId: String?, accountName: String): OCSpace? = runBlocking(CoroutinesDispatcherProvider().io) {
if (spaceId == null) return@runBlocking null
val getSpaceWithSpecialsByIdForAccountUseCase: GetSpaceWithSpecialsByIdForAccountUseCase by inject()

val space = withContext(CoroutineScope(CoroutinesDispatcherProvider().io).coroutineContext) {
getSpaceWithSpecialsByIdForAccountUseCase.execute(GetSpaceWithSpecialsByIdForAccountUseCase.Params(
spaceId = spaceId,
accountName = accountName,
))
}
return@runBlocking space
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import com.owncloud.android.R;
import com.owncloud.android.domain.files.model.OCFile;
import com.owncloud.android.domain.files.usecases.DisableThumbnailsForFileUseCase;
import com.owncloud.android.domain.files.usecases.GetWebDavUrlForSpaceUseCase;
import com.owncloud.android.domain.spaces.model.SpaceSpecial;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.SingleSessionManager;
Expand Down Expand Up @@ -74,7 +76,8 @@ public class ThumbnailsCacheManager {
private static final int mCompressQuality = 70;
private static OwnCloudClient mClient = null;

private static final String PREVIEW_URI = "%s/remote.php/dav/files/%s%s?x=%d&y=%d&c=%s&preview=1";
private static final String PREVIEW_URI = "%s%s?x=%d&y=%d&c=%s&preview=1";
private static final String SPACE_SPECIAL_URI = "%s?scalingup=0&a=1&x=%d&y=%d&c=%s&preview=1";

public static Bitmap mDefaultImg =
BitmapFactory.decodeResource(
Expand Down Expand Up @@ -186,6 +189,8 @@ protected Bitmap doInBackground(Object... params) {
thumbnail = doOCFileInBackground();
} else if (mFile instanceof File) {
thumbnail = doFileInBackground();
} else if (mFile instanceof SpaceSpecial) {
thumbnail = doSpaceImageInBackground();
//} else { do nothing
}

Expand All @@ -210,6 +215,8 @@ protected void onPostExecute(Bitmap bitmap) {
tagId = String.valueOf(((OCFile) mFile).getId());
} else if (mFile instanceof File) {
tagId = String.valueOf(mFile.hashCode());
} else if (mFile instanceof SpaceSpecial) {
tagId = ((SpaceSpecial) mFile).getId();
}
if (String.valueOf(imageView.getTag()).equals(tagId)) {
imageView.setImageBitmap(bitmap);
Expand Down Expand Up @@ -252,10 +259,18 @@ private int getThumbnailDimension() {
}

private String getPreviewUrl(OCFile ocFile, Account account) {
String baseUrl = mClient.getBaseUri() + "/remote.php/dav/files/" + account.name.split("@")[0];

if (ocFile.getSpaceId() != null) {
Lazy<GetWebDavUrlForSpaceUseCase> getWebDavUrlForSpaceUseCaseLazy = inject(GetWebDavUrlForSpaceUseCase.class);
baseUrl = getWebDavUrlForSpaceUseCaseLazy.getValue().execute(
new GetWebDavUrlForSpaceUseCase.Params(ocFile.getOwner(), ocFile.getSpaceId())
);

}
return String.format(Locale.ROOT,
PREVIEW_URI,
mClient.getBaseUri(),
account.name.split("@")[0],
baseUrl,
Uri.encode(ocFile.getRemotePath(), "/"),
getThumbnailDimension(),
getThumbnailDimension(),
Expand Down Expand Up @@ -349,6 +364,64 @@ private Bitmap doFileInBackground() {
return thumbnail;
}

private String getSpaceSpecialUri(SpaceSpecial spaceSpecial) {
// Converts dp to pixel
Resources r = MainApp.Companion.getAppContext().getResources();
Integer spacesThumbnailSize = Math.round(r.getDimension(R.dimen.spaces_thumbnail_height)) * 2;
return String.format(Locale.ROOT,
SPACE_SPECIAL_URI,
spaceSpecial.getWebDavUrl(),
spacesThumbnailSize,
spacesThumbnailSize,
spaceSpecial.getETag());
}

private Bitmap doSpaceImageInBackground() {
SpaceSpecial spaceSpecial = (SpaceSpecial) mFile;

final String imageKey = spaceSpecial.getId();

// Check disk cache in background thread
Bitmap thumbnail = getBitmapFromDiskCache(imageKey);

// Not found in disk cache
if (thumbnail == null) {
int px = getThumbnailDimension();

// Download thumbnail from server
if (mClient != null) {
GetMethod get;
try {
String uri = getSpaceSpecialUri(spaceSpecial);
Timber.d("URI: %s", uri);
get = new GetMethod(new URL(uri));
int status = mClient.executeHttpMethod(get);
if (status == HttpConstants.HTTP_OK) {
InputStream inputStream = get.getResponseBodyAsStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);

// Handle PNG
if (spaceSpecial.getFile().getMimeType().equalsIgnoreCase("image/png")) {
thumbnail = handlePNG(thumbnail, px);
}

// Add thumbnail to cache
if (thumbnail != null) {
addBitmapToCache(imageKey, thumbnail);
}
} else {
mClient.exhaustResponse(get.getResponseBodyAsStream());
}
} catch (Exception e) {
Timber.e(e);
}
}
}

return thumbnail;

}
}

public static boolean cancelPotentialThumbnailWork(Object file, ImageView imageView) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import com.owncloud.android.data.preferences.datasources.SharedPreferencesProvid
import com.owncloud.android.data.preferences.datasources.implementation.OCSharedPreferencesProvider
import com.owncloud.android.data.sharing.shares.datasources.LocalShareDataSource
import com.owncloud.android.data.sharing.shares.datasources.implementation.OCLocalShareDataSource
import com.owncloud.android.data.spaces.datasources.LocalSpacesDataSource
import com.owncloud.android.data.spaces.datasources.implementation.OCLocalSpacesDataSource
import com.owncloud.android.data.storage.LocalStorageProvider
import com.owncloud.android.data.storage.ScopedStorageProvider
import com.owncloud.android.data.transfers.datasources.LocalTransferDataSource
Expand All @@ -56,6 +58,7 @@ val localDataSourceModule = module {
single { OwncloudDatabase.getDatabase(androidContext()).userDao() }
single { OwncloudDatabase.getDatabase(androidContext()).folderBackUpDao() }
single { OwncloudDatabase.getDatabase(androidContext()).transferDao() }
single { OwncloudDatabase.getDatabase(androidContext()).spacesDao() }

single<SharedPreferencesProvider> { OCSharedPreferencesProvider(get()) }
single<LocalStorageProvider> { ScopedStorageProvider(dataFolder, androidContext()) }
Expand All @@ -67,4 +70,5 @@ val localDataSourceModule = module {
factory<LocalUserDataSource> { OCLocalUserDataSource(get()) }
factory<FolderBackupLocalDataSource> { OCFolderBackupLocalDataSource(get()) }
factory<LocalTransferDataSource> { OCLocalTransferDataSource(get()) }
factory<LocalSpacesDataSource> { OCLocalSpacesDataSource(get()) }
}
Loading

0 comments on commit 262cb56

Please sign in to comment.