Merge remote-tracking branch 'origin/master' into dev

This commit is contained in:
Tobias Kaminsky 2024-11-06 03:39:15 +01:00
commit 8247a31e5b
41 changed files with 237 additions and 69 deletions

View file

@ -16,7 +16,7 @@ import org.gradle.internal.jvm.Jvm
buildscript { buildscript {
dependencies { dependencies {
classpath "com.android.tools.build:gradle:$androidPluginVersion" classpath "com.android.tools.build:gradle:$androidPluginVersion"
classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.25' classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.26'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7" classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.7"
classpath "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2 classpath "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2
@ -269,7 +269,7 @@ dependencies {
} }
// Jetpack Compose // Jetpack Compose
implementation(platform("androidx.compose:compose-bom:2024.10.00")) implementation(platform("androidx.compose:compose-bom:2024.10.01"))
implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.material3:material3") implementation("androidx.compose.material3:material3")
@ -280,7 +280,7 @@ dependencies {
// remove after entire switch to lib v2 // remove after entire switch to lib v2
implementation "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2 implementation "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2
implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' // remove after entire switch to lib v2 implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' // remove after entire switch to lib v2
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.12.0' implementation 'com.google.android.material:material:1.12.0'
implementation 'com.jakewharton:disklrucache:2.0.2' implementation 'com.jakewharton:disklrucache:2.0.2'
@ -310,7 +310,7 @@ dependencies {
exclude group: "com.android.support" exclude group: "com.android.support"
} }
implementation 'com.caverock:androidsvg:1.4' implementation 'com.caverock:androidsvg:1.4'
implementation 'androidx.annotation:annotation:1.9.0' implementation 'androidx.annotation:annotation:1.9.1'
implementation 'com.vanniktech:emoji-google:0.21.0' implementation 'com.vanniktech:emoji-google:0.21.0'
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.6") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.6")

View file

@ -35,6 +35,10 @@
<ignore path="**/values-**/strings.xml" /> <ignore path="**/values-**/strings.xml" />
</issue> </issue>
<issue id="StringFormatCount">
<ignore path="**/values-**/strings.xml" />
</issue>
<issue id="ExtraTranslation"> <issue id="ExtraTranslation">
<ignore path="**/strings.xml"/> <ignore path="**/strings.xml"/>
<ignore path="**/values-b+en+001/strings.xml"/> <ignore path="**/values-b+en+001/strings.xml"/>

View file

@ -183,7 +183,7 @@ public abstract class AbstractIT {
String darkModeParameter = arguments.getString("DARKMODE"); String darkModeParameter = arguments.getString("DARKMODE");
if (darkModeParameter != null) { if (darkModeParameter != null) {
if (darkModeParameter.equalsIgnoreCase("dark")) { if ("dark".equalsIgnoreCase(darkModeParameter)) {
DARK_MODE = "dark"; DARK_MODE = "dark";
AppPreferencesImpl.fromContext(targetContext).setDarkThemeMode(DarkMode.DARK); AppPreferencesImpl.fromContext(targetContext).setDarkThemeMode(DarkMode.DARK);
MainApp.setAppTheme(DarkMode.DARK); MainApp.setAppTheme(DarkMode.DARK);
@ -192,7 +192,7 @@ public abstract class AbstractIT {
} }
} }
if (DARK_MODE.equalsIgnoreCase("light") && COLOR.equalsIgnoreCase("blue")) { if ("light".equalsIgnoreCase(DARK_MODE) && "blue".equalsIgnoreCase(COLOR)) {
// use already existing names // use already existing names
DARK_MODE = ""; DARK_MODE = "";
COLOR = ""; COLOR = "";

View file

@ -515,7 +515,7 @@ public class UploadIT extends AbstractOnServerIT {
OCFile ocFile = null; OCFile ocFile = null;
for (OCFile f : files) { for (OCFile f : files) {
if (f.getFileName().equals("metadata.jpg")) { if ("metadata.jpg".equals(f.getFileName())) {
ocFile = f; ocFile = f;
break; break;
} }

View file

@ -9,7 +9,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
@ -53,7 +52,6 @@
must request the FOREGROUND_SERVICE permission must request the FOREGROUND_SERVICE permission
--> -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Runtime permissions introduced in Android 13 (API level 33) --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Runtime permissions introduced in Android 13 (API level 33) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Needed for Android 14 (API level 34) --> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Needed for Android 14 (API level 34) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

View file

@ -1,7 +1,7 @@
/* /*
* Nextcloud - Android Client * Nextcloud - Android Client
* *
* SPDX-FileCopyrightText: 2023 TSI-mc * SPDX-FileCopyrightText: 2023-2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com> * SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/ */
@ -19,8 +19,10 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
import com.nextcloud.client.onboarding.FirstRunActivity;
import com.nextcloud.common.NextcloudClient; import com.nextcloud.common.NextcloudClient;
import com.nextcloud.utils.extensions.AccountExtensionsKt; import com.nextcloud.utils.extensions.AccountExtensionsKt;
import com.nmc.android.ui.LauncherActivity;
import com.owncloud.android.MainApp; import com.owncloud.android.MainApp;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.authentication.AuthenticatorActivity;
@ -179,19 +181,20 @@ public class UserAccountManagerImpl implements UserAccountManager {
*/ */
@Nullable @Nullable
private User createUserFromAccount(@NonNull Account account) { private User createUserFromAccount(@NonNull Account account) {
if (AccountExtensionsKt.isAnonymous(account, context)) { Context safeContext = context != null ? context : MainApp.getAppContext();
if (safeContext == null) {
Log_OC.e(TAG, "Unable to obtain a valid context");
return null; return null;
} }
if (context == null) { if (AccountExtensionsKt.isAnonymous(account, safeContext)) {
Log_OC.d(TAG, "Context is null MainApp.getAppContext() used"); return null;
context = MainApp.getAppContext();
} }
OwnCloudAccount ownCloudAccount; OwnCloudAccount ownCloudAccount;
try { try {
ownCloudAccount = new OwnCloudAccount(account, context); ownCloudAccount = new OwnCloudAccount(account, safeContext);
} catch (AccountUtils.AccountNotFoundException ex) { } catch (Exception ex) {
return null; return null;
} }
@ -211,7 +214,7 @@ public class UserAccountManagerImpl implements UserAccountManager {
*/ */
String serverAddressStr = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL); String serverAddressStr = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL);
if (serverAddressStr == null || serverAddressStr.isEmpty()) { if (serverAddressStr == null || serverAddressStr.isEmpty()) {
return AnonymousUser.fromContext(context); return AnonymousUser.fromContext(safeContext);
} }
URI serverUri = URI.create(serverAddressStr); // TODO: validate URI serverUri = URI.create(serverAddressStr); // TODO: validate
@ -397,6 +400,10 @@ public class UserAccountManagerImpl implements UserAccountManager {
@Override @Override
public void startAccountCreation(final Activity activity) { public void startAccountCreation(final Activity activity) {
// skipping AuthenticatorActivity redirection when user is on Launcher or FirstRun Activity
if (activity instanceof LauncherActivity || activity instanceof FirstRunActivity) return;
Intent intent = new Intent(context, AuthenticatorActivity.class); Intent intent = new Intent(context, AuthenticatorActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

View file

@ -40,8 +40,15 @@ class OfflineOperationTypeAdapter : JsonSerializer<OfflineOperationType>, JsonDe
jsonObject.addProperty("mimeType", src.mimeType) jsonObject.addProperty("mimeType", src.mimeType)
} }
is OfflineOperationType.RenameFile -> {
jsonObject.addProperty("type", src.type)
jsonObject.addProperty("ocFileId", src.ocFileId)
jsonObject.addProperty("newName", src.newName)
}
null -> Unit null -> Unit
} }
return jsonObject return jsonObject
} }
@ -65,6 +72,12 @@ class OfflineOperationTypeAdapter : JsonSerializer<OfflineOperationType>, JsonDe
jsonObject.get("mimeType").asString jsonObject.get("mimeType").asString
) )
OfflineOperationRawType.RenameFile.name -> OfflineOperationType.RenameFile(
jsonObject.get("type").asString,
jsonObject.get("ocFileId").asLong,
jsonObject.get("newName").asString
)
else -> null else -> null
} }
} }

View file

@ -173,5 +173,4 @@ interface BackgroundJobManager {
fun startOfflineOperations() fun startOfflineOperations()
fun startPeriodicallyOfflineOperation() fun startPeriodicallyOfflineOperation()
fun scheduleInternal2WaySync(intervalMinutes: Long) fun scheduleInternal2WaySync(intervalMinutes: Long)
fun cancelInternal2WaySyncJob()
} }

View file

@ -711,8 +711,4 @@ internal class BackgroundJobManagerImpl(
workManager.enqueueUniquePeriodicWork(JOB_INTERNAL_TWO_WAY_SYNC, ExistingPeriodicWorkPolicy.UPDATE, request) workManager.enqueueUniquePeriodicWork(JOB_INTERNAL_TWO_WAY_SYNC, ExistingPeriodicWorkPolicy.UPDATE, request)
} }
override fun cancelInternal2WaySyncJob() {
workManager.cancelJob(JOB_INTERNAL_TWO_WAY_SYNC)
}
} }

View file

@ -57,6 +57,8 @@ class FilesExportWork(
} }
private fun exportFiles(fileIDs: LongArray): Int { private fun exportFiles(fileIDs: LongArray): Int {
val fileDownloadHelper = FileDownloadHelper.instance()
var successfulExports = 0 var successfulExports = 0
fileIDs fileIDs
.asSequence() .asSequence()
@ -76,7 +78,11 @@ class FilesExportWork(
showErrorNotification(successfulExports) showErrorNotification(successfulExports)
} }
} else { } else {
downloadFile(ocFile) fileDownloadHelper.downloadFile(
user,
ocFile,
downloadType = DownloadType.EXPORT
)
} }
successfulExports++ successfulExports++
@ -95,14 +101,6 @@ class FilesExportWork(
) )
} }
private fun downloadFile(ocFile: OCFile) {
FileDownloadHelper.instance().downloadFile(
user,
ocFile,
downloadType = DownloadType.EXPORT
)
}
private fun showErrorNotification(successfulExports: Int) { private fun showErrorNotification(successfulExports: Int) {
val message = if (successfulExports == 0) { val message = if (successfulExports == 0) {
appContext.resources.getQuantityString(R.plurals.export_failed, successfulExports, successfulExports) appContext.resources.getQuantityString(R.plurals.export_failed, successfulExports, successfulExports)

View file

@ -25,6 +25,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation
import com.owncloud.android.operations.CreateFolderOperation import com.owncloud.android.operations.CreateFolderOperation
import com.owncloud.android.operations.RenameFileOperation
import com.owncloud.android.utils.theme.ViewThemeUtils import com.owncloud.android.utils.theme.ViewThemeUtils
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
@ -98,6 +99,7 @@ class OfflineOperationsWorker(
Result.success() Result.success()
} catch (e: Exception) { } catch (e: Exception) {
Log_OC.d(TAG, "OfflineOperationsWorker terminated: $e") Log_OC.d(TAG, "OfflineOperationsWorker terminated: $e")
notificationManager.dismissNotification()
Result.failure() Result.failure()
} }
} }
@ -146,6 +148,21 @@ class OfflineOperationsWorker(
createFileOperation.execute(client) to createFileOperation createFileOperation.execute(client) to createFileOperation
} }
is OfflineOperationType.RenameFile -> {
val renameFileOperation = withContext(NonCancellable) {
val operationType = (operation.type as OfflineOperationType.RenameFile)
fileDataStorageManager.getFileById(operationType.ocFileId)?.remotePath?.let { updatedRemotePath ->
RenameFileOperation(
updatedRemotePath,
operationType.newName,
fileDataStorageManager
)
}
}
renameFileOperation?.execute(client) to renameFileOperation
}
else -> { else -> {
Log_OC.d(TAG, "Unsupported operation type: ${operation.type}") Log_OC.d(TAG, "Unsupported operation type: ${operation.type}")
null null

View file

@ -2,6 +2,7 @@
* Nextcloud - Android Client * Nextcloud - Android Client
* *
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com> * SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/ */
package com.nextcloud.client.onboarding package com.nextcloud.client.onboarding
@ -42,7 +43,7 @@ internal class OnboardingServiceImpl constructor(
override val isFirstRun: Boolean override val isFirstRun: Boolean
get() { get() {
return accountProvider.currentAccount == null return accountProvider.user.isAnonymous
} }
override fun shouldShowWhatsNew(callingContext: Context): Boolean { override fun shouldShowWhatsNew(callingContext: Context): Boolean {

View file

@ -11,15 +11,23 @@ sealed class OfflineOperationType {
abstract val type: String abstract val type: String
data class CreateFolder(override val type: String, var path: String) : OfflineOperationType() data class CreateFolder(override val type: String, var path: String) : OfflineOperationType()
data class CreateFile( data class CreateFile(
override val type: String, override val type: String,
val localPath: String, val localPath: String,
var remotePath: String, var remotePath: String,
val mimeType: String val mimeType: String
) : OfflineOperationType() ) : OfflineOperationType()
data class RenameFile(
override val type: String,
var ocFileId: Long,
val newName: String
) : OfflineOperationType()
} }
enum class OfflineOperationRawType { enum class OfflineOperationRawType {
CreateFolder, CreateFolder,
CreateFile CreateFile,
RenameFile
} }

View file

@ -3,7 +3,7 @@
* *
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com> * SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2023 Andy Scherzinger <info@andy-scherzinger.de> * SPDX-FileCopyrightText: 2023 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-FileCopyrightText: 2023 TSI-mc * SPDX-FileCopyrightText: 2023-2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/ */
package com.nmc.android.ui package com.nmc.android.ui
@ -18,6 +18,7 @@ import androidx.annotation.VisibleForTesting
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.AppPreferences
import com.owncloud.android.R import com.owncloud.android.R
import com.owncloud.android.authentication.AuthenticatorActivity
import com.owncloud.android.databinding.ActivitySplashBinding import com.owncloud.android.databinding.ActivitySplashBinding
import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.ui.activity.BaseActivity
import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.activity.FileDisplayActivity
@ -65,6 +66,8 @@ class LauncherActivity : BaseActivity() {
Handler(Looper.getMainLooper()).postDelayed({ Handler(Looper.getMainLooper()).postDelayed({
if (user.isPresent) { if (user.isPresent) {
startActivity(Intent(this, FileDisplayActivity::class.java)) startActivity(Intent(this, FileDisplayActivity::class.java))
} else {
startActivity(Intent(this, AuthenticatorActivity::class.java))
} }
finish() finish()
}, SPLASH_DURATION) }, SPLASH_DURATION)

View file

@ -1,7 +1,7 @@
/* /*
* Nextcloud - Android Client * Nextcloud - Android Client
* *
* SPDX-FileCopyrightText: 2023 TSI-mc * SPDX-FileCopyrightText: 2023-2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2019-2021 Tobias Kaminsky <tobias@kaminsky.me> * SPDX-FileCopyrightText: 2019-2021 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2018 Andy Scherzinger <info@andy-scherzinger> * SPDX-FileCopyrightText: 2018 Andy Scherzinger <info@andy-scherzinger>
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com> * SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
@ -1364,14 +1364,13 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
} }
private void endSuccess() { private void endSuccess() {
if (onlyAdd) { if (!onlyAdd) {
finish();
} else {
Intent i = new Intent(this, FileDisplayActivity.class); Intent i = new Intent(this, FileDisplayActivity.class);
i.setAction(FileDisplayActivity.RESTART); i.setAction(FileDisplayActivity.RESTART);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i); startActivity(i);
} }
finish();
} }
private void getUserCapabilitiesAndFinish() { private void getUserCapabilitiesAndFinish() {

View file

@ -217,6 +217,35 @@ public class FileDataStorageManager {
offlineOperationsRepository.deleteOperation(file); offlineOperationsRepository.deleteOperation(file);
} }
public void addRenameFileOfflineOperation(OCFile file, String newName) {
OfflineOperationEntity entity = new OfflineOperationEntity();
entity.setFilename(newName);
entity.setParentOCFileId(file.getParentId());
OfflineOperationType operationType = new OfflineOperationType.RenameFile(OfflineOperationRawType.RenameFile.name(), file.getFileId(), newName);
entity.setType(operationType);
entity.setPath(file.getDecryptedRemotePath());
long createdAt = System.currentTimeMillis();
long modificationTimestamp = System.currentTimeMillis();
entity.setCreatedAt(createdAt);
entity.setModifiedAt(modificationTimestamp / 1000);
offlineOperationDao.insert(entity);
}
public String getFilenameConsideringOfflineOperation(OCFile file) {
String filename = file.getDecryptedFileName();
OfflineOperationEntity renameEntity = offlineOperationDao.getByPath(file.getDecryptedRemotePath());
if (renameEntity != null && renameEntity.getType() instanceof OfflineOperationType.RenameFile renameFile) {
filename = renameFile.getNewName();
}
return filename;
}
public void renameOfflineOperation(OCFile file, String newFolderName) { public void renameOfflineOperation(OCFile file, String newFolderName) {
var entity = offlineOperationDao.getByPath(file.getDecryptedRemotePath()); var entity = offlineOperationDao.getByPath(file.getDecryptedRemotePath());
if (entity == null) { if (entity == null) {

View file

@ -397,8 +397,10 @@ public class FileMenuFilter {
} }
private boolean anyFileDownloading() { private boolean anyFileDownloading() {
final var fileDownloadHelper = FileDownloadHelper.Companion.instance();
for (OCFile file : files) { for (OCFile file : files) {
if (FileDownloadHelper.Companion.instance().isDownloading(user, file)) { if (fileDownloadHelper.isDownloading(user, file)) {
return true; return true;
} }
} }

View file

@ -124,7 +124,7 @@ public class CreateShareWithShareeOperation extends SyncOperation {
try { try {
String publicKey = EncryptionUtils.getPublicKey(user, shareeName, arbitraryDataProvider); String publicKey = EncryptionUtils.getPublicKey(user, shareeName, arbitraryDataProvider);
if (publicKey.equals("")) { if ("".equals(publicKey)) {
NextcloudClient nextcloudClient = new ClientFactoryImpl(context).createNextcloudClient(user); NextcloudClient nextcloudClient = new ClientFactoryImpl(context).createNextcloudClient(user);
RemoteOperationResult<String> result = new GetPublicKeyRemoteOperation(shareeName).execute(nextcloudClient); RemoteOperationResult<String> result = new GetPublicKeyRemoteOperation(shareeName).execute(nextcloudClient);
if (result.isSuccess()) { if (result.isSuccess()) {

View file

@ -441,7 +441,8 @@ public class SynchronizeFolderOperation extends SyncOperation {
} }
private void startDirectDownloads() { private void startDirectDownloads() {
mFilesForDirectDownload.forEach(file -> FileDownloadHelper.Companion.instance().downloadFile(user, file)); final var fileDownloadHelper = FileDownloadHelper.Companion.instance();
mFilesForDirectDownload.forEach(file -> fileDownloadHelper.downloadFile(user, file));
} }
/** /**

View file

@ -2,6 +2,7 @@
* Nextcloud - Android Client * Nextcloud - Android Client
* *
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/ */
package com.owncloud.android.ui.activity; package com.owncloud.android.ui.activity;
@ -115,8 +116,10 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
protected void onRestart() { protected void onRestart() {
Log_OC.v(TAG, "onRestart() start"); Log_OC.v(TAG, "onRestart() start");
super.onRestart(); super.onRestart();
if (enableAccountHandling) {
mixinRegistry.onRestart(); mixinRegistry.onRestart();
} }
}
private void onThemeSettingsModeChanged() { private void onThemeSettingsModeChanged() {
if (paused) { if (paused) {

View file

@ -181,7 +181,7 @@ class InternalTwoWaySyncActivity :
if (isChecked) { if (isChecked) {
backgroundJobManager.scheduleInternal2WaySync(preferences.twoWaySyncInterval) backgroundJobManager.scheduleInternal2WaySync(preferences.twoWaySyncInterval)
} else { } else {
backgroundJobManager.cancelInternal2WaySyncJob() backgroundJobManager.cancelTwoWaySyncJob()
} }
} }
} }

View file

@ -142,7 +142,7 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable
String title; String title;
boolean isRoot = isRoot(chosenFile); boolean isRoot = isRoot(chosenFile);
title = isRoot ? themeUtils.getDefaultDisplayNameForRootFolder(this) : chosenFile.getFileName(); title = isRoot ? themeUtils.getDefaultDisplayNameForRootFolder(this) : fileDataStorageManager.getFilenameConsideringOfflineOperation(chosenFile);
updateActionBarTitleAndHomeButtonByString(title); updateActionBarTitleAndHomeButtonByString(title);
if (mAppBar != null) { if (mAppBar != null) {

View file

@ -518,7 +518,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
} }
private void bindListGridItemViewHolder(ListGridItemViewHolder holder, OCFile file) { private void bindListGridItemViewHolder(ListGridItemViewHolder holder, OCFile file) {
holder.getFileName().setText(file.getDecryptedFileName()); holder.getFileName().setText(mStorageManager.getFilenameConsideringOfflineOperation(file));
boolean gridImage = MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file); boolean gridImage = MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file);
if (gridView && gridImage) { if (gridView && gridImage) {

View file

@ -335,10 +335,11 @@ class OCFileListDelegate(
private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListViewHolder) { private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListViewHolder) {
val operationsServiceBinder = transferServiceGetter.operationsServiceBinder val operationsServiceBinder = transferServiceGetter.operationsServiceBinder
val fileDownloadHelper = FileDownloadHelper.instance()
val icon: Int? = when { val icon: Int? = when {
operationsServiceBinder?.isSynchronizing(user, file) == true || operationsServiceBinder?.isSynchronizing(user, file) == true ||
FileDownloadHelper.instance().isDownloading(user, file) || fileDownloadHelper.isDownloading(user, file) ||
fileUploadHelper.isUploading(user, file) -> { fileUploadHelper.isUploading(user, file) -> {
// synchronizing, downloading or uploading // synchronizing, downloading or uploading
R.drawable.ic_synchronizing R.drawable.ic_synchronizing

View file

@ -24,6 +24,7 @@ import com.google.common.collect.Sets
import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.account.CurrentAccountProvider
import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.Injectable
import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getParcelableArgument
import com.nextcloud.utils.extensions.typedActivity
import com.nextcloud.utils.fileNameValidator.FileNameValidator.checkFileName import com.nextcloud.utils.fileNameValidator.FileNameValidator.checkFileName
import com.nextcloud.utils.fileNameValidator.FileNameValidator.isFileHidden import com.nextcloud.utils.fileNameValidator.FileNameValidator.isFileHidden
import com.owncloud.android.R import com.owncloud.android.R
@ -147,12 +148,16 @@ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListen
if (mTargetFile?.isOfflineOperation == true) { if (mTargetFile?.isOfflineOperation == true) {
fileDataStorageManager.renameOfflineOperation(mTargetFile, newFileName) fileDataStorageManager.renameOfflineOperation(mTargetFile, newFileName)
if (requireActivity() is FileDisplayActivity) { typedActivity<FileDisplayActivity>()?.refreshCurrentDirectory()
val activity = requireActivity() as FileDisplayActivity
activity.refreshCurrentDirectory()
}
} else { } else {
(requireActivity() as ComponentsGetter).fileOperationsHelper.renameFile(mTargetFile, newFileName) typedActivity<FileDisplayActivity>()?.connectivityService?.isNetworkAndServerAvailable { result ->
if (result) {
typedActivity<ComponentsGetter>()?.fileOperationsHelper?.renameFile(mTargetFile, newFileName)
} else {
fileDataStorageManager.addRenameFileOfflineOperation(mTargetFile, newFileName)
typedActivity<FileDisplayActivity>()?.refreshCurrentDirectory()
}
}
} }
} }
} }

View file

@ -653,13 +653,15 @@ class PreviewMediaActivity :
packageName: String? = null, packageName: String? = null,
activityName: String? = null activityName: String? = null
) { ) {
if (FileDownloadHelper.instance().isDownloading(user, file)) { val fileDownloadHelper = FileDownloadHelper.instance()
if (fileDownloadHelper.isDownloading(user, file)) {
return return
} }
user?.let { user -> user?.let { user ->
file?.let { file -> file?.let { file ->
FileDownloadHelper.instance().downloadFile( fileDownloadHelper.downloadFile(
user, user,
file, file,
downloadBehavior ?: "", downloadBehavior ?: "",

View file

@ -50,13 +50,13 @@ public class CalendarSource {
String protocol = mUrl.getProtocol(); String protocol = mUrl.getProtocol();
String userPass = mUsername + ":" + mPassword; String userPass = mUsername + ":" + mPassword;
if (protocol.equalsIgnoreCase("ftp") || protocol.equalsIgnoreCase("ftps")) { if ("ftp".equalsIgnoreCase(protocol) || "ftps".equalsIgnoreCase(protocol)) {
String external = mUrl.toExternalForm(); String external = mUrl.toExternalForm();
String end = external.substring(protocol.length() + HTTP_SEP.length()); String end = external.substring(protocol.length() + HTTP_SEP.length());
return new URL(protocol + HTTP_SEP + userPass + "@" + end).openConnection(); return new URL(protocol + HTTP_SEP + userPass + "@" + end).openConnection();
} }
if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) { if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) {
String encoded = new String(new Base64().encode(userPass.getBytes("UTF-8"))); String encoded = new String(new Base64().encode(userPass.getBytes("UTF-8")));
URLConnection connection = mUrl.openConnection(); URLConnection connection = mUrl.openConnection();
connection.setRequestProperty("Authorization", "Basic " + encoded); connection.setRequestProperty("Authorization", "Basic " + encoded);

View file

@ -567,7 +567,7 @@ public class ProcessVEvent {
String expected = parts.length > 1 ? parts[1] : ""; String expected = parts.length > 1 ? parts[1] : "";
String got = c.getAsString(key); String got = c.getAsString(key);
if (expected.equals("<non-null>") && got != null) { if ("<non-null>".equals(expected) && got != null) {
got = "<non-null>"; // Sentinel for testing present and non-null got = "<non-null>"; // Sentinel for testing present and non-null
} }
if (got == null) { if (got == null) {

View file

@ -478,7 +478,7 @@ public class SaveCalendar {
return true; return true;
} }
final String utz = tz.toUpperCase(Locale.US); final String utz = tz.toUpperCase(Locale.US);
return utz.equals("UTC") || utz.equals("UTC-0") || utz.equals("UTC+0") || utz.endsWith("/UTC"); return "UTC".equals(utz) || "UTC-0".equals(utz) || "UTC+0".equals(utz) || utz.endsWith("/UTC");
} }
private Date getDateTime(Cursor cur, String dbName, String dbTzName, Calendar cal) { private Date getDateTime(Cursor cur, String dbName, String dbTzName, Calendar cal) {

View file

@ -700,7 +700,9 @@
<string name="prefs_synced_folders_local_path_title">مجلد محلي</string> <string name="prefs_synced_folders_local_path_title">مجلد محلي</string>
<string name="prefs_synced_folders_remote_path_title">مجلد عن بعد</string> <string name="prefs_synced_folders_remote_path_title">مجلد عن بعد</string>
<string name="prefs_theme_title">السمة</string> <string name="prefs_theme_title">السمة</string>
<string name="prefs_two_way_sync_interval">الفسحة الزمنية</string>
<string name="prefs_two_way_sync_summary">إدارة المجلدات الداخلية للمزامنة في الاتجاهين</string> <string name="prefs_two_way_sync_summary">إدارة المجلدات الداخلية للمزامنة في الاتجاهين</string>
<string name="prefs_two_way_sync_switch_title">تمكين المزامنة في الاتجاهين</string>
<string name="prefs_value_theme_dark">غامق</string> <string name="prefs_value_theme_dark">غامق</string>
<string name="prefs_value_theme_light">فاتح</string> <string name="prefs_value_theme_light">فاتح</string>
<string name="prefs_value_theme_system">اتبع النظام</string> <string name="prefs_value_theme_system">اتبع النظام</string>
@ -1097,6 +1099,22 @@
<string name="write_email">إرسال بريد</string> <string name="write_email">إرسال بريد</string>
<string name="wrong_storage_path">مجلد التخزين غير موجود !</string> <string name="wrong_storage_path">مجلد التخزين غير موجود !</string>
<string name="wrong_storage_path_desc">قد يكون هذا بسبب استعادة نسخة احتياطية على جهاز آخر . العودة الى الافتراضي . يرجى التحقق من الإعدادات لضبط مجلد تخزين البيانات.</string> <string name="wrong_storage_path_desc">قد يكون هذا بسبب استعادة نسخة احتياطية على جهاز آخر . العودة الى الافتراضي . يرجى التحقق من الإعدادات لضبط مجلد تخزين البيانات.</string>
<plurals name="hours">
<item quantity="zero">%d ساعة</item>
<item quantity="one">%d ساعة</item>
<item quantity="two">%d ساعة</item>
<item quantity="few">%d ساعات</item>
<item quantity="many">%d ساعة</item>
<item quantity="other">%d ساعة</item>
</plurals>
<plurals name="minutes">
<item quantity="zero">%d دقيقة</item>
<item quantity="one">%d دقيقة</item>
<item quantity="two">%d دقيقة</item>
<item quantity="few">%d دقائق</item>
<item quantity="many">%d دقيقة</item>
<item quantity="other">%d دقيقة</item>
</plurals>
<plurals name="sync_fail_in_favourites_content"> <plurals name="sync_fail_in_favourites_content">
<item quantity="zero">تعذرت مزامنة الملفات %1$d (التعارضات:%2$d)</item> <item quantity="zero">تعذرت مزامنة الملفات %1$d (التعارضات:%2$d)</item>
<item quantity="one">تعذرت مزامنة الملفات %1$d (التعارضات:%2$d)</item> <item quantity="one">تعذرت مزامنة الملفات %1$d (التعارضات:%2$d)</item>

View file

@ -696,7 +696,9 @@
<string name="prefs_synced_folders_local_path_title">Local folder</string> <string name="prefs_synced_folders_local_path_title">Local folder</string>
<string name="prefs_synced_folders_remote_path_title">Remote folder</string> <string name="prefs_synced_folders_remote_path_title">Remote folder</string>
<string name="prefs_theme_title">Theme</string> <string name="prefs_theme_title">Theme</string>
<string name="prefs_two_way_sync_interval">Interval</string>
<string name="prefs_two_way_sync_summary">Manage internal folders for two way sync</string> <string name="prefs_two_way_sync_summary">Manage internal folders for two way sync</string>
<string name="prefs_two_way_sync_switch_title">Enable two way sync</string>
<string name="prefs_value_theme_dark">Dark</string> <string name="prefs_value_theme_dark">Dark</string>
<string name="prefs_value_theme_light">Light</string> <string name="prefs_value_theme_light">Light</string>
<string name="prefs_value_theme_system">Follow system</string> <string name="prefs_value_theme_system">Follow system</string>
@ -1070,6 +1072,14 @@
<string name="write_email">Send email</string> <string name="write_email">Send email</string>
<string name="wrong_storage_path">Data storage folder does not exist!</string> <string name="wrong_storage_path">Data storage folder does not exist!</string>
<string name="wrong_storage_path_desc">This might be due to a backup restore on another device. Falling back to default. Please check settings to adjust data storage folder.</string> <string name="wrong_storage_path_desc">This might be due to a backup restore on another device. Falling back to default. Please check settings to adjust data storage folder.</string>
<plurals name="hours">
<item quantity="one">%d hour</item>
<item quantity="other">%d hours</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d minute</item>
<item quantity="other">%d minutes</item>
</plurals>
<plurals name="sync_fail_in_favourites_content"> <plurals name="sync_fail_in_favourites_content">
<item quantity="one">Could not sync %1$d file (conflicts: %2$d)</item> <item quantity="one">Could not sync %1$d file (conflicts: %2$d)</item>
<item quantity="other">Could not sync %1$d files (conflicts: %2$d)</item> <item quantity="other">Could not sync %1$d files (conflicts: %2$d)</item>

View file

@ -696,7 +696,9 @@
<string name="prefs_synced_folders_local_path_title">Fillteán áitiúil</string> <string name="prefs_synced_folders_local_path_title">Fillteán áitiúil</string>
<string name="prefs_synced_folders_remote_path_title">Fillteán cianda</string> <string name="prefs_synced_folders_remote_path_title">Fillteán cianda</string>
<string name="prefs_theme_title">Téama</string> <string name="prefs_theme_title">Téama</string>
<string name="prefs_two_way_sync_interval">Eatramh</string>
<string name="prefs_two_way_sync_summary">Bainistigh fillteáin inmheánacha le haghaidh sioncronaithe dhá bhealach</string> <string name="prefs_two_way_sync_summary">Bainistigh fillteáin inmheánacha le haghaidh sioncronaithe dhá bhealach</string>
<string name="prefs_two_way_sync_switch_title">Cumasaigh sioncronú dhá bhealach</string>
<string name="prefs_value_theme_dark">Dorcha</string> <string name="prefs_value_theme_dark">Dorcha</string>
<string name="prefs_value_theme_light">Solas</string> <string name="prefs_value_theme_light">Solas</string>
<string name="prefs_value_theme_system">Lean an córas</string> <string name="prefs_value_theme_system">Lean an córas</string>
@ -1070,6 +1072,20 @@
<string name="write_email">Seol ríomhphost</string> <string name="write_email">Seol ríomhphost</string>
<string name="wrong_storage_path">Níl fillteán stórála sonraí ann!</string> <string name="wrong_storage_path">Níl fillteán stórála sonraí ann!</string>
<string name="wrong_storage_path_desc">D\'fhéadfadh sé seo a bheith mar gheall ar aischur cúltaca ar ghléas eile. Ag titim ar ais go réamhshocraithe. Seiceáil le do thoil socruithe chun fillteán stórála sonraí a choigeartú.</string> <string name="wrong_storage_path_desc">D\'fhéadfadh sé seo a bheith mar gheall ar aischur cúltaca ar ghléas eile. Ag titim ar ais go réamhshocraithe. Seiceáil le do thoil socruithe chun fillteán stórála sonraí a choigeartú.</string>
<plurals name="hours">
<item quantity="one">%d uair</item>
<item quantity="two">%d uair an chloig</item>
<item quantity="few">%d uair an chloig</item>
<item quantity="many">%d uair an chloig</item>
<item quantity="other">%d uair an chloig</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d nóiméad</item>
<item quantity="two">%d nóiméad</item>
<item quantity="few">%d nóiméad</item>
<item quantity="many">%d nóiméad</item>
<item quantity="other">%d nóiméad</item>
</plurals>
<plurals name="sync_fail_in_favourites_content"> <plurals name="sync_fail_in_favourites_content">
<item quantity="one">Níorbh fhéidir comhad %1$d a shioncronú (coimhlint: %2$d)</item> <item quantity="one">Níorbh fhéidir comhad %1$d a shioncronú (coimhlint: %2$d)</item>
<item quantity="two">Níorbh fhéidir %1$d comhad a shioncronú (coimhlint: %2$d)</item> <item quantity="two">Níorbh fhéidir %1$d comhad a shioncronú (coimhlint: %2$d)</item>

View file

@ -697,7 +697,9 @@
<string name="prefs_synced_folders_local_path_title">Cartafol local</string> <string name="prefs_synced_folders_local_path_title">Cartafol local</string>
<string name="prefs_synced_folders_remote_path_title">Cartafol remoto</string> <string name="prefs_synced_folders_remote_path_title">Cartafol remoto</string>
<string name="prefs_theme_title">Tema</string> <string name="prefs_theme_title">Tema</string>
<string name="prefs_two_way_sync_interval">Intervalo</string>
<string name="prefs_two_way_sync_summary">Xestionar os cartafoles internos para a sincronización bidireccional</string> <string name="prefs_two_way_sync_summary">Xestionar os cartafoles internos para a sincronización bidireccional</string>
<string name="prefs_two_way_sync_switch_title">Activar a sincronización bidireccional</string>
<string name="prefs_value_theme_dark">Escuro</string> <string name="prefs_value_theme_dark">Escuro</string>
<string name="prefs_value_theme_light">Claro</string> <string name="prefs_value_theme_light">Claro</string>
<string name="prefs_value_theme_system">Seguir o sistema</string> <string name="prefs_value_theme_system">Seguir o sistema</string>
@ -1071,6 +1073,14 @@
<string name="write_email">Enviar o correo</string> <string name="write_email">Enviar o correo</string>
<string name="wrong_storage_path">O cartafol de almacenamento de datos non existe.</string> <string name="wrong_storage_path">O cartafol de almacenamento de datos non existe.</string>
<string name="wrong_storage_path_desc">Isto pode deberse a unha restauración de copia de seguranza noutro dispositivo. Volvendo ao predeterminado. Comprobe as opcións para axustar o cartafol de almacenamento de datos.</string> <string name="wrong_storage_path_desc">Isto pode deberse a unha restauración de copia de seguranza noutro dispositivo. Volvendo ao predeterminado. Comprobe as opcións para axustar o cartafol de almacenamento de datos.</string>
<plurals name="hours">
<item quantity="one">%d hora</item>
<item quantity="other">%d horas</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d minuto</item>
<item quantity="other">%d minutos</item>
</plurals>
<plurals name="sync_fail_in_favourites_content"> <plurals name="sync_fail_in_favourites_content">
<item quantity="one">Non foi posíbel sincronizar %1$d ficheiro (conflitos: %2$d)</item> <item quantity="one">Non foi posíbel sincronizar %1$d ficheiro (conflitos: %2$d)</item>
<item quantity="other">Non foi posíbel sincronizar %1$d ficheiros (conflitos: %2$d)</item> <item quantity="other">Non foi posíbel sincronizar %1$d ficheiros (conflitos: %2$d)</item>

View file

@ -696,7 +696,9 @@
<string name="prefs_synced_folders_local_path_title">Yerel klasör</string> <string name="prefs_synced_folders_local_path_title">Yerel klasör</string>
<string name="prefs_synced_folders_remote_path_title">Uzak klasör</string> <string name="prefs_synced_folders_remote_path_title">Uzak klasör</string>
<string name="prefs_theme_title">Tema</string> <string name="prefs_theme_title">Tema</string>
<string name="prefs_two_way_sync_interval">Aralık</string>
<string name="prefs_two_way_sync_summary">İç klasörleri iki yönlü eşitleme ile yönetin</string> <string name="prefs_two_way_sync_summary">İç klasörleri iki yönlü eşitleme ile yönetin</string>
<string name="prefs_two_way_sync_switch_title">İki yönlü eşitlemeyi aç</string>
<string name="prefs_value_theme_dark">Koyu</string> <string name="prefs_value_theme_dark">Koyu</string>
<string name="prefs_value_theme_light">ık</string> <string name="prefs_value_theme_light">ık</string>
<string name="prefs_value_theme_system">Sistem ayarı</string> <string name="prefs_value_theme_system">Sistem ayarı</string>
@ -1070,6 +1072,14 @@
<string name="write_email">E-posta gönder</string> <string name="write_email">E-posta gönder</string>
<string name="wrong_storage_path">Veri depolama klasörü bulunamadı!</string> <string name="wrong_storage_path">Veri depolama klasörü bulunamadı!</string>
<string name="wrong_storage_path_desc">Bunun nedeni bir yedeğin başka bir aygıta geri yüklenmesi olabilir. Varsayılan değerlere geri dönülüyor. Lütfen veri depolama klasörünü ayarlamak için ayarları denetleyin.</string> <string name="wrong_storage_path_desc">Bunun nedeni bir yedeğin başka bir aygıta geri yüklenmesi olabilir. Varsayılan değerlere geri dönülüyor. Lütfen veri depolama klasörünü ayarlamak için ayarları denetleyin.</string>
<plurals name="hours">
<item quantity="one">%d saat</item>
<item quantity="other">%d saat</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%d dakika</item>
<item quantity="other">%d dakika</item>
</plurals>
<plurals name="sync_fail_in_favourites_content"> <plurals name="sync_fail_in_favourites_content">
<item quantity="one">%1$d dosya eşitlenemedi (çakışma: %2$d)</item> <item quantity="one">%1$d dosya eşitlenemedi (çakışma: %2$d)</item>
<item quantity="other">%1$d dosya eşitlenemedi (çakışma: %2$d)</item> <item quantity="other">%1$d dosya eşitlenemedi (çakışma: %2$d)</item>

View file

@ -696,7 +696,9 @@
<string name="prefs_synced_folders_local_path_title">近端資料夾</string> <string name="prefs_synced_folders_local_path_title">近端資料夾</string>
<string name="prefs_synced_folders_remote_path_title">遠端資料夾</string> <string name="prefs_synced_folders_remote_path_title">遠端資料夾</string>
<string name="prefs_theme_title">佈景主題</string> <string name="prefs_theme_title">佈景主題</string>
<string name="prefs_two_way_sync_interval">間距</string>
<string name="prefs_two_way_sync_summary">管理內部資料夾以進行雙向同步</string> <string name="prefs_two_way_sync_summary">管理內部資料夾以進行雙向同步</string>
<string name="prefs_two_way_sync_switch_title">啟用雙向同步</string>
<string name="prefs_value_theme_dark">深色</string> <string name="prefs_value_theme_dark">深色</string>
<string name="prefs_value_theme_light">淺色</string> <string name="prefs_value_theme_light">淺色</string>
<string name="prefs_value_theme_system">跟隨系統</string> <string name="prefs_value_theme_system">跟隨系統</string>
@ -1070,6 +1072,12 @@
<string name="write_email">傳送電子郵件</string> <string name="write_email">傳送電子郵件</string>
<string name="wrong_storage_path">資料儲存資料夾不存在!</string> <string name="wrong_storage_path">資料儲存資料夾不存在!</string>
<string name="wrong_storage_path_desc">這可能是由於另一部設備上的備份還原所致。退回默認值。請檢查設置以調整數據存儲資料夾。</string> <string name="wrong_storage_path_desc">這可能是由於另一部設備上的備份還原所致。退回默認值。請檢查設置以調整數據存儲資料夾。</string>
<plurals name="hours">
<item quantity="other">%d 小時</item>
</plurals>
<plurals name="minutes">
<item quantity="other">%d 分鐘</item>
</plurals>
<plurals name="sync_fail_in_favourites_content"> <plurals name="sync_fail_in_favourites_content">
<item quantity="other">無法同步 %1$d 檔案(抵觸: %2$d</item> <item quantity="other">無法同步 %1$d 檔案(抵觸: %2$d</item>
</plurals> </plurals>

View file

@ -1176,7 +1176,7 @@
<string name="icon_of_widget_entry">Icon of widget entry</string> <string name="icon_of_widget_entry">Icon of widget entry</string>
<string name="choose_widget">Choose widget</string> <string name="choose_widget">Choose widget</string>
<string name="reload">Reload</string> <string name="reload">Reload</string>
<string name="widgets_not_available">Widgets are only available on %1$s 25 or later</string> <string name="widgets_not_available">Widgets are only available in %1$s 25 or later when the Dashboard app is enabled</string>
<string name="widgets_not_available_title">Not available</string> <string name="widgets_not_available_title">Not available</string>
<string name="icon_for_empty_list">Icon for empty list</string> <string name="icon_for_empty_list">Icon for empty list</string>
<string name="no_items">No items</string> <string name="no_items">No items</string>

View file

@ -252,7 +252,7 @@
<!-- Launch screen --> <!-- Launch screen -->
<style name="Theme.ownCloud.Launcher"> <style name="Theme.ownCloud.Launcher">
<item name="android:statusBarColor">@color/primary</item> <item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@color/primary</item> <item name="android:navigationBarColor">@color/primary</item>
<item name="android:windowBackground">@color/primary</item> <item name="android:windowBackground">@color/primary</item>
<item name="android:textColorHint">@color/secondary_text_color</item> <item name="android:textColorHint">@color/secondary_text_color</item>

View file

@ -2,13 +2,15 @@
* Nextcloud - Android Client * Nextcloud - Android Client
* *
* SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com> * SPDX-FileCopyrightText: 2019 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2024 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/ */
package com.nextcloud.client.onboarding package com.nextcloud.client.onboarding
import android.accounts.Account
import android.content.res.Resources import android.content.res.Resources
import com.nextcloud.client.account.AnonymousUser
import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.account.CurrentAccountProvider
import com.nextcloud.client.account.User
import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.AppPreferences
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
@ -30,7 +32,7 @@ class OnboardingServiceTest {
private lateinit var currentAccountProvider: CurrentAccountProvider private lateinit var currentAccountProvider: CurrentAccountProvider
@Mock @Mock
private lateinit var account: Account private lateinit var user: User
private lateinit var onboardingService: OnboardingServiceImpl private lateinit var onboardingService: OnboardingServiceImpl
@ -43,13 +45,16 @@ class OnboardingServiceTest {
@Test @Test
fun `first run flag toggles with current current account`() { fun `first run flag toggles with current current account`() {
// GIVEN // GIVEN
// current account is not set // current account is anonymous
whenever(currentAccountProvider.user).thenReturn(AnonymousUser("dummy"))
// THEN
// first run flag is true // first run flag is true
assertTrue(onboardingService.isFirstRun) assertTrue(onboardingService.isFirstRun)
// WHEN // WHEN
// current account is set // current account is set
whenever(currentAccountProvider.currentAccount).thenReturn(account) whenever(currentAccountProvider.user).thenReturn(user)
// THEN // THEN
// first run flag toggles // first run flag toggles

View file

@ -10,8 +10,8 @@
*/ */
buildscript { buildscript {
ext { ext {
androidLibraryVersion ="3ec02eb2aeb59185815a3a9c41c9dd98679f6fbe" androidLibraryVersion ="ceb3812b688f2288911acf4d917596283fab0ea5"
androidPluginVersion = '8.7.1' androidPluginVersion = '8.7.2'
androidxMediaVersion = '1.4.1' androidxMediaVersion = '1.4.1'
androidxTestVersion = "1.6.1" androidxTestVersion = "1.6.1"
appCompatVersion = '1.7.0' appCompatVersion = '1.7.0'

View file

@ -259,11 +259,13 @@
<trusting group="androidx.annotation"/> <trusting group="androidx.annotation"/>
<trusting group="androidx.appcompat"/> <trusting group="androidx.appcompat"/>
<trusting group="androidx.collection"/> <trusting group="androidx.collection"/>
<trusting group="androidx.constraintlayout"/>
<trusting group="androidx.core"/> <trusting group="androidx.core"/>
<trusting group="androidx.databinding"/> <trusting group="androidx.databinding"/>
<trusting group="androidx.fragment"/> <trusting group="androidx.fragment"/>
<trusting group="androidx.graphics"/> <trusting group="androidx.graphics"/>
<trusting group="androidx.lifecycle"/> <trusting group="androidx.lifecycle"/>
<trusting group="androidx.profileinstaller"/>
<trusting group="androidx.transition" name="transition" version="1.5.0"/> <trusting group="androidx.transition" name="transition" version="1.5.0"/>
<trusting group="androidx.webkit" name="webkit" version="1.11.0"/> <trusting group="androidx.webkit" name="webkit" version="1.11.0"/>
<trusting group="androidx.webkit" name="webkit" version="1.12.0"/> <trusting group="androidx.webkit" name="webkit" version="1.12.0"/>
@ -873,6 +875,11 @@
<sha256 value="61f162bcc78a43f88415bec61aa80060ab14a968aad73696a4373ddb17211ae2" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="61f162bcc78a43f88415bec61aa80060ab14a968aad73696a4373ddb17211ae2" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact> </artifact>
</component> </component>
<component group="androidx.compose" name="compose-bom" version="2024.10.01">
<artifact name="compose-bom-2024.10.01.pom">
<sha256 value="e4b122da072402de71c8a20b85289d68e4d4446d7b1bee6dee4fef9d4677130b" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation-core" version="1.0.0-beta03"> <component group="androidx.compose.animation" name="animation-core" version="1.0.0-beta03">
<artifact name="animation-core-1.0.0-beta03.aar"> <artifact name="animation-core-1.0.0-beta03.aar">
<sha256 value="4626086855eb6582dda9c3050c05bb56632f5a0308a3bb71a0f58def958602ca" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="4626086855eb6582dda9c3050c05bb56632f5a0308a3bb71a0f58def958602ca" origin="Generated by Gradle" reason="Artifact is not signed"/>

View file

@ -18,6 +18,8 @@ ruby scripts/analysis/lint-up.rb
lintValue=$? lintValue=$?
curl "https://www.kaminsky.me/nc-dev/$repository-findbugs/$stableBranch.xml" -o "/tmp/$stableBranch.xml" curl "https://www.kaminsky.me/nc-dev/$repository-findbugs/$stableBranch.xml" -o "/tmp/$stableBranch.xml"
[[ ! -e test1 ]] && exit 1
ruby scripts/analysis/spotbugs-up.rb "$stableBranch" ruby scripts/analysis/spotbugs-up.rb "$stableBranch"
spotbugsValue=$? spotbugsValue=$?
@ -132,10 +134,6 @@ else
exit 1 exit 1
fi fi
if [ $checkLibrary -eq 1 ]; then
exit 1
fi
if [ ! $lintValue -eq 2 ]; then if [ ! $lintValue -eq 2 ]; then
exit $lintValue exit $lintValue
fi fi