Add support for custom tabs and improve various things (#1019)

Adds support for Custom Tabs (at laest supported by Chrome and Firefox).
This is also useful if you set the app as default app for links from the supported Gitea instances.
If you then try to use the "Open in browser" buttons, this will just open the link in GitNex itself.
With Custom Tabs, the links are opened as Custom Tabs (only if the default browser supports them).
I also deleted the unused `OpenRepoInBrowserActivity` and added the mechanism to open an URL in the browser to the `AppUtil`.

I also improved the setting switches:
* hide settings if required settings are disabled (only notification settings)
* allow click on full layouts

Co-authored-by: qwerty287 <ndev@web.de>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1019
Reviewed-by: 6543 <6543@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
qwerty287 2021-12-17 20:56:12 +01:00 committed by 6543
parent 76fae56b87
commit 5550c153f2
17 changed files with 131 additions and 91 deletions

View File

@ -113,5 +113,6 @@ dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'com.github.chrisvest:stormpot:2.4.2'
implementation 'androidx.browser:browser:1.3.0'
}

View File

@ -105,9 +105,6 @@
<activity
android:name=".activities.CreateOrganizationActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.OpenRepoInBrowserActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />
<activity
android:name=".activities.FileDiffActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" />

View File

@ -346,13 +346,7 @@ public class DeepLinksActivity extends BaseActivity {
.withPort(port)
.toUri();
Intent intentBrowser = new Intent();
intentBrowser.setAction(Intent.ACTION_VIEW);
intentBrowser.addCategory(Intent.CATEGORY_BROWSABLE);
intentBrowser.setData(Uri.parse(String.valueOf(host)));
startActivity(intentBrowser);
AppUtil.openUrlInBrowser(this, String.valueOf(host));
finish();
});

View File

@ -1,55 +0,0 @@
package org.mian.gitnex.activities;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.PathsHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.net.URI;
import java.net.URISyntaxException;
import io.mikael.urlbuilder.UrlBuilder;
/**
* Author M M Arif
*/
public class OpenRepoInBrowserActivity extends AppCompatActivity {
private Context appCtx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
appCtx = getApplicationContext();
TinyDB tinyDb = TinyDB.getInstance(appCtx);
try {
URI instanceUrl = new URI(UrlBuilder.fromString(tinyDb.getString("instanceUrl"))
.withPath("/")
.toString());
String browserPath = PathsHelper.join(instanceUrl.getPath(), getIntent().getStringExtra("repoFullNameBrowser"));
String browserUrl = UrlBuilder.fromUri(instanceUrl)
.withPath(browserPath)
.toString();
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(browserUrl));
startActivity(i);
finish();
}
catch(URISyntaxException e) {
Toasty.error(appCtx, getString(R.string.genericError));
}
}
}

View File

@ -46,6 +46,7 @@ import org.mian.gitnex.fragments.MilestonesFragment;
import org.mian.gitnex.fragments.PullRequestsFragment;
import org.mian.gitnex.fragments.ReleasesFragment;
import org.mian.gitnex.fragments.RepoInfoFragment;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
@ -419,9 +420,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class));
break;
case "openWebRepo":
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(tinyDB.getString("repoHtmlUrl")));
startActivity(i);
AppUtil.openUrlInBrowser(this, tinyDB.getString("repoHtmlUrl"));
break;
case "shareRepo":

View File

@ -98,6 +98,7 @@ public class SettingsAppearanceActivity extends BaseActivity {
tinyDB.putBoolean("enableCounterBadges", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
activitySettingsAppearanceBinding.counterBadgeFrame.setOnClickListener(v -> counterBadgesSwitch.setChecked(!counterBadgesSwitch.isChecked()));
// theme selection dialog
themeFrame.setOnClickListener(view -> {

View File

@ -36,6 +36,8 @@ public class SettingsDraftsActivity extends BaseActivity {
tinyDB.putBoolean("draftsCommentsDeletionEnabled", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
activitySettingsDraftsBinding.enableDraftsCommentsDeletion.setOnClickListener(
v -> activitySettingsDraftsBinding.commentsDeletionSwitch.setChecked(!activitySettingsDraftsBinding.commentsDeletionSwitch.isChecked()));
}

View File

@ -2,7 +2,9 @@ package org.mian.gitnex.activities;
import android.os.Bundle;
import android.view.View;
import android.widget.CompoundButton;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.switchmaterial.SwitchMaterial;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsGeneralBinding;
import org.mian.gitnex.helpers.Toasty;
@ -139,6 +141,15 @@ public class SettingsGeneralActivity extends BaseActivity {
dlDialog.show();
});
// link handler
// custom tabs
viewBinding.switchTabs.setChecked(tinyDB.getBoolean("useCustomTabs"));
viewBinding.switchTabs.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("useCustomTabs", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
viewBinding.customTabsFrame.setOnClickListener(v -> viewBinding.switchTabs.setChecked(!viewBinding.switchTabs.isChecked()));
// custom tabs
}
private void initCloseListener() { onClickListener = view -> finish(); }

View File

@ -8,6 +8,7 @@ import androidx.appcompat.app.AlertDialog;
import com.pes.androidmaterialcolorpickerdialog.ColorPicker;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsNotificationsBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.notifications.Notifications;
@ -40,19 +41,46 @@ public class SettingsNotificationsActivity extends BaseActivity {
viewBinding.enableLightsMode.setChecked(tinyDB.getBoolean("notificationsEnableLights", true));
viewBinding.enableVibrationMode.setChecked(tinyDB.getBoolean("notificationsEnableVibration", true));
if(!viewBinding.enableNotificationsMode.isChecked()) {
AppUtil.setMultiVisibility(View.GONE,
viewBinding.chooseColorFrame,
viewBinding.enableLightsFrame,
viewBinding.enableVibrationFrame,
viewBinding.pollingDelayFrame
);
}
if(!viewBinding.enableLightsMode.isChecked()) {
viewBinding.chooseColorFrame.setVisibility(View.GONE);
}
viewBinding.enableNotificationsMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("notificationsEnabled", isChecked);
if(isChecked) {
Notifications.startWorker(ctx);
AppUtil.setMultiVisibility(View.VISIBLE,
viewBinding.chooseColorFrame,
viewBinding.enableLightsFrame,
viewBinding.enableVibrationFrame,
viewBinding.pollingDelayFrame
);
} else {
Notifications.stopWorker(ctx);
AppUtil.setMultiVisibility(View.GONE,
viewBinding.chooseColorFrame,
viewBinding.enableLightsFrame,
viewBinding.enableVibrationFrame,
viewBinding.pollingDelayFrame
);
}
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
viewBinding.enableNotificationsFrame.setOnClickListener(
v -> viewBinding.enableNotificationsMode.setChecked(!viewBinding.enableNotificationsMode.isChecked()));
// polling delay
viewBinding.pollingDelayFrame.setOnClickListener(v -> {
@ -88,10 +116,17 @@ public class SettingsNotificationsActivity extends BaseActivity {
// lights switcher
viewBinding.enableLightsMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
if(!isChecked) {
viewBinding.chooseColorFrame.setVisibility(View.GONE);
} else {
viewBinding.chooseColorFrame.setVisibility(View.VISIBLE);
}
tinyDB.putBoolean("notificationsEnableLights", isChecked);
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
viewBinding.enableLightsFrame.setOnClickListener(v -> viewBinding.enableLightsMode.setChecked(!viewBinding.enableLightsMode.isChecked()));
// lights color chooser
viewBinding.chooseColorFrame.setOnClickListener(v -> {
@ -117,6 +152,8 @@ public class SettingsNotificationsActivity extends BaseActivity {
Toasty.info(appCtx, getResources().getString(R.string.settingsSave));
});
viewBinding.enableVibrationFrame.setOnClickListener(
v -> viewBinding.enableVibrationMode.setChecked(!viewBinding.enableVibrationMode.isChecked()));
}

View File

@ -36,6 +36,8 @@ public class SettingsReportsActivity extends BaseActivity {
tinyDB.putBoolean("crashReportingEnabled", isChecked);
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
activitySettingsReportsBinding.enableSendReports.setOnClickListener(
v -> activitySettingsReportsBinding.crashReportsSwitch.setChecked(!activitySettingsReportsBinding.crashReportsSwitch.isChecked()));
}
private void initCloseListener() {

View File

@ -148,6 +148,8 @@ public class SettingsSecurityActivity extends BaseActivity {
});
activitySettingsSecurityBinding.biometricFrame.setOnClickListener(v -> switchBiometric.setChecked(!switchBiometric.isChecked()));
// clear cache setter
File cacheDir = appCtx.getCacheDir();
clearCacheSelected.setText(FileUtils.byteCountToDisplaySize((int) FileUtils.sizeOfDirectory(cacheDir)));

View File

@ -10,6 +10,7 @@ import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsTranslationBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Toasty;
import java.util.LinkedHashMap;
import java.util.Locale;
@ -50,13 +51,7 @@ public class SettingsTranslationActivity extends BaseActivity {
LinearLayout langFrame = activitySettingsTranslationBinding.langFrame;
helpTranslate.setOnClickListener(v12 -> {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink)));
startActivity(intent);
AppUtil.openUrlInBrowser(this, getResources().getString(R.string.crowdInLink));
});
tvLanguageSelected.setText(tinyDB.getString("localeStr"));

View File

@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.vdurmont.emoji.EmojiParser;
import org.gitnex.tea4j.models.Commits;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
@ -114,7 +115,7 @@ public class CommitsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
if(timeFormat.equals("pretty")) {
commitDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(commitsModel.getCommit().getCommitter().getDate()), context));
}
commitHtmlUrl.setOnClickListener(v -> context.startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(commitsModel.getHtml_url()))));
commitHtmlUrl.setOnClickListener(v -> AppUtil.openUrlInBrowser(context, commitsModel.getHtml_url()));
}
}

