mirror of
https://github.com/gitnex-org/gitnex.git
synced 2026-03-11 17:34:09 -05:00
Gitignores, improve notification badge count, fix home screen selection, libs updates (#1573)
closes #1569 Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1573 Co-authored-by: M M Arif <mmarif@swatian.com> Co-committed-by: M M Arif <mmarif@swatian.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id "com.diffplug.spotless" version "8.1.0"
|
||||
id "com.diffplug.spotless" version "8.2.1"
|
||||
}
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
@@ -8,8 +8,8 @@ android {
|
||||
applicationId = "org.mian.gitnex"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 36
|
||||
versionCode = 1200
|
||||
versionName = "12.0.0"
|
||||
versionCode = 1295
|
||||
versionName = "13.0.0-dev"
|
||||
multiDexEnabled = true
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
compileSdk = 36
|
||||
@@ -82,8 +82,8 @@ dependencies {
|
||||
implementation 'androidx.viewpager2:viewpager2:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "androidx.navigation:navigation-fragment:2.9.6"
|
||||
implementation "androidx.navigation:navigation-ui:2.9.6"
|
||||
implementation "androidx.navigation:navigation-fragment:2.9.7"
|
||||
implementation "androidx.navigation:navigation-ui:2.9.7"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel:2.10.0"
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||
@@ -96,7 +96,7 @@ dependencies {
|
||||
implementation 'com.squareup.retrofit2:converter-scalars:3.0.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.3.2'
|
||||
implementation 'org.ocpsoft.prettytime:prettytime:5.0.7.Final'
|
||||
implementation "com.github.skydoves:colorpickerview:2.3.0"
|
||||
implementation "com.github.skydoves:colorpickerview:2.4.0"
|
||||
implementation "io.noties.markwon:core:4.6.2"
|
||||
implementation "io.noties.markwon:ext-latex:4.6.2"
|
||||
implementation "io.noties.markwon:ext-strikethrough:4.6.2"
|
||||
@@ -125,13 +125,13 @@ dependencies {
|
||||
implementation 'ch.acra:acra-notification:5.13.1'
|
||||
implementation 'androidx.room:room-runtime:2.8.4'
|
||||
annotationProcessor 'androidx.room:room-compiler:2.8.4'
|
||||
implementation "androidx.work:work-runtime:2.11.0"
|
||||
implementation "androidx.work:work-runtime:2.11.1"
|
||||
implementation "io.mikael:urlbuilder:2.0.9"
|
||||
implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2"
|
||||
//noinspection GradleDependency
|
||||
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5"
|
||||
implementation 'androidx.biometric:biometric:1.1.0'
|
||||
//noinspection GradleDependency
|
||||
//noinspection NewerVersionAvailable,GradleDependency
|
||||
implementation 'com.github.chrisvest:stormpot:2.4.2'
|
||||
implementation 'androidx.browser:browser:1.9.0'
|
||||
implementation 'com.google.android.flexbox:flexbox:3.0.0'
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import androidx.annotation.NonNull;
|
||||
import java.util.ArrayList;
|
||||
@@ -16,6 +17,8 @@ import org.gitnex.tea4j.v2.models.CreateRepoOption;
|
||||
import org.gitnex.tea4j.v2.models.Organization;
|
||||
import org.gitnex.tea4j.v2.models.Repository;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.api.clients.ApiRetrofitClient;
|
||||
import org.mian.gitnex.api.models.license.License;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import org.mian.gitnex.databinding.ActivityCreateRepoBinding;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
@@ -25,21 +28,23 @@ import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
|
||||
/**
|
||||
* @author M M Arif
|
||||
* @author mmarif
|
||||
*/
|
||||
public class CreateRepoActivity extends BaseActivity {
|
||||
|
||||
// https://github.com/go-gitea/gitea/blob/52cfd2743c0e85b36081cf80a850e6a5901f1865/models/repo.go#L964-L967
|
||||
final List<String> reservedRepoNames = Arrays.asList(".", "..");
|
||||
final Pattern reservedRepoPatterns = Pattern.compile("\\.(git|wiki)$");
|
||||
List<String> organizationsList = new ArrayList<>();
|
||||
List<String> issueLabelsList = new ArrayList<>();
|
||||
List<String> licenseList = new ArrayList<>();
|
||||
List<String> licenseDisplayList = new ArrayList<>();
|
||||
List<String> licenseKeyList = new ArrayList<>();
|
||||
List<String> gitignoreList = new ArrayList<>();
|
||||
private ActivityCreateRepoBinding activityCreateRepoBinding;
|
||||
private String loginUid;
|
||||
private String selectedOwner;
|
||||
private String selectedIssueLabels;
|
||||
private String selectedLicense;
|
||||
private String selectedGitignore;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -59,14 +64,14 @@ public class CreateRepoActivity extends BaseActivity {
|
||||
MenuItem markdown = activityCreateRepoBinding.topAppBar.getMenu().getItem(1);
|
||||
markdown.setVisible(false);
|
||||
|
||||
String[] licenses = getResources().getStringArray(R.array.licenses);
|
||||
Collections.addAll(licenseList, licenses);
|
||||
getLicenses();
|
||||
|
||||
issueLabelsList.add(getString(R.string.advanced));
|
||||
issueLabelsList.add(getString(R.string.defaultText));
|
||||
getIssueLabels();
|
||||
|
||||
getGitignoreTemplates();
|
||||
|
||||
activityCreateRepoBinding.topAppBar.setOnMenuItemClickListener(
|
||||
menuItem -> {
|
||||
int id = menuItem.getItemId();
|
||||
@@ -170,6 +175,10 @@ public class CreateRepoActivity extends BaseActivity {
|
||||
createRepository.setTemplate(repoAsTemplate);
|
||||
createRepository.setLicense(selectedLicense);
|
||||
|
||||
if (selectedGitignore != null && !selectedGitignore.isEmpty()) {
|
||||
createRepository.setGitignores(selectedGitignore);
|
||||
}
|
||||
|
||||
Call<Repository> call;
|
||||
if (selectedOwner.equals(loginUid)) {
|
||||
|
||||
@@ -237,15 +246,127 @@ public class CreateRepoActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
private void getLicenses() {
|
||||
Call<List<License>> call = ApiRetrofitClient.getInstance(ctx).getLicenses();
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<List<License>> call,
|
||||
@NonNull retrofit2.Response<List<License>> response) {
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<License> licenses = response.body();
|
||||
if (!licenses.isEmpty()) {
|
||||
licenseDisplayList.clear();
|
||||
licenseKeyList.clear();
|
||||
|
||||
licenseDisplayList.add(getString(R.string.no_license));
|
||||
licenseKeyList.add("");
|
||||
|
||||
for (License license : licenses) {
|
||||
licenseDisplayList.add(license.getName());
|
||||
licenseKeyList.add(license.getKey());
|
||||
}
|
||||
|
||||
setupLicenseDropdown();
|
||||
} else {
|
||||
hideLicenseDropdown();
|
||||
}
|
||||
} else {
|
||||
hideLicenseDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<License>> call, @NonNull Throwable t) {
|
||||
hideLicenseDropdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupLicenseDropdown() {
|
||||
ArrayAdapter<String> adapter =
|
||||
new ArrayAdapter<>(
|
||||
CreateRepoActivity.this, R.layout.list_spinner_items, licenseList);
|
||||
CreateRepoActivity.this, R.layout.list_spinner_items, licenseDisplayList);
|
||||
|
||||
activityCreateRepoBinding.licenses.setAdapter(adapter);
|
||||
|
||||
activityCreateRepoBinding.licenses.setOnItemClickListener(
|
||||
(parent, view, position, id) -> selectedLicense = licenseList.get(position));
|
||||
(parent, view, position, id) -> {
|
||||
if (position == 0) {
|
||||
selectedLicense = null;
|
||||
} else {
|
||||
selectedLicense = licenseKeyList.get(position);
|
||||
}
|
||||
});
|
||||
|
||||
activityCreateRepoBinding.licenses.setText(licenseDisplayList.get(0), false);
|
||||
selectedLicense = null;
|
||||
}
|
||||
|
||||
private void hideLicenseDropdown() {
|
||||
activityCreateRepoBinding.licenseFrame.setVisibility(View.GONE);
|
||||
selectedLicense = null;
|
||||
}
|
||||
|
||||
private void getGitignoreTemplates() {
|
||||
Call<List<String>> call = ApiRetrofitClient.getInstance(ctx).getGitignoreTemplates();
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<List<String>> call,
|
||||
@NonNull retrofit2.Response<List<String>> response) {
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<String> templates = response.body();
|
||||
if (!templates.isEmpty()) {
|
||||
Collections.sort(templates);
|
||||
gitignoreList.addAll(templates);
|
||||
|
||||
gitignoreList.add(0, getString(R.string.no_template));
|
||||
|
||||
setupGitignoreDropdown();
|
||||
} else {
|
||||
hideGitignoreDropdown();
|
||||
}
|
||||
} else {
|
||||
hideGitignoreDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<String>> call, @NonNull Throwable t) {
|
||||
hideGitignoreDropdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupGitignoreDropdown() {
|
||||
ArrayAdapter<String> adapter =
|
||||
new ArrayAdapter<>(
|
||||
CreateRepoActivity.this, R.layout.list_spinner_items, gitignoreList);
|
||||
|
||||
activityCreateRepoBinding.gitignoreTemplates.setAdapter(adapter);
|
||||
|
||||
activityCreateRepoBinding.gitignoreTemplates.setOnItemClickListener(
|
||||
(parent, view, position, id) -> {
|
||||
if (position == 0) {
|
||||
selectedGitignore = null;
|
||||
} else {
|
||||
selectedGitignore = gitignoreList.get(position);
|
||||
}
|
||||
});
|
||||
|
||||
activityCreateRepoBinding.gitignoreTemplates.setText(gitignoreList.get(0), false);
|
||||
selectedGitignore = null;
|
||||
}
|
||||
|
||||
private void hideGitignoreDropdown() {
|
||||
activityCreateRepoBinding.gitignoreFrame.setVisibility(View.GONE);
|
||||
selectedGitignore = null;
|
||||
}
|
||||
|
||||
private void getOrganizations(final String userLogin) {
|
||||
|
||||
@@ -16,6 +16,8 @@ import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavOptions;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.google.android.material.badge.BadgeDrawable;
|
||||
@@ -44,6 +46,9 @@ import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.helpers.ChangeLog;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.notifications.Notifications;
|
||||
import org.mian.gitnex.notifications.NotificationsBadge;
|
||||
import org.mian.gitnex.notifications.NotificationsBadgeWorker;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
@@ -54,7 +59,7 @@ import retrofit2.Response;
|
||||
public class MainActivity extends BaseActivity
|
||||
implements NotificationsFragment.NotificationCountListener {
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
public ActivityMainBinding binding;
|
||||
private TinyDB tinyDB;
|
||||
private NavController navController;
|
||||
private boolean noConnection;
|
||||
@@ -112,6 +117,13 @@ public class MainActivity extends BaseActivity
|
||||
}
|
||||
}
|
||||
|
||||
loadSavedBadgeCount();
|
||||
if (Boolean.parseBoolean(
|
||||
AppDatabaseSettings.getSettingsValue(
|
||||
this, AppDatabaseSettings.APP_NOTIFICATIONS_KEY))) {
|
||||
Notifications.startBadgeWorker(this);
|
||||
}
|
||||
|
||||
setSupportActionBar(binding.toolbar);
|
||||
binding.toolbar.setVisibility(View.GONE);
|
||||
binding.toolbar.invalidate();
|
||||
@@ -277,6 +289,17 @@ public class MainActivity extends BaseActivity
|
||||
});
|
||||
DetailFragment.refProfile = false;
|
||||
}
|
||||
|
||||
getNotificationsCount();
|
||||
loadSavedBadgeCount();
|
||||
WorkManager.getInstance(this)
|
||||
.enqueue(new OneTimeWorkRequest.Builder(NotificationsBadgeWorker.class).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Notifications.stopBadgeWorker(this);
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
@@ -498,7 +521,7 @@ public class MainActivity extends BaseActivity
|
||||
navController.navigate(R.id.repositoriesFragment, null, navOptions);
|
||||
break;
|
||||
case "org":
|
||||
navController.navigate(R.id.action_to_organizations, null, navOptions);
|
||||
navController.navigate(R.id.organizationsFragment, null, navOptions);
|
||||
break;
|
||||
case "notification":
|
||||
binding.toolbarTitle.setText(
|
||||
@@ -514,7 +537,7 @@ public class MainActivity extends BaseActivity
|
||||
startActivity(intentProfile);
|
||||
break;
|
||||
case "admin":
|
||||
navController.navigate(R.id.action_to_administration, null, navOptions);
|
||||
navController.navigate(R.id.administrationFragment, null, navOptions);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
@@ -538,27 +561,35 @@ public class MainActivity extends BaseActivity
|
||||
}
|
||||
|
||||
private void navigateToDefaultFragment() {
|
||||
int homeScreenValue;
|
||||
try {
|
||||
homeScreenValue =
|
||||
Integer.parseInt(
|
||||
AppDatabaseSettings.getSettingsValue(
|
||||
this, AppDatabaseSettings.APP_HOME_SCREEN_KEY));
|
||||
} catch (NumberFormatException e) {
|
||||
homeScreenValue = 0;
|
||||
}
|
||||
|
||||
NavOptions navOptions =
|
||||
new NavOptions.Builder()
|
||||
.setPopUpTo(R.id.nav_graph, true)
|
||||
.setPopUpTo(navController.getGraph().getId(), true)
|
||||
.setLaunchSingleTop(true)
|
||||
.build();
|
||||
|
||||
switch (Integer.parseInt(
|
||||
AppDatabaseSettings.getSettingsValue(
|
||||
this, AppDatabaseSettings.APP_HOME_SCREEN_KEY))) {
|
||||
switch (homeScreenValue) {
|
||||
case 1:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.navMyRepos));
|
||||
navController.navigate(R.id.nav_graph, null, navOptions);
|
||||
navController.navigate(R.id.myRepositoriesFragment, null, navOptions);
|
||||
break;
|
||||
case 2:
|
||||
binding.toolbarTitle.setText(
|
||||
getResources().getString(R.string.pageTitleStarredRepos));
|
||||
navController.navigate(R.id.action_to_starredRepositories, null, navOptions);
|
||||
navController.navigate(R.id.starredRepositoriesFragment, null, navOptions);
|
||||
break;
|
||||
case 3:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.navOrg));
|
||||
navController.navigate(R.id.action_to_organizations, null, navOptions);
|
||||
navController.navigate(R.id.organizationsFragment, null, navOptions);
|
||||
break;
|
||||
case 4:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.navRepos));
|
||||
@@ -575,15 +606,15 @@ public class MainActivity extends BaseActivity
|
||||
break;
|
||||
case 7:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.navMyIssues));
|
||||
navController.navigate(R.id.action_to_myIssues, null, navOptions);
|
||||
navController.navigate(R.id.myIssuesFragment, null, navOptions);
|
||||
break;
|
||||
case 8:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.navMostVisited));
|
||||
navController.navigate(R.id.action_to_mostVisitedRepos, null, navOptions);
|
||||
navController.navigate(R.id.mostVisitedReposFragment, null, navOptions);
|
||||
break;
|
||||
case 9:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.navNotes));
|
||||
navController.navigate(R.id.action_to_notes, null, navOptions);
|
||||
navController.navigate(R.id.notesFragment, null, navOptions);
|
||||
break;
|
||||
case 10:
|
||||
binding.toolbarTitle.setText(getResources().getString(R.string.activities));
|
||||
@@ -592,7 +623,7 @@ public class MainActivity extends BaseActivity
|
||||
case 11:
|
||||
binding.toolbarTitle.setText(
|
||||
getResources().getString(R.string.navWatchedRepositories));
|
||||
navController.navigate(R.id.action_to_watchedRepositories, null, navOptions);
|
||||
navController.navigate(R.id.watchedRepositoriesFragment, null, navOptions);
|
||||
break;
|
||||
default:
|
||||
navController.navigate(R.id.homeDashboardFragment, null, navOptions);
|
||||
@@ -600,6 +631,37 @@ public class MainActivity extends BaseActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSavedBadgeCount() {
|
||||
TinyDB tinyDB = TinyDB.getInstance(this);
|
||||
int currentAccountId = tinyDB.getInt("currentActiveAccountId", -1);
|
||||
|
||||
if (currentAccountId > 0) {
|
||||
int savedCount = NotificationsBadge.getBadgeCount(this, currentAccountId);
|
||||
if (savedCount > 0) {
|
||||
updateBadgeUI(savedCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBadgeUI(int count) {
|
||||
runOnUiThread(
|
||||
() -> {
|
||||
if (count > 0) {
|
||||
BadgeDrawable badge =
|
||||
binding.bottomNavigation.getOrCreateBadge(
|
||||
R.id.notificationsFragment);
|
||||
badge.setNumber(count);
|
||||
badge.setBackgroundColor(getThemeColor(R.attr.primaryTextColor));
|
||||
badge.setBadgeTextColor(getThemeColor(R.attr.materialCardBackgroundColor));
|
||||
badge.setVisible(true);
|
||||
} else {
|
||||
if (binding.bottomNavigation.getBadge(R.id.notificationsFragment) != null) {
|
||||
binding.bottomNavigation.removeBadge(R.id.notificationsFragment);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getNotificationsCount() {
|
||||
Call<NotificationCount> call = RetrofitClient.getApiInterface(this).notifyNewAvailable();
|
||||
call.enqueue(
|
||||
@@ -608,29 +670,31 @@ public class MainActivity extends BaseActivity
|
||||
public void onResponse(
|
||||
@NonNull Call<NotificationCount> call,
|
||||
@NonNull Response<NotificationCount> response) {
|
||||
NotificationCount notificationCount = response.body();
|
||||
if (response.code() == 200
|
||||
&& notificationCount != null
|
||||
&& notificationCount.getNew() > 0) {
|
||||
BadgeDrawable badge =
|
||||
binding.bottomNavigation.getOrCreateBadge(
|
||||
R.id.notificationsFragment);
|
||||
badge.setNumber(Math.toIntExact(notificationCount.getNew()));
|
||||
badge.setBackgroundColor(getThemeColor(R.attr.primaryTextColor));
|
||||
badge.setBadgeTextColor(
|
||||
getThemeColor(R.attr.materialCardBackgroundColor));
|
||||
if (response.code() == 200 && response.body() != null) {
|
||||
int newCount = Math.toIntExact(response.body().getNew());
|
||||
|
||||
TinyDB tinyDB = TinyDB.getInstance(MainActivity.this);
|
||||
int accountId = tinyDB.getInt("currentActiveAccountId", -1);
|
||||
if (accountId > 0) {
|
||||
NotificationsBadge.saveBadgeCount(
|
||||
MainActivity.this, accountId, newCount);
|
||||
}
|
||||
|
||||
updateBadgeUI(newCount);
|
||||
} else {
|
||||
binding.bottomNavigation.removeBadge(R.id.notificationsFragment);
|
||||
updateBadgeUI(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(
|
||||
@NonNull Call<NotificationCount> call, @NonNull Throwable t) {}
|
||||
@NonNull Call<NotificationCount> call, @NonNull Throwable t) {
|
||||
loadSavedBadgeCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getThemeColor(int attr) {
|
||||
public int getThemeColor(int attr) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
getTheme().resolveAttribute(attr, typedValue, true);
|
||||
return typedValue.data;
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.mian.gitnex.api.clients;
|
||||
|
||||
import java.util.List;
|
||||
import org.mian.gitnex.api.models.contents.RepoGetContentsList;
|
||||
import org.mian.gitnex.api.models.license.License;
|
||||
import org.mian.gitnex.api.models.settings.RepositoryGlobal;
|
||||
import org.mian.gitnex.api.models.topics.Topics;
|
||||
import retrofit2.Call;
|
||||
@@ -44,4 +45,10 @@ public interface ApiInterface {
|
||||
|
||||
@GET("settings/repository") // get repository global settings
|
||||
Call<RepositoryGlobal> getRepositoryGlobalSettings();
|
||||
|
||||
@GET("gitignore/templates") // get all gitignore templates
|
||||
Call<List<String>> getGitignoreTemplates();
|
||||
|
||||
@GET("licenses") // get all licenses
|
||||
Call<List<License>> getLicenses();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.mian.gitnex.api.models.license;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* @author mmarif
|
||||
*/
|
||||
public class License {
|
||||
|
||||
@SerializedName("key")
|
||||
private String key;
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
@SerializedName("url")
|
||||
private String url;
|
||||
|
||||
public License() {}
|
||||
|
||||
public License(String key, String name, String url) {
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
@@ -129,14 +129,12 @@ public class NotificationsFragment extends Fragment
|
||||
.enqueue(
|
||||
(SimpleCallback<List<NotificationThread>>)
|
||||
(call, voidResponse) -> {
|
||||
View fragmentRootView = getView();
|
||||
if (voidResponse.isPresent()
|
||||
&& voidResponse.get().isSuccessful()) {
|
||||
SnackBar.success(
|
||||
context,
|
||||
requireActivity()
|
||||
.findViewById(
|
||||
android.R.id
|
||||
.content),
|
||||
fragmentRootView,
|
||||
getString(
|
||||
R.string
|
||||
.markedNotificationsAsRead));
|
||||
@@ -153,12 +151,7 @@ public class NotificationsFragment extends Fragment
|
||||
"205")) {
|
||||
SnackBar.success(
|
||||
context,
|
||||
requireActivity()
|
||||
.findViewById(
|
||||
android
|
||||
.R
|
||||
.id
|
||||
.content),
|
||||
fragmentRootView,
|
||||
getString(
|
||||
R.string
|
||||
.markedNotificationsAsRead));
|
||||
@@ -175,12 +168,7 @@ public class NotificationsFragment extends Fragment
|
||||
() ->
|
||||
SnackBar.error(
|
||||
context,
|
||||
requireActivity()
|
||||
.findViewById(
|
||||
android
|
||||
.R
|
||||
.id
|
||||
.content),
|
||||
fragmentRootView,
|
||||
getString(
|
||||
R
|
||||
.string
|
||||
|
||||
@@ -68,6 +68,7 @@ public class RepoInfoFragment extends Fragment {
|
||||
private LinearLayout pageContent;
|
||||
private FragmentRepoInfoBinding binding;
|
||||
private RepositoryContext repository;
|
||||
boolean isAdmin;
|
||||
|
||||
public RepoInfoFragment() {}
|
||||
|
||||
@@ -96,6 +97,8 @@ public class RepoInfoFragment extends Fragment {
|
||||
|
||||
setRepoInfo(locale);
|
||||
|
||||
isAdmin = repository.getPermissions() != null && repository.getPermissions().isAdmin();
|
||||
|
||||
loadRepoTopics();
|
||||
binding.addTopicChip.setOnClickListener(v -> showAddTopicDialog());
|
||||
|
||||
@@ -514,19 +517,37 @@ public class RepoInfoFragment extends Fragment {
|
||||
if (isAdded()) {
|
||||
switch (response.code()) {
|
||||
case 200:
|
||||
List<String> topics = new ArrayList<>();
|
||||
if (response.body() != null
|
||||
&& !response.body().getTopics().isEmpty()) {
|
||||
topics = response.body().getTopics();
|
||||
}
|
||||
|
||||
boolean hasTopics = !topics.isEmpty();
|
||||
|
||||
if (hasTopics || isAdmin) {
|
||||
binding.repoTopicsContainer.setVisibility(View.VISIBLE);
|
||||
displayTopics(response.body().getTopics());
|
||||
displayTopics(topics);
|
||||
} else {
|
||||
binding.repoTopicsContainer.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
case 401:
|
||||
AlertDialogs.authorizationTokenRevokedDialog(ctx);
|
||||
if (isAdmin) {
|
||||
binding.repoTopicsContainer.setVisibility(View.VISIBLE);
|
||||
displayTopics(new ArrayList<>());
|
||||
} else {
|
||||
binding.repoTopicsContainer.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
binding.repoTopicsContainer.setVisibility(View.GONE);
|
||||
if (isAdmin) {
|
||||
binding.repoTopicsContainer.setVisibility(View.VISIBLE);
|
||||
displayTopics(new ArrayList<>());
|
||||
} else {
|
||||
binding.repoTopicsContainer.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -535,8 +556,13 @@ public class RepoInfoFragment extends Fragment {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Topics> call, @NonNull Throwable t) {
|
||||
if (isAdded()) {
|
||||
if (isAdmin) {
|
||||
binding.repoTopicsContainer.setVisibility(View.VISIBLE);
|
||||
displayTopics(new ArrayList<>());
|
||||
} else {
|
||||
binding.repoTopicsContainer.setVisibility(View.GONE);
|
||||
}
|
||||
Toasty.error(ctx, ctx.getString(R.string.errorLoadingTopics));
|
||||
binding.repoTopicsContainer.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -573,15 +599,25 @@ public class RepoInfoFragment extends Fragment {
|
||||
plusChip.setStateListAnimator(null);
|
||||
plusChip.setElevation(0f);
|
||||
|
||||
binding.repoTopicsChipGroup.addView(plusChip);
|
||||
if (isAdmin) {
|
||||
binding.repoTopicsChipGroup.addView(plusChip);
|
||||
}
|
||||
}
|
||||
|
||||
private Chip createTopicChip(String topic, int backgroundColor) {
|
||||
Chip chip = new Chip(ctx);
|
||||
chip.setCheckable(false);
|
||||
chip.setClickable(false);
|
||||
chip.setSelected(false);
|
||||
chip.setText(topic);
|
||||
chip.setCloseIconVisible(true);
|
||||
chip.setCloseIconTint(
|
||||
ColorStateList.valueOf(ContextCompat.getColor(ctx, R.color.colorRed)));
|
||||
chip.setCloseIconVisible(isAdmin);
|
||||
|
||||
if (isAdmin) {
|
||||
chip.setCloseIconTint(
|
||||
ColorStateList.valueOf(ContextCompat.getColor(ctx, R.color.colorRed)));
|
||||
chip.setOnCloseIconClickListener(v -> deleteTopic(topic));
|
||||
}
|
||||
|
||||
chip.setChipBackgroundColor(ColorStateList.valueOf(backgroundColor));
|
||||
chip.setTextColor(isLightColor(backgroundColor) ? Color.BLACK : Color.WHITE);
|
||||
|
||||
@@ -593,8 +629,6 @@ public class RepoInfoFragment extends Fragment {
|
||||
getResources().getDimension(R.dimen.dimen8dp))
|
||||
.build());
|
||||
|
||||
chip.setOnCloseIconClickListener(v -> deleteTopic(topic));
|
||||
|
||||
return chip;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,27 @@ public class Notifications {
|
||||
WorkManager.getInstance(context).cancelAllWorkByTag(Constants.notificationsWorkerId);
|
||||
}
|
||||
|
||||
public static void startBadgeWorker(Context context) {
|
||||
Constraints constraints =
|
||||
new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
|
||||
|
||||
PeriodicWorkRequest badgeWorkRequest =
|
||||
new PeriodicWorkRequest.Builder(
|
||||
NotificationsBadgeWorker.class, 15, TimeUnit.MINUTES)
|
||||
.setConstraints(constraints)
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance(context)
|
||||
.enqueueUniquePeriodicWork(
|
||||
"notification_badge_updates",
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
badgeWorkRequest);
|
||||
}
|
||||
|
||||
public static void stopBadgeWorker(Context context) {
|
||||
WorkManager.getInstance(context).cancelUniqueWork("notification_badge_updates");
|
||||
}
|
||||
|
||||
public static void startWorker(Context context) {
|
||||
|
||||
int delay;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.mian.gitnex.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
|
||||
/**
|
||||
* @author mmarif
|
||||
*/
|
||||
public class NotificationsBadge {
|
||||
|
||||
private static final String PREFS_NAME = "notification_badge_prefs";
|
||||
private static final String KEY_PREFIX = "badge_count_";
|
||||
|
||||
public static void saveBadgeCount(Context context, int accountId, int count) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
prefs.edit().putInt(KEY_PREFIX + accountId, count).apply();
|
||||
}
|
||||
|
||||
public static int getBadgeCount(Context context, int accountId) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
return prefs.getInt(KEY_PREFIX + accountId, 0);
|
||||
}
|
||||
|
||||
public static void clearAllBadgeCounts(Context context) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
prefs.edit().clear().apply();
|
||||
}
|
||||
|
||||
public static void updateBadgeUI(Context context, int count) {
|
||||
TinyDB tinyDB = TinyDB.getInstance(context);
|
||||
int accountId = tinyDB.getInt("currentActiveAccountId", -1);
|
||||
if (accountId > 0) {
|
||||
saveBadgeCount(context, accountId, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.mian.gitnex.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import org.gitnex.tea4j.v2.models.NotificationCount;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
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.helpers.TinyDB;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
|
||||
/**
|
||||
* @author mmarif
|
||||
*/
|
||||
public class NotificationsBadgeWorker extends Worker {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public NotificationsBadgeWorker(@NonNull Context context, @NonNull WorkerParameters params) {
|
||||
super(context, params);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Result doWork() {
|
||||
updateNotificationBadgeForAllAccounts();
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private void updateNotificationBadgeForAllAccounts() {
|
||||
UserAccountsApi userAccountsApi = BaseApi.getInstance(context, UserAccountsApi.class);
|
||||
if (userAccountsApi == null) return;
|
||||
|
||||
for (UserAccount account : userAccountsApi.loggedInUserAccounts()) {
|
||||
updateBadgeForAccount(account);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBadgeForAccount(UserAccount account) {
|
||||
try {
|
||||
Call<NotificationCount> call =
|
||||
RetrofitClient.getApiInterface(
|
||||
context,
|
||||
account.getInstanceUrl(),
|
||||
"token " + account.getToken(),
|
||||
null)
|
||||
.notifyNewAvailable();
|
||||
|
||||
Response<NotificationCount> response = call.execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
int newCount = Math.toIntExact(response.body().getNew());
|
||||
|
||||
NotificationsBadge.saveBadgeCount(context, account.getAccountId(), newCount);
|
||||
|
||||
if (isCurrentActiveAccount(account)) {
|
||||
NotificationsBadge.updateBadgeUI(context, newCount);
|
||||
}
|
||||
} else {
|
||||
NotificationsBadge.saveBadgeCount(context, account.getAccountId(), 0);
|
||||
if (isCurrentActiveAccount(account)) {
|
||||
NotificationsBadge.updateBadgeUI(context, 0);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCurrentActiveAccount(UserAccount account) {
|
||||
TinyDB tinyDB = TinyDB.getInstance(context);
|
||||
int currentAccountId = tinyDB.getInt("currentActiveAccountId", -1);
|
||||
return account.getAccountId() == currentAccountId;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="40dp"
|
||||
android:height="40dp" android:autoMirrored="true"
|
||||
android:viewportWidth="40" android:viewportHeight="40">
|
||||
<path android:fillAlpha="0.2" android:fillColor="@color/colorAccent"
|
||||
android:pathData="M20.201,5.169c-8.254,0 -14.946,6.692 -14.946,14.946c0,8.255 6.692,14.946 14.946,14.946s14.946,-6.691 14.946,-14.946C35.146,11.861 28.455,5.169 20.201,5.169zM20.201,31.749c-6.425,0 -11.634,-5.208 -11.634,-11.634c0,-6.425 5.209,-11.634 11.634,-11.634c6.425,0 11.633,5.209 11.633,11.634C31.834,26.541 26.626,31.749 20.201,31.749z"
|
||||
android:strokeAlpha="0.2"/>
|
||||
<path android:fillColor="@color/colorAccent"
|
||||
android:pathData="M26.013,10.047l1.654,-2.866c-2.198,-1.272 -4.743,-2.012 -7.466,-2.012h0v3.312h0C22.32,8.481 24.301,9.057 26.013,10.047z"/>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,1A11,11 0,1 0,23 12,11 11,0 0,0 12,1ZM12,20a8,8 0,1 1,8 -8A8,8 0,0 1,12 20Z"
|
||||
android:strokeAlpha="0.25"
|
||||
android:fillColor="?attr/iconsColor"
|
||||
android:fillAlpha="0.25"/>
|
||||
<path
|
||||
android:pathData="M12,2.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
|
||||
android:fillColor="?attr/iconsColor"/>
|
||||
</vector>
|
||||
|
||||
@@ -169,6 +169,29 @@
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/gitignoreFrame"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen8dp"
|
||||
android:hint="@string/gitignore_template"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/gitignoreTemplates"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="none"
|
||||
android:labelFor="@+id/gitignoreTemplates"
|
||||
android:textColor="?attr/inputTextColor"
|
||||
android:textSize="@dimen/dimen16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/licenseFrame"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:layout_marginBottom="@dimen/dimen16dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
@@ -144,6 +143,7 @@
|
||||
app:cardCornerRadius="@dimen/dimen16dp"
|
||||
app:cardElevation="@dimen/dimen0dp"
|
||||
app:strokeWidth="@dimen/dimen0dp"
|
||||
android:layout_marginTop="@dimen/dimen16dp"
|
||||
android:visibility="gone"
|
||||
app:cardBackgroundColor="@android:color/transparent">
|
||||
|
||||
|
||||
@@ -130,184 +130,4 @@
|
||||
<item>@string/pollingDelay45Minutes</item>
|
||||
<item>@string/pollingDelay1Hour</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="licenses">
|
||||
<item>0BSD</item>
|
||||
<item>AAL</item>
|
||||
<item>ADSL</item>
|
||||
<item>AFL-1.1</item>
|
||||
<item>AFL-1.1</item>
|
||||
<item>AFL-2.0</item>
|
||||
<item>AFL-3.0</item>
|
||||
<item>AGPL-1.0-only</item>
|
||||
<item>AGPL-1.0-or-later</item>
|
||||
<item>AGPL-3.0-only</item>
|
||||
<item>AGPL-3.0-or-later</item>
|
||||
<item>AML</item>
|
||||
<item>APL-1.0</item>
|
||||
<item>APSL-1.0</item>
|
||||
<item>APSL-2.0</item>
|
||||
<item>Adobe-2006</item>
|
||||
<item>Aladdin</item>
|
||||
<item>Apache-1.0</item>
|
||||
<item>Apache-1.1</item>
|
||||
<item>Apache-2.0</item>
|
||||
<item>Artistic-1.0</item>
|
||||
<item>Artistic-2.0</item>
|
||||
<item>BSD-1-Clause</item>
|
||||
<item>BSD-2-Clause</item>
|
||||
<item>BSD-2-Clause-Patent</item>
|
||||
<item>BSD-2-Clause-Views</item>
|
||||
<item>BSD-3-Clause</item>
|
||||
<item>BSD-3-Clause-Attribution</item>
|
||||
<item>BSD-3-Clause-Clear</item>
|
||||
<item>BSD-3-Clause-LBNL</item>
|
||||
<item>BSD-3-Clause-Modification</item>
|
||||
<item>BSD-3-Clause-No-Military-License</item>
|
||||
<item>BSD-3-Clause-No-Nuclear-License</item>
|
||||
<item>BSD-3-Clause-No-Nuclear-License-2014</item>
|
||||
<item>BSD-3-Clause-No-Nuclear-Warranty</item>
|
||||
<item>BSD-3-Clause-Open-MPI</item>
|
||||
<item>BSD-3-Clause-Sun</item>
|
||||
<item>BSD-4-Clause-Shortened</item>
|
||||
<item>BSD-4-Clause-UC</item>
|
||||
<item>BSD-4.3RENO</item>
|
||||
<item>BSD-4.3TAHOE</item>
|
||||
<item>BSD-Advertising-Acknowledgement</item>
|
||||
<item>BSD-Attribution-HPND-disclaimer</item>
|
||||
<item>BSD-Protection</item>
|
||||
<item>BSD-Source-Code</item>
|
||||
<item>BSD-Systemics</item>
|
||||
<item>BitTorrent-1.0</item>
|
||||
<item>BitTorrent-1.1</item>
|
||||
<item>CC-BY-1.0</item>
|
||||
<item>CC-BY-2.0</item>
|
||||
<item>CC-BY-2.5</item>
|
||||
<item>CC-BY-2.5-AU</item>
|
||||
<item>CC-BY-3.0</item>
|
||||
<item>CC-BY-3.0-AT</item>
|
||||
<item>CC-BY-3.0-DE</item>
|
||||
<item>CC-BY-4.0</item>
|
||||
<item>CC-BY-NC-1.0</item>
|
||||
<item>CC-BY-NC-2.0</item>
|
||||
<item>CC-BY-NC-2.5</item>
|
||||
<item>CC-BY-NC-3.0</item>
|
||||
<item>CC-BY-NC-4.0</item>
|
||||
<item>Community-Spec-1.0</item>
|
||||
<item>Cube</item>
|
||||
<item>D-FSL-1.0</item>
|
||||
<item>DL-DE-BY-2.0</item>
|
||||
<item>ECL-1.0</item>
|
||||
<item>ECL-2.0</item>
|
||||
<item>EFL-1.0</item>
|
||||
<item>EFL-2.0</item>
|
||||
<item>Elastic-2.0</item>
|
||||
<item>FreeBSD-DOC</item>
|
||||
<item>GD</item>
|
||||
<item>GFDL-1.1-only</item>
|
||||
<item>GFDL-1.1-or-later</item>
|
||||
<item>GFDL-1.2-only</item>
|
||||
<item>GFDL-1.2-or-later</item>
|
||||
<item>GFDL-1.3-only</item>
|
||||
<item>GFDL-1.3-or-later</item>
|
||||
<item>GPL-1.0-only</item>
|
||||
<item>GPL-1.0-or-later</item>
|
||||
<item>GPL-2.0-only</item>
|
||||
<item>GPL-2.0-or-later</item>
|
||||
<item>GPL-3.0-interface-exception</item>
|
||||
<item>GPL-3.0-only</item>
|
||||
<item>GPL-3.0-or-later</item>
|
||||
<item>GPL-CC-1.0</item>
|
||||
<item>GStreamer-exception-2008</item>
|
||||
<item>Glide</item>
|
||||
<item>HP-1989</item>
|
||||
<item>IBM-pibs</item>
|
||||
<item>ICU</item>
|
||||
<item>IPL-1.0</item>
|
||||
<item>ImageMagick</item>
|
||||
<item>Intel</item>
|
||||
<item>Intel-ACPI</item>
|
||||
<item>Interbase-1.0</item>
|
||||
<item>JSON</item>
|
||||
<item>LAL-1.3</item>
|
||||
<item>LGPL-2.0-only</item>
|
||||
<item>LGPL-2.0-or-later</item>
|
||||
<item>LGPL-2.1-only</item>
|
||||
<item>LGPL-2.1-or-later</item>
|
||||
<item>LGPL-3.0-only</item>
|
||||
<item>LGPL-3.0-or-later</item>
|
||||
<item>LGPLLR</item>
|
||||
<item>LLGPL</item>
|
||||
<item>LPL-1.0</item>
|
||||
<item>LPL-1.02</item>
|
||||
<item>LPPL-1.0</item>
|
||||
<item>LPPL-1.3a</item>
|
||||
<item>LPPL-1.3c</item>
|
||||
<item>Libpng</item>
|
||||
<item>Linux-OpenIB</item>
|
||||
<item>MIT</item>
|
||||
<item>MIT-0</item>
|
||||
<item>MIT-CMU</item>
|
||||
<item>MIT-Festival</item>
|
||||
<item>MIT-Modern-Variant</item>
|
||||
<item>MIT-Wu</item>
|
||||
<item>MIT-advertising</item>
|
||||
<item>MIT-open-group</item>
|
||||
<item>MPL-1.0</item>
|
||||
<item>MPL-2.0</item>
|
||||
<item>MirOS</item>
|
||||
<item>NASA-1.3</item>
|
||||
<item>NTP</item>
|
||||
<item>Nokia</item>
|
||||
<item>OCLC-2.0</item>
|
||||
<item>OFL-1.0</item>
|
||||
<item>OFL-1.1</item>
|
||||
<item>OLDAP-1.1</item>
|
||||
<item>OLDAP-2.0</item>
|
||||
<item>OLDAP-2.8</item>
|
||||
<item>OML</item>
|
||||
<item>OSL-1.0</item>
|
||||
<item>OSL-2.0</item>
|
||||
<item>OSL-3.0</item>
|
||||
<item>OpenSSL</item>
|
||||
<item>PHP-3.0</item>
|
||||
<item>PSF-2.0</item>
|
||||
<item>PostgreSQL</item>
|
||||
<item>Python-2.0</item>
|
||||
<item>QPL-1.0</item>
|
||||
<item>Qt-GPL-exception-1.0</item>
|
||||
<item>Qt-GPL-exception-1.1</item>
|
||||
<item>RPL-1.1</item>
|
||||
<item>RPL-1.5</item>
|
||||
<item>Ruby</item>
|
||||
<item>SGI-B-1.0</item>
|
||||
<item>SGI-B-2.0</item>
|
||||
<item>SSH-OpenSSH</item>
|
||||
<item>Sendmail</item>
|
||||
<item>TCL</item>
|
||||
<item>UnixCrypt</item>
|
||||
<item>Unlicense</item>
|
||||
<item>Vim</item>
|
||||
<item>W3C</item>
|
||||
<item>WTFPL</item>
|
||||
<item>X11</item>
|
||||
<item>XFree86-1.1</item>
|
||||
<item>Xdebug-1.03</item>
|
||||
<item>Xerox</item>
|
||||
<item>YPL-1.0</item>
|
||||
<item>ZPL-1.1</item>
|
||||
<item>ZPL-2.0</item>
|
||||
<item>Zed</item>
|
||||
<item>Zimbra-1.4</item>
|
||||
<item>Zlib</item>
|
||||
<item>bzip2-1.0.6</item>
|
||||
<item>copyleft-next-0.3.1</item>
|
||||
<item>curl</item>
|
||||
<item>gnuplot</item>
|
||||
<item>libpng-2.0</item>
|
||||
<item>libselinux-1.0</item>
|
||||
<item>w3m</item>
|
||||
<item>xpp</item>
|
||||
<item>zlib-acknowledgement</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -1073,4 +1073,8 @@
|
||||
|
||||
<string name="url_prompt_title">Show URL confirmation dialog</string>
|
||||
<string name="url_prompt_description">Show a confirmation dialog before opening external links in Markdown rendered contents</string>
|
||||
|
||||
<string name="gitignore_template">Gitignore Template</string>
|
||||
<string name="no_template">No template</string>
|
||||
<string name="no_license">No license</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<changelog>
|
||||
|
||||
<release version="12.0.0-dev" versioncode="1195">
|
||||
<release version="13.0.0-dev" versioncode="1295">
|
||||
<type name="🎉 Features 🎉">
|
||||
<change>HTTP basic authentication (more in README.md)</change>
|
||||
<change>Pinch to zoom in and out of images in issue/PR/comment popups</change>
|
||||
<change>PIN/password as a fallback for biometric authentication</change>
|
||||
<change>URL opening prompt popup (Settings → General)</change>
|
||||
<change>Issue templates for new issues</change>
|
||||
<change>DEV</change>
|
||||
</type>
|
||||
<type name="v🚀 Improvements 🚀">
|
||||
<change>Zig language support in files and the languages bar</change>
|
||||
<change>Added pagination to labels for the issues filter</change>
|
||||
<change>Improved pinned issues scrolling</change>
|
||||
<change>UI improvements across the app</change>
|
||||
<change>DEV</change>
|
||||
</type>
|
||||
<type name="🐛 Bug Fixes 🐛">
|
||||
<change>Fixed bottom navigation colors</change>
|
||||
<change>Fixed releases and tags view</change>
|
||||
<change>Fixed topics add button UI</change>
|
||||
<change>Fixed showing 'no data found' for most visited repositories for a split second</change>
|
||||
<change>Fixed comment content formatting in Activities</change>
|
||||
<change>DEV</change>
|
||||
</type>
|
||||
</release>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user