From 839c800dc0d7deddf831150d93839125f03da487 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 15 Jan 2026 13:23:17 +0100 Subject: [PATCH 1/7] ecosystem link handle Signed-off-by: alperozturk96 --- .../owncloud/notes/main/MainActivity.java | 31 ++++++- .../owncloud/notes/util/LinkHelper.kt | 86 +------------------ 2 files changed, 30 insertions(+), 87 deletions(-) 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..8238cbd17 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 @@ -67,6 +67,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; @@ -77,10 +80,13 @@ import com.nextcloud.android.sso.exceptions.UnknownErrorException; import com.nextcloud.android.sso.helper.SingleAccountHelper; +import org.jetbrains.annotations.NotNull; + import java.net.HttpURLConnection; import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -133,6 +139,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 +181,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,9 +389,11 @@ private void setupDrawerAppMenu() { } private void setupDrawerAppMenuListener() { + final var accountName = Objects.requireNonNull(mainViewModel.getCurrentAccount().getValue()).getAccountName(); + // 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, accountName)); + binding.drawerEcosystemTalk.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.TALK, accountName)); binding.drawerEcosystemMore.setOnClickListener(v -> LinkHelper.INSTANCE.openAppStore("Nextcloud", true, this)); } @@ -482,6 +494,20 @@ 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) { + + } + + @Override + public void onAccountError(@NotNull String reason) { + + } + }); + } + private void setupToolbars() { setSupportActionBar(binding.activityNotesListView.searchToolbar); activityBinding.searchBar.homeToolbar.setOnClickListener((v) -> { @@ -754,6 +780,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/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 } From 44b27debaccb0d2f428caee32e561dd80eb9004c Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 15 Jan 2026 13:45:40 +0100 Subject: [PATCH 2/7] ecosystem link handle Signed-off-by: alperozturk96 --- .../owncloud/notes/main/MainActivity.java | 26 +++++++--- .../owncloud/notes/main/MainViewModel.java | 4 ++ build.gradle | 2 +- gradle/verification-metadata.xml | 48 ++++++++++++++----- 4 files changed, 61 insertions(+), 19 deletions(-) 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 8238cbd17..512a67be7 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 @@ -79,6 +79,7 @@ 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; @@ -389,14 +390,20 @@ private void setupDrawerAppMenu() { } private void setupDrawerAppMenuListener() { - final var accountName = Objects.requireNonNull(mainViewModel.getCurrentAccount().getValue()).getAccountName(); - - // Add listeners to the ecosystem items to launch the app or app-store - binding.drawerEcosystemFiles.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.FILES, accountName)); - binding.drawerEcosystemTalk.setOnClickListener(v -> ecosystemManager.openApp(EcosystemApp.TALK, accountName)); + 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); @@ -498,12 +505,17 @@ 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) { + mainViewModel.postCurrentAccount(account); + } else { + Log_OC.e(TAG, "account not found"); + } } @Override public void onAccountError(@NotNull String reason) { - + Log_OC.e(TAG,"on account error: " + reason); } }); } 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/build.gradle b/build.gradle index 7142dd7f4..52286d303 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 = "476368a869" singleSignOnVersion = "1.3.4" } repositories { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 1ad09525e..c6136e5f8 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -806,6 +806,11 @@ + + + + + @@ -12760,17 +12765,14 @@ - - - - - - - - + + + + + + + + @@ -12939,6 +12941,14 @@ + + + + + + + + @@ -13139,6 +13149,14 @@ + + + + + + + + @@ -13343,6 +13361,14 @@ + + + + + + + + From 5a5e30e28f227a7b252f2b9a2640c188b38e22ee Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 15 Jan 2026 13:45:54 +0100 Subject: [PATCH 3/7] ecosystem link handle Signed-off-by: alperozturk96 --- .../niedermann/owncloud/notes/main/MainActivity.java | 10 ---------- 1 file changed, 10 deletions(-) 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 512a67be7..96f323979 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; @@ -84,15 +78,11 @@ import org.jetbrains.annotations.NotNull; import java.net.HttpURLConnection; -import java.util.Arrays; import java.util.LinkedList; -import java.util.List; -import java.util.Objects; 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; From 623b91f0be56cd3f517873954d42a9e1cd455efd Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 15 Jan 2026 14:39:58 +0100 Subject: [PATCH 4/7] ecosystem link handle Signed-off-by: alperozturk96 --- app/src/main/AndroidManifest.xml | 6 +++++ .../owncloud/notes/main/MainActivity.java | 2 +- build.gradle | 2 +- gradle/verification-metadata.xml | 24 +++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) 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 96f323979..9c84776fe 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 @@ -505,7 +505,7 @@ public void onAccountReceived(@NotNull String accountName) { @Override public void onAccountError(@NotNull String reason) { - Log_OC.e(TAG,"on account error: " + reason); + Log_OC.w(TAG, "handleEcosystemIntent: " + reason); } }); } diff --git a/build.gradle b/build.gradle index 52286d303..d6380873c 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 = "476368a869" + nextcloudAndroidCommonLib = "c7da76323d" singleSignOnVersion = "1.3.4" } repositories { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c6136e5f8..bf691440e 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -12981,6 +12981,14 @@ + + + + + + + + @@ -13193,6 +13201,14 @@ + + + + + + + + @@ -13401,6 +13417,14 @@ + + + + + + + + From 081feb0e3a27095cf9318b582839c9e1a087b835 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 15 Jan 2026 15:24:46 +0100 Subject: [PATCH 5/7] ecosystem link handle Signed-off-by: alperozturk96 --- build.gradle | 2 +- gradle/verification-metadata.xml | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d6380873c..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 = "c7da76323d" + nextcloudAndroidCommonLib = "3babd42636" singleSignOnVersion = "1.3.4" } repositories { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index bf691440e..5be15792c 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -12941,6 +12941,14 @@ + + + + + + + + @@ -13157,6 +13165,14 @@ + + + + + + + + @@ -13377,6 +13393,14 @@ + + + + + + + + From 5603f88b26485ed046a13aaacabaf97b34f7ecb9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 15 Jan 2026 15:37:50 +0100 Subject: [PATCH 6/7] close drawer after account choosing Signed-off-by: alperozturk96 --- .../java/it/niedermann/owncloud/notes/main/MainActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9c84776fe..5c18602fa 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 @@ -497,7 +497,7 @@ private void handleEcosystemIntent(Intent intent) { public void onAccountReceived(@NotNull String accountName) { final var account = mainViewModel.getAccountByName(accountName); if (account != null) { - mainViewModel.postCurrentAccount(account); + onAccountChosen(account); } else { Log_OC.e(TAG, "account not found"); } From f81b1db873c82f1e9a799f77945ab7455419c6c1 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 16 Jan 2026 09:14:36 +0100 Subject: [PATCH 7/7] inform user when account not found Signed-off-by: alperozturk96 --- .../java/it/niedermann/owncloud/notes/main/MainActivity.java | 4 +++- app/src/main/res/values/strings.xml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) 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 5c18602fa..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 @@ -118,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; @@ -499,7 +500,8 @@ public void onAccountReceived(@NotNull String accountName) { if (account != null) { onAccountChosen(account); } else { - Log_OC.e(TAG, "account not found"); + Log_OC.w(TAG, "account not found"); + DisplayUtils.showSnackMessage(MainActivity.this, R.string.account_not_found); } } 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!