diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3de7f410d..111a0dc01 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -37,6 +37,12 @@
android:label="@string/app_name"
android:theme="@style/Theme.App.Starting"
android:exported="true">
+
+
+
+
+
+
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java
index 1ebd68fa1..1a235f4c1 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java
@@ -26,18 +26,13 @@
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.Menu;
import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.ColorInt;
@@ -46,7 +41,6 @@
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
-import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
@@ -67,6 +61,9 @@
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
+import com.nextcloud.android.common.core.utils.ecosystem.AccountReceiverCallback;
+import com.nextcloud.android.common.core.utils.ecosystem.EcosystemApp;
+import com.nextcloud.android.common.core.utils.ecosystem.EcosystemManager;
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.exceptions.AccountImportCancelledException;
@@ -76,16 +73,16 @@
import com.nextcloud.android.sso.exceptions.TokenMismatchException;
import com.nextcloud.android.sso.exceptions.UnknownErrorException;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import org.jetbrains.annotations.NotNull;
import java.net.HttpURLConnection;
-import java.util.Arrays;
import java.util.LinkedList;
-import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
-import hct.Hct;
import it.niedermann.android.util.ColorUtil;
import it.niedermann.owncloud.notes.LockedActivity;
import it.niedermann.owncloud.notes.NotesApplication;
@@ -121,6 +118,7 @@
import it.niedermann.owncloud.notes.shared.model.NavigationCategory;
import it.niedermann.owncloud.notes.shared.model.NoteClickListener;
import it.niedermann.owncloud.notes.shared.util.CustomAppGlideModule;
+import it.niedermann.owncloud.notes.shared.util.DisplayUtils;
import it.niedermann.owncloud.notes.shared.util.NoteUtil;
import it.niedermann.owncloud.notes.shared.util.ShareUtil;
import it.niedermann.owncloud.notes.util.LinkHelper;
@@ -133,6 +131,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
protected MainViewModel mainViewModel;
+ private EcosystemManager ecosystemManager;
+
private boolean gridView = true;
public static final String ADAPTER_KEY_RECENT = "recent";
@@ -173,6 +173,8 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(binding.getRoot());
+ ecosystemManager = new EcosystemManager(this);
+ handleEcosystemIntent(getIntent());
this.coordinatorLayout = binding.activityNotesListView.activityNotesListView;
this.swipeRefreshLayout = binding.activityNotesListView.swiperefreshlayout;
this.fabCreate = binding.activityNotesListView.fabCreate;
@@ -379,12 +381,20 @@ private void setupDrawerAppMenu() {
}
private void setupDrawerAppMenuListener() {
- // Add listeners to the ecosystem items to launch the app or app-store
- binding.drawerEcosystemFiles.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_FILES, mainViewModel.getCurrentAccount().getValue().getAccountName(), this));
- binding.drawerEcosystemTalk.setOnClickListener(v -> LinkHelper.INSTANCE.openAppOrStore(LinkHelper.APP_NEXTCLOUD_TALK, mainViewModel.getCurrentAccount().getValue().getAccountName(), this));
+ binding.drawerEcosystemFiles.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.FILES, getAccountName()));
+ binding.drawerEcosystemTalk.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.TALK, getAccountName()));
binding.drawerEcosystemMore.setOnClickListener(v -> LinkHelper.INSTANCE.openAppStore("Nextcloud", true, this));
}
+ private String getAccountName() {
+ final var currentAccount = mainViewModel.getCurrentAccount().getValue();
+ if (currentAccount == null) {
+ return null;
+ }
+
+ return currentAccount.getAccountName();
+ }
+
private void themeDrawerAppMenu(int color) {
ColorStateList colorStateList = ColorStateList.valueOf(color);
binding.drawerEcosystemFilesIcon.setImageTintList(colorStateList);
@@ -482,6 +492,26 @@ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
mainViewModel.restoreInstanceState();
}
+ private void handleEcosystemIntent(Intent intent) {
+ ecosystemManager.receiveAccount(intent, new AccountReceiverCallback() {
+ @Override
+ public void onAccountReceived(@NotNull String accountName) {
+ final var account = mainViewModel.getAccountByName(accountName);
+ if (account != null) {
+ onAccountChosen(account);
+ } else {
+ Log_OC.w(TAG, "account not found");
+ DisplayUtils.showSnackMessage(MainActivity.this, R.string.account_not_found);
+ }
+ }
+
+ @Override
+ public void onAccountError(@NotNull String reason) {
+ Log_OC.w(TAG, "handleEcosystemIntent: " + reason);
+ }
+ });
+ }
+
private void setupToolbars() {
setSupportActionBar(binding.activityNotesListView.searchToolbar);
activityBinding.searchBar.homeToolbar.setOnClickListener((v) -> {
@@ -754,6 +784,7 @@ protected void onNewIntent(Intent intent) {
activityBinding.searchView.setQuery(intent.getStringExtra(SearchManager.QUERY), true);
}
super.onNewIntent(intent);
+ handleEcosystemIntent(intent);
}
@Override
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java
index bae942e5a..771cb42a4 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java
@@ -126,6 +126,10 @@ public LiveData getCurrentAccount() {
return distinctUntilChanged(currentAccount);
}
+ public Account getAccountByName(String accountName) {
+ return repo.getAccountByName(accountName);
+ }
+
public void postCurrentAccount(@NonNull Account account) {
state.set(KEY_CURRENT_ACCOUNT, account);
BrandingUtil.saveBrandColor(getApplication(), account.getColor());
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/LinkHelper.kt b/app/src/main/java/it/niedermann/owncloud/notes/util/LinkHelper.kt
index 365f3d708..0c9be9e91 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/LinkHelper.kt
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/LinkHelper.kt
@@ -10,10 +10,7 @@ package it.niedermann.owncloud.notes.util
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
-import android.net.Uri
import androidx.core.net.toUri
-import com.owncloud.android.lib.common.utils.Log_OC
-import java.util.Locale
/**
* Helper class for opening Nextcloud apps if present
@@ -21,35 +18,8 @@ import java.util.Locale
* in case the app is not yet installed on the device.
*/
object LinkHelper {
- const val APP_NEXTCLOUD_FILES = "com.nextcloud.client"
- const val APP_NEXTCLOUD_NOTES = "it.niedermann.owncloud.notes"
- const val APP_NEXTCLOUD_TALK = "com.nextcloud.talk2"
- const val KEY_ACCOUNT: String = "KEY_ACCOUNT"
private const val TAG = "LinkHelper"
- /**
- * Open specified app and, if not installed redirect to corresponding download.
- *
- * @param packageName of app to be opened
- * @param userHash to pass in intent
- */
- fun openAppOrStore(
- packageName: String,
- userHash: String?,
- context: Context,
- ) {
- val intent = context.packageManager.getLaunchIntentForPackage(packageName)
- if (intent != null) {
- // app installed - open directly
- // TODO handle null user?
- intent.putExtra(KEY_ACCOUNT, userHash)
- context.startActivity(intent)
- } else {
- // app not found - open market (Google Play Store, F-Droid, etc.)
- openAppStore(packageName, false, context)
- }
- }
-
/**
* Open app store page of specified app or search for specified string. Will attempt to open browser when no app
* store is available.
@@ -66,7 +36,7 @@ object LinkHelper {
val intent = Intent(Intent.ACTION_VIEW, "market://$suffix".toUri())
try {
context.startActivity(intent)
- } catch (activityNotFoundException1: ActivityNotFoundException) {
+ } catch (_: ActivityNotFoundException) {
// all is lost: open google play store web page for app
if (!search) {
suffix = "apps/$suffix"
@@ -75,58 +45,4 @@ object LinkHelper {
context.startActivity(intent)
}
}
-
- // region Validation
- private const val HTTP = "http"
- private const val HTTPS = "https"
- private const val FILE = "file"
- private const val CONTENT = "content"
-
- /**
- * Validates if a string can be converted to a valid URI
- */
- @Suppress("TooGenericExceptionCaught", "ReturnCount")
- fun validateAndGetURI(uriString: String?): Uri? {
- if (uriString.isNullOrBlank()) {
- Log_OC.w(TAG, "Given uriString is null or blank")
- return null
- }
-
- return try {
- val uri = uriString.toUri()
- if (uri.scheme == null) {
- return null
- }
-
- val validSchemes = listOf(HTTP, HTTPS, FILE, CONTENT)
- if (uri.scheme in validSchemes) uri else null
- } catch (e: Exception) {
- Log_OC.e(TAG, "Invalid URI string: $uriString -- $e")
- null
- }
- }
-
- /**
- * Validates if a URL string is valid
- */
- @Suppress("TooGenericExceptionCaught", "ReturnCount")
- fun validateAndGetURL(url: String?): String? {
- if (url.isNullOrBlank()) {
- Log_OC.w(TAG, "Given url is null or blank")
- return null
- }
-
- return try {
- val uri = url.toUri()
- if (uri.scheme == null) {
- return null
- }
- val validSchemes = listOf(HTTP, HTTPS)
- if (uri.scheme in validSchemes) url else null
- } catch (e: Exception) {
- Log_OC.e(TAG, "Invalid URL: $url -- $e")
- null
- }
- }
- // endregion
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 17a1de26c..3dfe25173 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -520,4 +520,5 @@
Sharing Details
Share expires on %1$s
Dismiss
+ Account not found!
diff --git a/build.gradle b/build.gradle
index 7142dd7f4..2100c808a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
kotlinVersion = '2.3.0'
commonsVersion = '2.4.1'
androidCommonsVersion = '1.1.1'
- nextcloudAndroidCommonLib = "0.31.0"
+ nextcloudAndroidCommonLib = "3babd42636"
singleSignOnVersion = "1.3.4"
}
repositories {
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 1ad09525e..5be15792c 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -806,6 +806,11 @@
+
+
+
+
+
@@ -12760,17 +12765,14 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -12939,6 +12941,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -12971,6 +12989,14 @@
+
+
+
+
+
+
+
+
@@ -13139,6 +13165,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13175,6 +13217,14 @@
+
+
+
+
+
+
+
+
@@ -13343,6 +13393,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13375,6 +13441,14 @@
+
+
+
+
+
+
+
+