View File

@ -91,27 +91,15 @@ public class SettingsFragment extends Fragment {
aboutAppDialogBinding.userServerVersion.setText(tinyDB.getString("giteaVersion"));
aboutAppDialogBinding.donationLinkPatreon.setOnClickListener(v12 -> {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.supportLinkPatreon)));
startActivity(intent);
AppUtil.openUrlInBrowser(requireContext(), getResources().getString(R.string.supportLinkPatreon));
});
aboutAppDialogBinding.translateLink.setOnClickListener(v13 -> {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink)));
startActivity(intent);
AppUtil.openUrlInBrowser(requireContext(), getResources().getString(R.string.crowdInLink));
});
aboutAppDialogBinding.appWebsite.setOnClickListener(v14 -> {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(getResources().getString(R.string.appWebsiteLink)));
startActivity(intent);
AppUtil.openUrlInBrowser(requireContext(), getResources().getString(R.string.appWebsiteLink));
});
if(AppUtil.isPro(requireContext())) {

View File

@ -3,16 +3,22 @@ package org.mian.gitnex.helpers;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
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;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.pm.PackageInfoCompat;
import org.mian.gitnex.R;
import org.mian.gitnex.database.models.UserAccount;
import java.io.IOException;
import java.io.InputStream;
@ -343,4 +349,30 @@ public class AppUtil {
}
public static void openUrlInBrowser(Context context, String url) {
TinyDB tinyDB = TinyDB.getInstance(context);
try {
if(tinyDB.getBoolean("useCustomTabs")) {
new CustomTabsIntent
.Builder()
.setDefaultColorSchemeParams(
new CustomTabColorSchemeParams.Builder()
.setToolbarColor(getColorFromAttribute(context, R.attr.primaryBackgroundColor))
.setNavigationBarColor(getColorFromAttribute(context, R.attr.primaryBackgroundColor))
.setSecondaryToolbarColor(R.attr.primaryTextColor)
.build()
)
.build()
.launchUrl(context, Uri.parse(url));
} else {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(tinyDB.getString("repoHtmlUrl")));
i.addCategory(Intent.CATEGORY_BROWSABLE);
context.startActivity(i);
}
} catch(Exception e) {
Toasty.error(context, context.getString(R.string.genericError));
}
}
}

View File

@ -123,4 +123,36 @@
</LinearLayout>
<RelativeLayout
android:id="@+id/customTabsFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/customTabsHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginEnd="24dp"
android:text="@string/useCustomTabs"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switchTabs"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:layout_toEndOf="@+id/customTabsHeader"
android:gravity="end"
android:paddingStart="0dp"
android:paddingEnd="24dp"
android:switchMinWidth="56dp" />
</RelativeLayout>
</LinearLayout>

View File

@ -750,4 +750,5 @@
<string name="updateStrategyRebase">Rebase</string>
<string name="selectUpdateStrategy">Select Update Strategy</string>
<string name="userAvatar">Avatar</string>
<string name="useCustomTabs">Use Custom Tabs</string>
</resources>