mirror of https://codeberg.org/gitnex/GitNex.git
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 <ndev@web.de> 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 <qwerty287@noreply.codeberg.org> Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
parent
b31a36d880
commit
23704e62d8
|
@ -88,8 +88,10 @@ public class DeepLinksActivity extends BaseActivity {
|
||||||
|
|
||||||
currentInstance = userAccount.getInstanceUrl();
|
currentInstance = userAccount.getInstanceUrl();
|
||||||
instanceToken = userAccount.getToken();
|
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;
|
accountFound = true;
|
||||||
|
|
||||||
|
@ -151,8 +153,13 @@ public class DeepLinksActivity extends BaseActivity {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
else if(!data.getPathSegments().get(0).equals("") & !data.getLastPathSegment().equals("")) { // go to repo
|
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(() ->
|
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
|
else { // no action, show options
|
||||||
showNoActionButtons();
|
showNoActionButtons();
|
||||||
|
|
|
@ -19,9 +19,13 @@ import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import org.gitnex.tea4j.models.Files;
|
import org.gitnex.tea4j.models.Files;
|
||||||
import org.mian.gitnex.R;
|
import org.mian.gitnex.R;
|
||||||
|
import org.mian.gitnex.activities.DeepLinksActivity;
|
||||||
import org.mian.gitnex.activities.FileViewActivity;
|
import org.mian.gitnex.activities.FileViewActivity;
|
||||||
import org.mian.gitnex.activities.RepoDetailActivity;
|
import org.mian.gitnex.activities.RepoDetailActivity;
|
||||||
import org.mian.gitnex.adapters.FilesAdapter;
|
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.databinding.FragmentFilesBinding;
|
||||||
import org.mian.gitnex.helpers.AppUtil;
|
import org.mian.gitnex.helpers.AppUtil;
|
||||||
import org.mian.gitnex.helpers.Authorization;
|
import org.mian.gitnex.helpers.Authorization;
|
||||||
|
@ -29,6 +33,7 @@ import org.mian.gitnex.helpers.Path;
|
||||||
import org.mian.gitnex.viewmodels.FilesViewModel;
|
import org.mian.gitnex.viewmodels.FilesViewModel;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import moe.feng.common.view.breadcrumbs.DefaultBreadcrumbsCallback;
|
import moe.feng.common.view.breadcrumbs.DefaultBreadcrumbsCallback;
|
||||||
import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem;
|
import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem;
|
||||||
|
|
||||||
|
@ -183,12 +188,46 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "file":
|
case "file":
|
||||||
|
case "symlink":
|
||||||
Intent intent = new Intent(getContext(), FileViewActivity.class);
|
Intent intent = new Intent(getContext(), FileViewActivity.class);
|
||||||
intent.putExtra("file", file);
|
intent.putExtra("file", file);
|
||||||
|
|
||||||
requireContext().startActivity(intent);
|
requireContext().startActivity(intent);
|
||||||
break;
|
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<UserAccount> 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);
|
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().clear();
|
||||||
filesAdapter.getOriginalFiles().addAll(filesListMain2);
|
filesAdapter.getOriginalFiles().addAll(filesListMain2);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.mian.gitnex.helpers;
|
package org.mian.gitnex.helpers;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -8,7 +9,6 @@ import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Color;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
@ -370,9 +370,45 @@ public class AppUtil {
|
||||||
i.addCategory(Intent.CATEGORY_BROWSABLE);
|
i.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||||
context.startActivity(i);
|
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));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -751,4 +751,5 @@
|
||||||
<string name="selectUpdateStrategy">Select Update Strategy</string>
|
<string name="selectUpdateStrategy">Select Update Strategy</string>
|
||||||
<string name="userAvatar">Avatar</string>
|
<string name="userAvatar">Avatar</string>
|
||||||
<string name="useCustomTabs">Use Custom Tabs</string>
|
<string name="useCustomTabs">Use Custom Tabs</string>
|
||||||
|
<string name="browserOpenFailed">No application found to open this link. SSH URLs and URLs with another prefix the http:// or https:// are not supported by most browser</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue