From 23704e62d8fff0e6c9a01912a117b3c12ea586b2 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 1 Jan 2022 00:46:10 +0100 Subject: [PATCH] Allow clicks on submodules and symlinks (#1018) Allows clicks on submodules and symlinks in the file browser. Symlinks opens the file viewer which will view the link target (same behavior as Gitea) Submodules will redirect to the repository from where they are Co-authored-by: qwerty287 Co-authored-by: 6543 <6543@obermui.de> Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1018 Reviewed-by: 6543 <6543@obermui.de> Co-authored-by: qwerty287 Co-committed-by: qwerty287 --- .../gitnex/activities/DeepLinksActivity.java | 11 ++++- .../mian/gitnex/fragments/FilesFragment.java | 41 ++++++++++++++++- .../java/org/mian/gitnex/helpers/AppUtil.java | 40 +++++++++++++++- app/src/main/res/values/strings.xml | 1 + .../org/mian/gitnex/helpers/AppUtilTest.java | 46 +++++++++++++++++++ 5 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 app/src/test/java/org/mian/gitnex/helpers/AppUtilTest.java diff --git a/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java b/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java index b20dc743..d00ed17d 100644 --- a/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java @@ -88,8 +88,10 @@ public class DeepLinksActivity extends BaseActivity { currentInstance = userAccount.getInstanceUrl(); instanceToken = userAccount.getToken(); + String host = data.getHost(); + if (host == null) host = ""; - if(hostUri.toLowerCase().contains(Objects.requireNonNull(data.getHost().toLowerCase()))) { + if(hostUri.toLowerCase().contains(host.toLowerCase())) { accountFound = true; @@ -151,8 +153,13 @@ public class DeepLinksActivity extends BaseActivity { finish(); } else if(!data.getPathSegments().get(0).equals("") & !data.getLastPathSegment().equals("")) { // go to repo + String repo = data.getLastPathSegment(); + if (repo.endsWith(".git")) { // Git clone URL + repo = repo.substring(0, repo.length() - 4); + } + String finalRepo = repo; new Handler(Looper.getMainLooper()).postDelayed(() -> - goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getLastPathSegment(), "repo"), 500); + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), finalRepo, "repo"), 500); } else { // no action, show options showNoActionButtons(); diff --git a/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java index 7e8bfa6d..da9a28d3 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java @@ -19,9 +19,13 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import org.gitnex.tea4j.models.Files; import org.mian.gitnex.R; +import org.mian.gitnex.activities.DeepLinksActivity; import org.mian.gitnex.activities.FileViewActivity; import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.adapters.FilesAdapter; +import org.mian.gitnex.database.api.BaseApi; +import org.mian.gitnex.database.api.UserAccountsApi; +import org.mian.gitnex.database.models.UserAccount; import org.mian.gitnex.databinding.FragmentFilesBinding; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Authorization; @@ -29,6 +33,7 @@ import org.mian.gitnex.helpers.Path; import org.mian.gitnex.viewmodels.FilesViewModel; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import moe.feng.common.view.breadcrumbs.DefaultBreadcrumbsCallback; import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem; @@ -183,12 +188,46 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter break; case "file": + case "symlink": Intent intent = new Intent(getContext(), FileViewActivity.class); intent.putExtra("file", file); requireContext().startActivity(intent); break; + case "submodule": + String rawUrl = file.getSubmodule_git_url(); + if(rawUrl == null) { + return; + } + Uri url = AppUtil.getUriFromGitUrl(rawUrl); + String host = url.getHost(); + + + UserAccountsApi userAccountsApi = BaseApi.getInstance(requireContext(), UserAccountsApi.class); + List userAccounts = userAccountsApi.usersAccounts(); + boolean accountFound = false; + + for(UserAccount userAccount : userAccounts) { + Uri instanceUri = Uri.parse(userAccount.getInstanceUrl()); + if(instanceUri.getHost().toLowerCase().equals(host)) { + accountFound = true; + // if scheme is wrong fix it + if (!url.getScheme().equals(instanceUri.getScheme())) { + url = AppUtil.changeScheme(url,instanceUri.getScheme()); + } + break; + } + } + + if(accountFound) { + Intent iLink = new Intent(requireContext(), DeepLinksActivity.class); + iLink.setData(url); + startActivity(iLink); + } else { + AppUtil.openUrlInBrowser(requireContext(), url.toString()); + } + break; } } @@ -229,7 +268,7 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class); - filesModel.getFilesList2(instanceToken, owner, repo, filesDir, ref, getContext(), binding.progressBar, binding.noDataFiles).observe(this, filesListMain2 -> { + filesModel.getFilesList2(instanceToken, owner, repo, filesDir, ref, getContext(), binding.progressBar, binding.noDataFiles).observe(getViewLifecycleOwner(), filesListMain2 -> { filesAdapter.getOriginalFiles().clear(); filesAdapter.getOriginalFiles().addAll(filesListMain2); diff --git a/app/src/main/java/org/mian/gitnex/helpers/AppUtil.java b/app/src/main/java/org/mian/gitnex/helpers/AppUtil.java index 56932528..5e9bb1be 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/AppUtil.java +++ b/app/src/main/java/org/mian/gitnex/helpers/AppUtil.java @@ -1,5 +1,6 @@ package org.mian.gitnex.helpers; +import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -8,7 +9,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Color; import android.net.Uri; import android.util.Base64; import android.util.DisplayMetrics; @@ -370,9 +370,45 @@ public class AppUtil { i.addCategory(Intent.CATEGORY_BROWSABLE); context.startActivity(i); } - } catch(Exception e) { + } catch(ActivityNotFoundException e) { + Toasty.error(context, context.getString(R.string.browserOpenFailed)); + } catch (Exception e) { Toasty.error(context, context.getString(R.string.genericError)); } } + public static Uri getUriFromGitUrl(String url) { + Uri uri = Uri.parse(url); + String host = uri.getHost(); + if(host != null) { + return uri; + } + // must be a SSH URL now + return Uri.parse(getUriHostFromSSHUrl(url)); + } + + public static String getUriHostFromSSHUrl(String url) { + int scheme = url.indexOf("://"); + if (scheme >= 0) { + url = url.substring(scheme+3); + } + + String result = ""; + String[] userHost = url.split("@"); // for a full URL this should be ["//user", "host.tld"] + if(userHost.length < 2) { + result = userHost[0].replace("//", ""); + } else { + result = userHost[1]; + } + return "https://" + result.replace(":", "/"); + } + + public static Uri changeScheme(Uri origin, String scheme) { + String raw = origin.toString(); + int schemeIndex = raw.indexOf("://"); + if (schemeIndex >= 0) { + raw = raw.substring(schemeIndex); + } + return Uri.parse(scheme+raw); + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 74c6a456..9048124e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -751,4 +751,5 @@ Select Update Strategy Avatar Use Custom Tabs + No application found to open this link. SSH URLs and URLs with another prefix the http:// or https:// are not supported by most browser diff --git a/app/src/test/java/org/mian/gitnex/helpers/AppUtilTest.java b/app/src/test/java/org/mian/gitnex/helpers/AppUtilTest.java new file mode 100644 index 00000000..125cf406 --- /dev/null +++ b/app/src/test/java/org/mian/gitnex/helpers/AppUtilTest.java @@ -0,0 +1,46 @@ +package org.mian.gitnex.helpers; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * @author qwerty287 + */ +public class AppUtilTest { + + @Test + public void getFileType() { + assertEquals(AppUtil.FileType.AUDIO, AppUtil.getFileType("mp3")); + assertEquals(AppUtil.FileType.IMAGE, AppUtil.getFileType("png")); + assertEquals(AppUtil.FileType.EXECUTABLE, AppUtil.getFileType("deb")); + assertEquals(AppUtil.FileType.TEXT, AppUtil.getFileType("JSON")); + assertEquals(AppUtil.FileType.DOCUMENT, AppUtil.getFileType("PDF")); + } + + @Test + public void checkStringsWithAlphaNumeric() { + assertEquals(AppUtil.checkStringsWithAlphaNumeric("string"), true); + assertEquals(AppUtil.checkStringsWithAlphaNumeric("123"), true); + assertEquals(AppUtil.checkStringsWithAlphaNumeric("123 with string"), false); + assertEquals(AppUtil.checkStringsWithAlphaNumeric("string 123"), false); + assertEquals(AppUtil.checkStringsWithAlphaNumeric("string-123"), false); + } + + @Test + public void checkIntegers() { + assertEquals(AppUtil.checkIntegers("string"), false); + assertEquals(AppUtil.checkIntegers("123"), true); + assertEquals(AppUtil.checkIntegers("123 with string"), false); + assertEquals(AppUtil.checkIntegers("string 123"), false); + } + + @Test + public void parseSSHUrl() { + assertEquals("https://codeberg.org/gitnex/GitNex", AppUtil.getUriHostFromSSHUrl("ssh://git@codeberg.org:gitnex/GitNex")); + assertEquals("https://codeberg.org/gitnex/GitNex", AppUtil.getUriHostFromSSHUrl("codeberg.org:gitnex/GitNex")); + assertEquals("https://codeberg.org/gitnex/GitNex", AppUtil.getUriHostFromSSHUrl("ssh://git@codeberg.org/gitnex/GitNex")); + assertEquals("https://codeberg.org/gitnex/GitNex.git", AppUtil.getUriHostFromSSHUrl("ssh://git@codeberg.org:gitnex/GitNex.git")); + assertEquals("https://codeberg.org/gitnex/GitNex.git", AppUtil.getUriHostFromSSHUrl("codeberg.org:gitnex/GitNex.git")); + } + +}