Merge branch 'master' into 7-assign-team-to-repo

This commit is contained in:
opyale 2021-03-31 19:24:12 +02:00
commit a47be21017
106 changed files with 1968 additions and 2745 deletions

View File

@ -69,26 +69,30 @@ We use [Crowdin](https://crowdin.com/project/gitnex) for translation. If your la
Thanks to all the open source libraries, contributors and donators.
#### Open source libraries
- Retrofit
- Gson
- Okhttp
- Picasso
- Markwon
- Prism4j
- Prettytime
- Amulyakhare/textdrawable
- Vdurmont/emoji-java
- Pes/materialcolorpicker
- HamidrezaAmz/BreadcrumbsView
- Chrisbanes/PhotoView
- Pddstudio/highlightjs-android
- Apache/commons-io
- Caverock/androidsvg
- Droidsonroids.gif/android-gif-drawable
- Barteksc/androidPdfViewer
- Ge0rg/memorizingTrustManager
- Dimezis/blurView
- Mikaelhg/urlbuilder
- [square/retrofit](https://github.com/square/retrofit)
- [google/gson](https://github.com/google/gson)
- [square/okhttp](https://github.com/square/okhttp)
- [square/picasso](https://github.com/square/picasso)
- [wasabeef/picasso-transformations](https://github.com/wasabeef/picasso-transformations)
- [cats-oss/android-gpuimage](https://github.com/cats-oss/android-gpuimage)
- [noties/Markwon](https://github.com/noties/Markwon)
- [noties/Prism4j](https://github.com/noties/Prism4j)
- [ocpsoft/prettytime](https://github.com/ocpsoft/prettytime)
- [amulyakhare/TextDrawable](https://github.com/amulyakhare/TextDrawable)
- [vdurmont/emoji-java](https://github.com/vdurmont/emoji-java)
- [Pes8/android-material-color-picker-dialog](https://github.com/Pes8/android-material-color-picker-dialog)
- [HamidrezaAmz/BreadcrumbsView](https://github.com/HamidrezaAmz/BreadcrumbsView)
- [Baseflow/PhotoView](https://github.com/Baseflow/PhotoView)
- [apache/commons](https://github.com/apache/commons-io)
- [barteksc/AndroidPdfViewer](https://github.com/barteksc/AndroidPdfViewer)
- [ge0rg/MemorizingTrustManager](https://github.com/ge0rg/MemorizingTrustManager)
- [mikaelhg/urlbuilder](https://github.com/mikaelhg/urlbuilder)
- [ACRA/acra](https://github.com/ACRA/acra)
#### Icon sets
- [feathericons/feather](https://github.com/feathericons/feather)
- [primer/octicons](https://github.com/primer/octicons)
- [google/material-design-icons](https://github.com/google/material-design-icons)
[Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif)

View File

@ -6,8 +6,8 @@ android {
applicationId "org.mian.gitnex"
minSdkVersion 21
targetSdkVersion 30
versionCode 346
versionName "3.5.0-dev"
versionCode 395
versionName "4.0.0-dev"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -30,7 +30,7 @@ android {
release {
minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
@ -54,28 +54,30 @@ configurations {
}
dependencies {
def lifecycle_version = '2.3.0'
def markwon_version = '4.6.1'
def lifecycle_version = '2.3.1'
def markwon_version = '4.6.2'
def work_version = "2.5.0"
def acra = "5.7.0"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.3.0-beta01'
implementation 'androidx.appcompat:appcompat:1.3.0-rc01'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
testImplementation 'junit:junit:4.13.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.squareup.picasso:picasso:2.71828"
implementation 'jp.wasabeef:picasso-transformations:2.4.0'
implementation 'jp.co.cyberagent.android:gpuimage:2.1.0'
implementation "com.amulyakhare:com.amulyakhare.textdrawable:1.0.1"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2'
implementation 'org.ocpsoft.prettytime:prettytime:5.0.0.Final'
implementation "com.pes.materialcolorpicker:library:1.2.5"
implementation "io.noties.markwon:core:$markwon_version"
@ -94,11 +96,9 @@ dependencies {
implementation "io.noties.markwon:image-picasso:$markwon_version"
implementation "io.noties:prism4j:2.0.0"
annotationProcessor "io.noties:prism4j-bundler:2.0.0"
implementation "com.caverock:androidsvg:1.4"
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.21"
implementation "com.github.HamidrezaAmz:BreadcrumbsView:0.2.9"
implementation "commons-io:commons-io:20030203.000550"
implementation 'org.apache.commons:commons-lang3:3.11'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation "com.github.chrisbanes:PhotoView:2.3.0"
implementation "com.github.barteksc:android-pdf-viewer:3.2.0-beta.1"
implementation "ch.acra:acra-mail:$acra"
@ -107,11 +107,10 @@ dependencies {
implementation 'androidx.room:room-runtime:2.2.6'
annotationProcessor 'androidx.room:room-compiler:2.2.6'
implementation "androidx.work:work-runtime:$work_version"
implementation "com.eightbitlab:blurview:1.6.4"
implementation "io.mikael:urlbuilder:2.0.9"
implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2"
implementation "org.codeberg.gitnex:tea4j:1.0.1"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.1"
implementation "org.codeberg.gitnex:tea4j:1.0.5"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.biometric:biometric:1.1.0'
}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
!function(e){"use strict";function t(){"complete"===document.readyState?n():e.addEventListener("DOMContentLoaded",n)}function n(){try{var e=document.querySelectorAll("code.hljs");for(var t in e)e.hasOwnProperty(t)&&r(e[t])}catch(n){console.error("LineNumbers error: ",n)}}function r(e){if("object"==typeof e){var t=e.parentNode,n=o(t.textContent);if(n>1){for(var r="",c=0;n>c;c++)r+=c+1+"\n";var l=document.createElement("code");l.className="hljs hljs-line-numbers",l.style["float"]="left",l.textContent=r,t.insertBefore(l,e)}}}function o(e){if(0===e.length)return 0;var t=/\r\n|\r|\n/g,n=e.match(t);return n=n?n.length:0,e[e.length-1].match(t)||(n+=1),n}"undefined"==typeof e.hljs?console.error("highlight.js not detected!"):(e.hljs.initLineNumbersOnLoad=t,e.hljs.lineNumbersBlock=r)}(window);

View File

@ -1,66 +0,0 @@
/*
Date: 24 Fev 2015
Author: Pedro Oliveira <kanytu@gmail . com>
*/
.hljs {
color: #a9b7c6;
background: #282b2e;
display: block;
overflow-x: auto;
padding: 0.5em;
}
.hljs-number,
.hljs-literal,
.hljs-symbol,
.hljs-bullet {
color: #6897BB;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-deletion {
color: #cc7832;
}
.hljs-variable,
.hljs-template-variable,
.hljs-link {
color: #629755;
}
.hljs-comment,
.hljs-quote {
color: #808080;
}
.hljs-meta {
color: #bbb529;
}
.hljs-string,
.hljs-attribute,
.hljs-addition {
color: #6A8759;
}
.hljs-section,
.hljs-title,
.hljs-type {
color: #ffc66d;
}
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #e8bf6a;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@ -1,87 +0,0 @@
/*
Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #FFFFFF;
}
.hljs,
.hljs-subst {
color: #434f54;
}
.hljs-keyword,
.hljs-attribute,
.hljs-selector-tag,
.hljs-doctag,
.hljs-name {
color: #00979D;
}
.hljs-built_in,
.hljs-literal,
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #D35400;
}
.hljs-regexp,
.hljs-symbol,
.hljs-variable,
.hljs-template-variable,
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #00979D;
}
.hljs-type,
.hljs-string,
.hljs-selector-id,
.hljs-selector-class,
.hljs-quote,
.hljs-template-tag,
.hljs-deletion {
color: #005C5F;
}
.hljs-title,
.hljs-section {
color: #880000;
font-weight: bold;
}
.hljs-comment {
color: rgba(149,165,166,.8);
}
.hljs-meta-keyword {
color: #728E00;
}
.hljs-meta {
color: #434f54;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-function {
color: #728E00;
}
.hljs-number {
color: #8A7B52;
}

View File

@ -1,71 +0,0 @@
/*
FAR Style (c) MajestiC <majestic2k@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #000080;
}
.hljs,
.hljs-subst {
color: #0ff;
}
.hljs-string,
.hljs-attribute,
.hljs-symbol,
.hljs-bullet,
.hljs-built_in,
.hljs-builtin-name,
.hljs-template-tag,
.hljs-template-variable,
.hljs-addition {
color: #ff0;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-section,
.hljs-type,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-variable {
color: #fff;
}
.hljs-comment,
.hljs-quote,
.hljs-doctag,
.hljs-deletion {
color: #888;
}
.hljs-number,
.hljs-regexp,
.hljs-literal,
.hljs-link {
color: #0f0;
}
.hljs-meta {
color: #008080;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-title,
.hljs-section,
.hljs-name,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

View File

@ -1,99 +0,0 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@ -1,73 +0,0 @@
/*
IR_Black style (c) Vasily Mikhailitchenko <vaskas@programica.ru>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #000;
color: #f8f8f8;
}
.hljs-comment,
.hljs-quote,
.hljs-meta {
color: #7c7c7c;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-tag,
.hljs-name {
color: #96cbfe;
}
.hljs-attribute,
.hljs-selector-id {
color: #ffffb6;
}
.hljs-string,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-addition {
color: #a8ff60;
}
.hljs-subst {
color: #daefa3;
}
.hljs-regexp,
.hljs-link {
color: #e9c062;
}
.hljs-title,
.hljs-section,
.hljs-type,
.hljs-doctag {
color: #ffffb6;
}
.hljs-symbol,
.hljs-bullet,
.hljs-variable,
.hljs-template-variable,
.hljs-literal {
color: #c6c5fe;
}
.hljs-number,
.hljs-deletion {
color:#ff73fd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@ -1,83 +0,0 @@
/*
Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #23241f;
}
.hljs,
.hljs-tag,
.hljs-subst {
color: #f8f8f2;
}
.hljs-strong,
.hljs-emphasis {
color: #a8a8a2;
}
.hljs-bullet,
.hljs-quote,
.hljs-number,
.hljs-regexp,
.hljs-literal,
.hljs-link {
color: #ae81ff;
}
.hljs-code,
.hljs-title,
.hljs-section,
.hljs-selector-class {
color: #a6e22e;
}
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-name,
.hljs-attr {
color: #f92672;
}
.hljs-symbol,
.hljs-attribute {
color: #66d9ef;
}
.hljs-params,
.hljs-class .hljs-title {
color: #f8f8f2;
}
.hljs-string,
.hljs-type,
.hljs-built_in,
.hljs-builtin-name,
.hljs-selector-id,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-addition,
.hljs-variable,
.hljs-template-variable {
color: #e6db74;
}
.hljs-comment,
.hljs-deletion,
.hljs-meta {
color: #75715e;
}

View File

@ -7,7 +7,6 @@ import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.TinyDB;
import java.io.IOException;
import java.util.Date;
import okhttp3.ResponseBody;
import retrofit2.Call;
/**
@ -35,7 +34,7 @@ public class NotificationsActions {
public void setNotificationStatus(NotificationThread notificationThread, NotificationStatus notificationStatus) throws IOException {
Call<ResponseBody> call = RetrofitClient.getApiInterface(context)
Call<Void> call = RetrofitClient.getApiInterface(context)
.markNotificationThreadAsRead(instanceToken, notificationThread.getId(), notificationStatus.name());
if(!call.execute().isSuccessful()) {
@ -46,7 +45,7 @@ public class NotificationsActions {
public boolean setAllNotificationsRead(Date date) throws IOException {
Call<ResponseBody> call = RetrofitClient.getApiInterface(context)
Call<Void> call = RetrofitClient.getApiInterface(context)
.markNotificationThreadsAsRead(instanceToken, AppUtil.getTimestampFromDate(context, date), true,
new String[]{"unread", "pinned"}, "read");

View File

@ -7,6 +7,7 @@ import org.mian.gitnex.R;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.notifications.Notifications;
/**
* Author M M Arif
@ -77,6 +78,8 @@ public abstract class BaseActivity extends AppCompatActivity {
}
AppUtil.setAppLocale(getResources(), tinyDB.getString("locale"));
Notifications.startWorker(appCtx);
}
}

View File

@ -24,7 +24,7 @@ import org.mian.gitnex.adapters.CommitsAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityCommitsBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
@ -43,7 +43,7 @@ public class CommitsActivity extends BaseActivity {
private TextView noData;
private ProgressBar progressBar;
private String TAG = "CommitsActivity";
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private int pageSize = 1;
private RecyclerView recyclerView;
@ -85,7 +85,7 @@ public class CommitsActivity extends BaseActivity {
// if gitea is 1.12 or higher use the new limit (resultLimitNewGiteaInstances)
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
recyclerView = activityCommitsBinding.recyclerView;

View File

@ -8,10 +8,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
@ -38,16 +34,7 @@ import retrofit2.Callback;
public class CreateFileActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
private Button newFileCreate;
private EditText newFileName;
private EditText newFileContent;
private EditText newFileCommitMessage;
private AutoCompleteTextView newFileBranches;
private String filePath;
private String fileSha;
private ActivityCreateFileBinding binding;
public static final int FILE_ACTION_CREATE = 0;
public static final int FILE_ACTION_DELETE = 1;
@ -55,6 +42,9 @@ public class CreateFileActivity extends BaseActivity {
private int fileAction = FILE_ACTION_CREATE;
private String filePath;
private String fileSha;
private final List<String> branches = new ArrayList<>();
private String repoOwner;
@ -66,154 +56,127 @@ public class CreateFileActivity extends BaseActivity {
super.onCreate(savedInstanceState);
ActivityCreateFileBinding activityCreateFileBinding = ActivityCreateFileBinding.inflate(getLayoutInflater());
setContentView(activityCreateFileBinding.getRoot());
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
binding = ActivityCreateFileBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
repoOwner = parts[0];
repoName = parts[1];
closeActivity = activityCreateFileBinding.close;
newFileName = activityCreateFileBinding.newFileName;
newFileContent = activityCreateFileBinding.newFileContent;
newFileCommitMessage = activityCreateFileBinding.newFileCommitMessage;
TextView toolbarTitle = activityCreateFileBinding.toolbarTitle;
TextView toolbarTitle = binding.toolbarTitle;
newFileName.requestFocus();
assert imm != null;
imm.showSoftInput(newFileName, InputMethodManager.SHOW_IMPLICIT);
binding.newFileName.requestFocus();
initCloseListener();
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
assert inputMethodManager != null;
inputMethodManager.showSoftInput(binding.newFileName, InputMethodManager.SHOW_IMPLICIT);
closeActivity.setOnClickListener(onClickListener);
newFileCreate = activityCreateFileBinding.newFileCreate;
newFileContent.setOnTouchListener((touchView, motionEvent) -> {
binding.close.setOnClickListener(view -> finish());
binding.newFileContent.setOnTouchListener((touchView, motionEvent) -> {
touchView.getParent().requestDisallowInterceptTouchEvent(true);
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 && (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0 &&
(motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
touchView.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
});
if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", FILE_ACTION_DELETE) == FILE_ACTION_DELETE) {
fileAction = getIntent().getIntExtra("fileAction", FILE_ACTION_DELETE);
filePath = getIntent().getStringExtra("filePath");
String fileContents = getIntent().getStringExtra("fileContents");
fileSha = getIntent().getStringExtra("fileSha");
toolbarTitle.setText(getString(R.string.deleteFileText, filePath));
newFileCreate.setText(R.string.deleteFile);
newFileName.setText(filePath);
newFileName.setEnabled(false);
newFileName.setFocusable(false);
binding.newFileCreate.setText(R.string.deleteFile);
newFileContent.setText(fileContents);
newFileContent.setEnabled(false);
newFileContent.setFocusable(false);
binding.newFileNameLayout.setVisibility(View.GONE);
binding.newFileContentLayout.setVisibility(View.GONE);
}
if(getIntent().getStringExtra("filePath") != null && getIntent().getIntExtra("fileAction", FILE_ACTION_EDIT) == FILE_ACTION_EDIT) {
fileAction = getIntent().getIntExtra("fileAction", FILE_ACTION_EDIT);
filePath = getIntent().getStringExtra("filePath");
String fileContents = getIntent().getStringExtra("fileContents");
fileSha = getIntent().getStringExtra("fileSha");
toolbarTitle.setText(getString(R.string.editFileText, filePath));
newFileCreate.setText(R.string.editFile);
newFileName.setText(filePath);
newFileName.setEnabled(false);
newFileName.setFocusable(false);
binding.newFileCreate.setText(R.string.editFile);
binding.newFileName.setText(filePath);
binding.newFileName.setEnabled(false);
binding.newFileName.setFocusable(false);
newFileContent.setText(fileContents);
binding.newFileContent.setText(getIntent().getStringExtra("fileContents"));
}
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
newFileBranches = activityCreateFileBinding.newFileBranches;
getBranches(repoOwner, repoName);
disableProcessButton();
NetworkStatusObserver networkStatusObserver = NetworkStatusObserver.getInstance(ctx);
networkStatusObserver.registerNetworkStatusListener(hasNetworkConnection -> newFileCreate.setEnabled(hasNetworkConnection));
networkStatusObserver.registerNetworkStatusListener(binding.newFileCreate::setEnabled);
newFileCreate.setOnClickListener(createFileListener);
binding.newFileCreate.setOnClickListener(v -> processNewFile());
}
private final View.OnClickListener createFileListener = v -> processNewFile();
private void processNewFile() {
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newFileName_ = newFileName.getText().toString();
String newFileContent_ = newFileContent.getText().toString();
String newFileBranchName_ = newFileBranches.getText().toString();
String newFileCommitMessage_ = newFileCommitMessage.getText().toString();
if(!connToInternet) {
String newFileName = binding.newFileName.getText() != null ? binding.newFileName.getText().toString() : "";
String newFileContent = binding.newFileContent.getText() != null ? binding.newFileContent.getText().toString() : "";
String newFileBranchName = binding.newFileBranches.getText() != null ? binding.newFileBranches.getText().toString() : "";
String newFileCommitMessage = binding.newFileCommitMessage.getText() != null ? binding.newFileCommitMessage.getText().toString() : "";
if(!AppUtil.hasNetworkConnection(appCtx)) {
Toasty.error(ctx, getResources().getString(R.string.checkNetConnection));
return;
}
if(newFileName_.equals("") || newFileContent_.equals("") || newFileCommitMessage_.equals("")) {
if(((newFileName.isEmpty() || newFileContent.isEmpty()) && fileAction != FILE_ACTION_DELETE) || newFileCommitMessage.isEmpty()) {
Toasty.error(ctx, getString(R.string.newFileRequiredFields));
return;
}
if(!AppUtil.checkStringsWithDash(newFileBranchName_)) {
if(!AppUtil.checkStringsWithDash(newFileBranchName)) {
Toasty.error(ctx, getString(R.string.newFileInvalidBranchName));
return;
}
if(newFileCommitMessage_.length() > 255) {
if(newFileCommitMessage.length() > 255) {
Toasty.warning(ctx, getString(R.string.newFileCommitMessageError));
return;
}
else {
disableProcessButton();
disableProcessButton();
switch(fileAction) {
switch(fileAction) {
case FILE_ACTION_CREATE:
createNewFile(Authorization.get(ctx), repoOwner, repoName, newFileName_, AppUtil.encodeBase64(newFileContent_), newFileCommitMessage_, newFileBranchName_);
break;
case FILE_ACTION_CREATE:
createNewFile(repoOwner, repoName, newFileName, AppUtil.encodeBase64(newFileContent), newFileCommitMessage, newFileBranchName);
break;
case FILE_ACTION_DELETE:
deleteFile(Authorization.get(ctx), repoOwner, repoName, filePath, newFileCommitMessage_, newFileBranchName_, fileSha);
break;
case FILE_ACTION_DELETE:
deleteFile(repoOwner, repoName, filePath, newFileCommitMessage, newFileBranchName, fileSha);
break;
case FILE_ACTION_EDIT:
editFile(Authorization.get(ctx), repoOwner, repoName, filePath,
AppUtil.encodeBase64(newFileContent_), newFileCommitMessage_, newFileBranchName_, fileSha);
break;
case FILE_ACTION_EDIT:
editFile(repoOwner, repoName, filePath, AppUtil.encodeBase64(newFileContent), newFileCommitMessage, newFileBranchName, fileSha);
break;
}
}
}
private void createNewFile(final String token, String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName) {
private void createNewFile(String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName) {
NewFile createNewFileJsonStr = branches.contains(branchName) ?
new NewFile(branchName, fileContent, fileCommitMessage, "") :
@ -221,7 +184,7 @@ public class CreateFileActivity extends BaseActivity {
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.createNewFile(token, repoOwner, repoName, fileName, createNewFileJsonStr);
.createNewFile(Authorization.get(ctx), repoOwner, repoName, fileName, createNewFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@ -268,7 +231,7 @@ public class CreateFileActivity extends BaseActivity {
}
private void deleteFile(final String token, String repoOwner, String repoName, String fileName, String fileCommitMessage, String branchName, String fileSha) {
private void deleteFile(String repoOwner, String repoName, String fileName, String fileCommitMessage, String branchName, String fileSha) {
DeleteFile deleteFileJsonStr = branches.contains(branchName) ?
new DeleteFile(branchName, fileCommitMessage, "", fileSha) :
@ -276,42 +239,42 @@ public class CreateFileActivity extends BaseActivity {
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.deleteFile(token, repoOwner, repoName, fileName, deleteFileJsonStr);
.deleteFile(Authorization.get(ctx), repoOwner, repoName, fileName, deleteFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.code() == 200) {
switch(response.code()) {
enableProcessButton();
Toasty.info(ctx, getString(R.string.deleteFileMessage, tinyDB.getString("repoBranch")));
getIntent().removeExtra("filePath");
getIntent().removeExtra("fileSha");
getIntent().removeExtra("fileContents");
finish();
}
else if(response.code() == 401) {
case 200:
enableProcessButton();
Toasty.info(ctx, getString(R.string.deleteFileMessage, tinyDB.getString("repoBranch")));
getIntent().removeExtra("filePath");
getIntent().removeExtra("fileSha");
getIntent().removeExtra("fileContents");
finish();
break;
enableProcessButton();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
if(response.code() == 404) {
case 401:
enableProcessButton();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
break;
case 404:
enableProcessButton();
Toasty.info(ctx, getString(R.string.apiNotFound));
}
else {
break;
default:
enableProcessButton();
Toasty.info(ctx, getString(R.string.genericError));
}
break;
}
}
@ -325,7 +288,7 @@ public class CreateFileActivity extends BaseActivity {
}
private void editFile(final String token, String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName, String fileSha) {
private void editFile(String repoOwner, String repoName, String fileName, String fileContent, String fileCommitMessage, String branchName, String fileSha) {
EditFile editFileJsonStr = branches.contains(branchName) ?
new EditFile(branchName, fileCommitMessage, "", fileSha, fileContent) :
@ -333,7 +296,7 @@ public class CreateFileActivity extends BaseActivity {
Call<JsonElement> call = RetrofitClient
.getApiInterface(ctx)
.editFile(token, repoOwner, repoName, fileName, editFileJsonStr);
.editFile(Authorization.get(ctx), repoOwner, repoName, fileName, editFileJsonStr);
call.enqueue(new Callback<JsonElement>() {
@ -402,8 +365,8 @@ public class CreateFileActivity extends BaseActivity {
ArrayAdapter<String> adapter = new ArrayAdapter<>(CreateFileActivity.this, R.layout.list_spinner_items, branches);
newFileBranches.setAdapter(adapter);
newFileBranches.setText(tinyDB.getString("repoBranch"), false);
binding.newFileBranches.setAdapter(adapter);
binding.newFileBranches.setText(tinyDB.getString("repoBranch"), false);
enableProcessButton();
@ -419,19 +382,7 @@ public class CreateFileActivity extends BaseActivity {
}
private void initCloseListener() {
onClickListener = view -> finish();
}
private void disableProcessButton() {
newFileCreate.setEnabled(false);
}
private void enableProcessButton() {
newFileCreate.setEnabled(true);
}
private void disableProcessButton() { binding.newFileCreate.setEnabled(false); }
private void enableProcessButton() { binding.newFileCreate.setEnabled(true); }
}

View File

@ -30,7 +30,7 @@ import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
@ -51,7 +51,7 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
private CustomLabelsSelectionDialogBinding labelsBinding;
private CustomAssigneesSelectionDialogBinding assigneesBinding;
private View.OnClickListener onClickListener;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private Dialog dialogLabels;
private Dialog dialogAssignees;
private String labelsSetter;
@ -93,7 +93,7 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
// require gitea 1.12 or higher
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
viewBinding.newIssueTitle.requestFocus();

View File

@ -24,13 +24,12 @@ import org.mian.gitnex.databinding.ActivityCreatePrBinding;
import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
@ -43,7 +42,7 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
private View.OnClickListener onClickListener;
private ActivityCreatePrBinding viewBinding;
private CustomLabelsSelectionDialogBinding labelsBinding;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private Dialog dialogLabels;
private String labelsSetter;
private List<Integer> labelsIds = new ArrayList<>();
@ -80,7 +79,7 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
// require gitea 1.12 or higher
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
viewBinding.prBody.setOnTouchListener((touchView, motionEvent) -> {
@ -165,14 +164,14 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
CreatePullRequest createPullRequest = new CreatePullRequest(prTitle, prDescription, loginUid, mergeInto, pullFrom, milestoneId, dueDate, assignees, labelsIds);
Call<ResponseBody> transferCall = RetrofitClient
Call<Void> transferCall = RetrofitClient
.getApiInterface(appCtx)
.createPullRequest(instanceToken, repoOwner, repoName, createPullRequest);
transferCall.enqueue(new Callback<ResponseBody>() {
transferCall.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
disableProcessButton();
@ -199,7 +198,7 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
enableProcessButton();
Toasty.error(ctx, getString(R.string.genericServerResponseError));

View File

@ -27,7 +27,7 @@ import org.mian.gitnex.databinding.ActivityEditIssueBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.text.DateFormat;
@ -45,7 +45,7 @@ import retrofit2.Callback;
public class EditIssueActivity extends BaseActivity implements View.OnClickListener {
private View.OnClickListener onClickListener;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private EditText editIssueTitle;
private EditText editIssueDescription;
@ -93,7 +93,7 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
editIssueTitle.requestFocus();

View File

@ -1,13 +1,11 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import org.gitnex.tea4j.models.FileDiffView;
import org.mian.gitnex.R;
@ -15,6 +13,7 @@ import org.mian.gitnex.adapters.FilesDiffAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityFileDiffBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.ParseDiff;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
@ -23,7 +22,7 @@ import java.io.IOException;
import java.util.List;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -52,8 +51,6 @@ public class FileDiffActivity extends BaseActivity {
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
ImageView closeActivity = activityFileDiffBinding.close;
toolbarTitle = activityFileDiffBinding.toolbarTitle;
@ -71,80 +68,69 @@ public class FileDiffActivity extends BaseActivity {
String pullIndex = tinyDb.getString("issueNumber");
boolean apiCall = !new Version(tinyDb.getString("giteaVersion")).less("1.13.0");
getPullDiffContent(repoOwner, repoName, pullIndex, instanceToken, apiCall);
getPullDiffContent(repoOwner, repoName, pullIndex, apiCall);
}
private void getPullDiffContent(String owner, String repo, String pullIndex, String token, boolean apiCall) {
private void getPullDiffContent(String owner, String repo, String pullIndex, boolean apiCall) {
Call<ResponseBody> call;
if(apiCall) {
Thread thread = new Thread(() -> {
call = RetrofitClient.getApiInterface(ctx).getPullDiffContent(token, owner, repo, pullIndex);
}
else {
Call<ResponseBody> call = apiCall ?
RetrofitClient.getApiInterface(ctx).getPullDiffContent(Authorization.get(ctx), owner, repo, pullIndex) :
RetrofitClient.getWebInterface(ctx).getPullDiffContent(Authorization.getWeb(ctx), owner, repo, pullIndex);
call = RetrofitClient.getWebInterface(ctx).getPullDiffContent(owner, repo, pullIndex);
}
try {
call.enqueue(new Callback<ResponseBody>() {
Response<ResponseBody> response = call.execute();
assert response.body() != null;
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
switch(response.code()) {
if(response.code() == 200) {
case 200:
List<FileDiffView> fileDiffViews = ParseDiff.getFileDiffViewArray(response.body().string());
try {
int filesCount = fileDiffViews.size();
assert response.body() != null;
String toolbarTitleText = (filesCount > 1) ?
getResources().getString(R.string.fileDiffViewHeader, Integer.toString(filesCount)) :
getResources().getString(R.string.fileDiffViewHeaderSingle, Integer.toString(filesCount));
List<FileDiffView> fileContentsArray = ParseDiff.getFileDiffViewArray(response.body().string());
FilesDiffAdapter adapter = new FilesDiffAdapter(ctx, getSupportFragmentManager(), fileDiffViews);
int filesCount = fileContentsArray.size();
if(filesCount > 1) {
runOnUiThread(() -> {
toolbarTitle.setText(toolbarTitleText);
mListView.setAdapter(adapter);
mProgressBar.setVisibility(View.GONE);
});
break;
toolbarTitle.setText(getResources().getString(R.string.fileDiffViewHeader, Integer.toString(filesCount)));
}
else {
case 401:
AlertDialogs.authorizationTokenRevokedDialog(ctx,
getString(R.string.alertDialogTokenRevokedTitle),
getString(R.string.alertDialogTokenRevokedMessage),
getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
break;
toolbarTitle.setText(getResources().getString(R.string.fileDiffViewHeaderSingle, Integer.toString(filesCount)));
}
case 403:
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
break;
FilesDiffAdapter adapter = new FilesDiffAdapter(ctx, getSupportFragmentManager(), fileContentsArray);
mListView.setAdapter(adapter);
case 404:
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
break;
mProgressBar.setVisibility(View.GONE);
}
catch(IOException e) {
default:
Toasty.error(ctx, getString(R.string.labelGeneralError));
e.printStackTrace();
}
}
else if(response.code() == 401) {
} catch(IOException ignored) {}
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle), getResources().getString(R.string.alertDialogTokenRevokedMessage), getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.error(ctx, getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
thread.start();
}
private void initCloseListener() {
@ -153,6 +139,7 @@ public class FileDiffActivity extends BaseActivity {
getIntent().removeExtra("singleFileName");
finish();
};
}

View File

@ -1,29 +1,21 @@
package org.mian.gitnex.activities;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Base64;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import com.github.barteksc.pdfviewer.PDFView;
import androidx.core.app.NotificationCompat;
import com.github.barteksc.pdfviewer.util.FitPolicy;
import com.github.chrisbanes.photoview.PhotoView;
import com.vdurmont.emoji.EmojiParser;
import org.apache.commons.io.FileUtils;
import org.gitnex.tea4j.models.Files;
@ -33,19 +25,18 @@ import org.mian.gitnex.databinding.ActivityFileViewBinding;
import org.mian.gitnex.fragments.BottomSheetFileViewerFragment;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Images;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.highlightjs.HighlightJsView;
import org.mian.gitnex.helpers.highlightjs.models.Theme;
import java.io.File;
import org.mian.gitnex.notifications.Notifications;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Objects;
import java.util.Arrays;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -53,74 +44,38 @@ import retrofit2.Callback;
public class FileViewActivity extends BaseActivity implements BottomSheetFileViewerFragment.BottomSheetListener {
private View.OnClickListener onClickListener;
private TextView singleFileContents;
private LinearLayout singleFileContentsFrame;
private HighlightJsView singleCodeContents;
private PhotoView imageView;
private ProgressBar mProgressBar;
private byte[] imageData;
private PDFView pdfView;
private LinearLayout pdfViewFrame;
private byte[] decodedPdf;
private ActivityFileViewBinding binding;
private Boolean pdfNightMode;
private String singleFileName;
private String fileSha;
private Files file;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityFileViewBinding activityFileViewBinding = ActivityFileViewBinding.inflate(getLayoutInflater());
setContentView(activityFileViewBinding.getRoot());
binding = ActivityFileViewBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Toolbar toolbar = activityFileViewBinding.toolbar;
setSupportActionBar(toolbar);
setSupportActionBar(binding.toolbar);
tinyDB.putBoolean("enableMarkdownInFileView", false);
file = (Files) getIntent().getSerializableExtra("file");
binding.close.setOnClickListener(view -> finish());
binding.toolbarTitle.setMovementMethod(new ScrollingMovementMethod());
binding.toolbarTitle.setText(file.getPath());
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String instanceToken = "token " + tinyDB.getString(loginUid + "-token");
String repoOwner = parts[0];
String repoName = parts[1];
tinyDB.putBoolean("enableMarkdownInFileView", false);
getSingleFileContents(repoOwner, repoName, file.getPath(), repoBranch);
ImageView closeActivity = activityFileViewBinding.close;
singleFileContents = activityFileViewBinding.singleFileContents;
singleCodeContents = activityFileViewBinding.singleCodeContents;
imageView = activityFileViewBinding.imageView;
mProgressBar = activityFileViewBinding.progressBar;
pdfView = activityFileViewBinding.pdfView;
pdfViewFrame = activityFileViewBinding.pdfViewFrame;
singleFileContentsFrame = activityFileViewBinding.singleFileContentsFrame;
singleFileName = getIntent().getStringExtra("singleFileName");
TextView toolbar_title = activityFileViewBinding.toolbarTitle;
toolbar_title.setMovementMethod(new ScrollingMovementMethod());
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
tinyDB.putString("downloadFileContents", "");
try {
singleFileName = URLDecoder.decode(singleFileName, "UTF-8");
singleFileName = singleFileName.replaceAll("//", "/");
singleFileName = singleFileName.startsWith("/") ? singleFileName.substring(1) : singleFileName;
}
catch(UnsupportedEncodingException e) {
Log.i("singleFileName", singleFileName);
}
toolbar_title.setText(singleFileName);
getSingleFileContents(instanceToken, repoOwner, repoName, singleFileName, repoBranch);
}
@Override
@ -128,166 +83,189 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie
super.onResume();
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
String loginUid = tinyDB.getString("loginUid");
String instanceToken = "token " + tinyDB.getString(loginUid + "-token");
if(tinyDB.getBoolean("fileModified")) {
getSingleFileContents(instanceToken, repoOwner, repoName, singleFileName, repoBranch);
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
getSingleFileContents(repoOwner, repoName, file.getPath(), repoBranch);
tinyDB.putBoolean("fileModified", false);
}
}
private void getSingleFileContents(final String owner, String repo, final String filename, String ref) {
private void getSingleFileContents(String token, final String owner, String repo, final String filename, String ref) {
Thread thread = new Thread(() -> {
Call<Files> call = RetrofitClient.getApiInterface(ctx).getSingleFileContents(token, owner, repo, filename, ref);
Call<ResponseBody> call = RetrofitClient
.getWebInterface(ctx)
.getFileContents(Authorization.getWeb(ctx), owner, repo, ref, filename);
call.enqueue(new Callback<Files>() {
try {
@Override
public void onResponse(@NonNull Call<Files> call, @NonNull retrofit2.Response<Files> response) {
Response<ResponseBody> response = call.execute();
if(response.code() == 200) {
assert response.body() != null;
ResponseBody responseBody = response.body();
if(!response.body().getContent().equals("")) {
if(responseBody != null) {
runOnUiThread(() -> binding.progressBar.setVisibility(View.GONE));
String fileExtension = FileUtils.getExtension(filename);
mProgressBar.setVisibility(View.GONE);
fileSha = response.body().getSha();
// download file meta
tinyDB.putString("downloadFileName", filename);
tinyDB.putString("downloadFileContents", response.body().getContent());
boolean unknown = false;
boolean processable = false;
switch(AppUtil.getFileType(fileExtension)) {
case IMAGE:
singleFileContentsFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
imageView.setVisibility(View.VISIBLE);
// See https://developer.android.com/guide/topics/media/media-formats#core
if(Arrays.asList("bmp", "gif", "jpg", "jpeg", "png", "webp", "heic", "heif").contains(fileExtension.toLowerCase())) {
imageData = Base64.decode(response.body().getContent(), Base64.DEFAULT);
imageView.setImageBitmap(Images.scaleImage(imageData, 1920));
processable = true;
byte[] pictureBytes = responseBody.bytes();
runOnUiThread(() -> {
binding.contents.setVisibility(View.GONE);
binding.pdfViewFrame.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.GONE);
binding.photoView.setVisibility(View.VISIBLE);
binding.photoView.setImageBitmap(Images.scaleImage(pictureBytes, 1920));
});
}
break;
case UNKNOWN:
case TEXT:
imageView.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.VISIBLE);
switch(tinyDB.getInt("fileviewerSourceCodeThemeId")) {
case 1: singleCodeContents.setTheme(Theme.ARDUINO_LIGHT); break;
case 2: singleCodeContents.setTheme(Theme.GITHUB); break;
case 3: singleCodeContents.setTheme(Theme.FAR); break;
case 4: singleCodeContents.setTheme(Theme.IR_BLACK); break;
case 5: singleCodeContents.setTheme(Theme.ANDROID_STUDIO); break;
default: singleCodeContents.setTheme(Theme.MONOKAI_SUBLIME);
if(file.getSize() > Constants.maximumFileViewerSize) {
break;
}
singleCodeContents.setSource(AppUtil.decodeBase64(response.body().getContent()));
processable = true;
String text = responseBody.string();
runOnUiThread(() -> {
binding.photoView.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.GONE);
binding.pdfViewFrame.setVisibility(View.GONE);
binding.contents.setVisibility(View.VISIBLE);
binding.contents.setContent(text, fileExtension);
});
break;
case DOCUMENT:
if(fileExtension.equalsIgnoreCase("pdf")) {
imageView.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.VISIBLE);
processable = true;
pdfNightMode = tinyDB.getBoolean("enablePdfMode");
decodedPdf = Base64.decode(response.body().getContent(), Base64.DEFAULT);
byte[] documentBytes = responseBody.bytes();
pdfView.fromBytes(decodedPdf)
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
.enableAnnotationRendering(false)
.password(null)
.scrollHandle(null)
.enableAntialiasing(true)
.spacing(0)
.autoSpacing(true)
.pageFitPolicy(FitPolicy.WIDTH)
.fitEachPage(true)
.pageSnap(false)
.pageFling(true)
.nightMode(pdfNightMode).load();
runOnUiThread(() -> {
binding.photoView.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.GONE);
binding.contents.setVisibility(View.GONE);
pdfNightMode = tinyDB.getBoolean("enablePdfMode");
binding.pdfViewFrame.setVisibility(View.VISIBLE);
binding.pdfView.fromBytes(documentBytes)
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
.enableAnnotationRendering(false)
.password(null)
.scrollHandle(null)
.enableAntialiasing(true)
.spacing(0)
.autoSpacing(true)
.pageFitPolicy(FitPolicy.WIDTH)
.fitEachPage(true)
.pageSnap(false)
.pageFling(true)
.nightMode(pdfNightMode).load();
});
}
else {
unknown = true;
}
break;
case UNKNOWN:
default:
unknown = true;
break;
}
if(unknown) { // While the file could still be non-binary,
if(!processable) { // While the file could still be non-binary,
// it's better we don't show it (to prevent any crashes and/or unwanted behavior) and let the user download it instead.
imageView.setVisibility(View.GONE);
singleCodeContents.setVisibility(View.GONE);
pdfViewFrame.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
responseBody.close();
singleFileContents.setText(getString(R.string.excludeFilesInFileViewer));
singleFileContents.setGravity(Gravity.CENTER);
singleFileContents.setTypeface(null, Typeface.BOLD);
runOnUiThread(() -> {
binding.photoView.setVisibility(View.GONE);
binding.contents.setVisibility(View.GONE);
binding.pdfViewFrame.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.VISIBLE);
binding.markdown.setText(getString(R.string.excludeFilesInFileViewer));
binding.markdown.setGravity(Gravity.CENTER);
binding.markdown.setTypeface(null, Typeface.BOLD);
});
}
}
else {
} else {
runOnUiThread(() -> {
binding.markdown.setText("");
binding.progressBar.setVisibility(View.GONE);
});
}
} else {
switch(response.code()) {
case 401:
AlertDialogs.authorizationTokenRevokedDialog(ctx,
getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
break;
case 403:
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
break;
case 404:
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
break;
default:
Toasty.error(ctx, getString(R.string.labelGeneralError));
singleFileContents.setText("");
mProgressBar.setVisibility(View.GONE);
}
}
else if(response.code() == 401) {
} catch(IOException ignored) {}
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle), getResources().getString(R.string.alertDialogTokenRevokedMessage), getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 403) {
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
}
else if(response.code() == 404) {
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
}
else {
Toasty.error(ctx, getString(R.string.labelGeneralError));
}
}
@Override
public void onFailure(@NonNull Call<Files> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
thread.start();
}
@Override
@ -297,11 +275,11 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
inflater.inflate(R.menu.files_view_menu, menu);
String fileExtension = FileUtils.getExtension(singleFileName);
if(!FileUtils.getExtension(file.getName())
.equalsIgnoreCase("md")) {
if(!fileExtension.equalsIgnoreCase("md")) {
menu.getItem(0).setVisible(false);
menu.getItem(0)
.setVisible(false);
}
return true;
@ -316,35 +294,36 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie
finish();
return true;
}
else if(id == R.id.genericMenu) {
} else if(id == R.id.genericMenu) {
BottomSheetFileViewerFragment bottomSheet = new BottomSheetFileViewerFragment();
bottomSheet.show(getSupportFragmentManager(), "fileViewerBottomSheet");
return true;
}
else if(id == R.id.markdown) {
new Markdown(ctx, EmojiParser.parseToUnicode(AppUtil.decodeBase64(tinyDB.getString("downloadFileContents"))), singleFileContents);
} else if(id == R.id.markdown) {
if(!tinyDB.getBoolean("enableMarkdownInFileView")) {
singleCodeContents.setVisibility(View.GONE);
singleFileContentsFrame.setVisibility(View.VISIBLE);
singleFileContents.setVisibility(View.VISIBLE);
tinyDB.putBoolean("enableMarkdownInFileView", true);
}
else {
new Markdown(ctx, EmojiParser.parseToUnicode(binding.contents.getContent()), binding.markdown);
binding.contents.setVisibility(View.GONE);
binding.markdownFrame.setVisibility(View.VISIBLE);
tinyDB.putBoolean("enableMarkdownInFileView", true);
} else {
binding.markdownFrame.setVisibility(View.GONE);
binding.contents.setVisibility(View.VISIBLE);
singleCodeContents.setVisibility(View.VISIBLE);
singleFileContentsFrame.setVisibility(View.GONE);
singleFileContents.setVisibility(View.GONE);
singleCodeContents.setSource(AppUtil.decodeBase64(tinyDB.getString("downloadFileContents")));
tinyDB.putBoolean("enableMarkdownInFileView", false);
}
return true;
}
else {
} else {
return super.onOptionsItemSelected(item);
}
@ -360,102 +339,118 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie
if("deleteFile".equals(text)) {
String fileExtension = FileUtils.getExtension(singleFileName);
String data = AppUtil.getFileType(fileExtension) == AppUtil.FileType.TEXT ?
AppUtil.decodeBase64(tinyDB.getString("downloadFileContents")) : "";
Intent intent = new Intent(ctx, CreateFileActivity.class);
intent.putExtra("fileAction", CreateFileActivity.FILE_ACTION_DELETE);
intent.putExtra("filePath", singleFileName);
intent.putExtra("fileSha", fileSha);
intent.putExtra("fileContents", data);
intent.putExtra("filePath", file.getPath());
intent.putExtra("fileSha", file.getSha());
ctx.startActivity(intent);
}
if("editFile".equals(text)) {
String fileExtension = FileUtils.getExtension(singleFileName);
if(binding.contents.getContent() != null &&
!binding.contents.getContent().isEmpty()) {
switch(AppUtil.getFileType(fileExtension)) {
Intent intent = new Intent(ctx, CreateFileActivity.class);
case TEXT:
intent.putExtra("fileAction", CreateFileActivity.FILE_ACTION_EDIT);
intent.putExtra("filePath", file.getPath());
intent.putExtra("fileSha", file.getSha());
intent.putExtra("fileContents", binding.contents.getContent());
Intent intent = new Intent(ctx, CreateFileActivity.class);
ctx.startActivity(intent);
intent.putExtra("fileAction", CreateFileActivity.FILE_ACTION_EDIT);
intent.putExtra("filePath", singleFileName);
intent.putExtra("fileSha", fileSha);
intent.putExtra("fileContents", AppUtil.decodeBase64(tinyDB.getString("downloadFileContents")));
} else {
ctx.startActivity(intent);
break;
default:
Toasty.error(ctx, getString(R.string.fileTypeCannotBeEdited));
Toasty.error(ctx, getString(R.string.fileTypeCannotBeEdited));
}
}
}
private void requestFileDownload() {
if(!tinyDB.getString("downloadFileContents").isEmpty()) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
File outputFileName = new File(tinyDB.getString("downloadFileName"));
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_TITLE, file.getName());
intent.setType("*/*");
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
activityResultLauncher.launch(intent);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, outputFileName.getName());
fileDownloadActivityResultLauncher.launch(intent);
}
else {
Toasty.warning(ctx, getString(R.string.waitLoadingDownloadFile));
}
}
ActivityResultLauncher<Intent> fileDownloadActivityResultLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
assert result.getData() != null;
try {
try {
assert data != null;
Uri uri = data.getData();
OutputStream outputStream = getContentResolver().openOutputStream(result.getData().getData());
assert uri != null;
OutputStream outputStream = getContentResolver().openOutputStream(uri);
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx, ctx.getPackageName())
.setContentTitle(getString(R.string.fileViewerNotificationTitleStarted))
.setContentText(getString(R.string.fileViewerNotificationDescriptionStarted, file.getName()))
.setSmallIcon(R.drawable.gitnex_transparent)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setChannelId(Constants.downloadNotificationChannelId)
.setProgress(100, 0, false)
.setOngoing(true);
byte[] dataAsBytes = Base64.decode(tinyDB.getString("downloadFileContents"), 0);
int notificationId = Notifications.uniqueNotificationId(ctx);
assert outputStream != null;
outputStream.write(dataAsBytes);
outputStream.close();
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);;
notificationManager.notify(notificationId, builder.build());
Toasty.success(ctx, getString(R.string.downloadFileSaved));
}
catch(IOException e) {
String repoFullName = tinyDB.getString("repoFullName");
String repoBranch = tinyDB.getString("repoBranch");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Log.e("errorFileDownloading", Objects.requireNonNull(e.getMessage()));
}
}
Thread thread = new Thread(() -> {
});
try {
private void initCloseListener() {
Call<ResponseBody> call = RetrofitClient
.getWebInterface(ctx)
.getFileContents(Authorization.getWeb(ctx), repoOwner, repoName, repoBranch, file.getPath());
onClickListener = view -> {
Response<ResponseBody> response = call.execute();
getIntent().removeExtra("singleFileName");
finish();
};
}
assert response.body() != null;
AppUtil.copyProgress(response.body().byteStream(), outputStream, file.getSize(), progress -> {
builder.setProgress(100, progress, false);
notificationManager.notify(notificationId, builder.build());
});
builder.setContentTitle(getString(R.string.fileViewerNotificationTitleFinished))
.setContentText(getString(R.string.fileViewerNotificationDescriptionFinished, file.getName()));
} catch(IOException ignored) {
builder.setContentTitle(getString(R.string.fileViewerNotificationTitleFailed))
.setContentText(getString(R.string.fileViewerNotificationDescriptionFailed, file.getName()));
} finally {
builder.setProgress(0,0,false)
.setOngoing(false);
notificationManager.notify(notificationId, builder.build());
}
});
thread.start();
} catch(IOException ignored) {}
}
});
}

View File

@ -10,7 +10,6 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -61,8 +60,7 @@ import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import eightbitlab.com.blurview.BlurView;
import eightbitlab.com.blurview.RenderScriptBlur;
import jp.wasabeef.picasso.transformations.BlurTransformation;
import retrofit2.Call;
import retrofit2.Callback;
@ -73,12 +71,10 @@ import retrofit2.Callback;
public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, BottomSheetDraftsFragment.BottomSheetListener {
private DrawerLayout drawer;
private BlurView blurView;
private TextView userFullName;
private TextView userEmail;
private ImageView userAvatar;
private ImageView userAvatarBackground;
private ViewGroup navHeaderFrame;
private TextView toolbarTitle;
private Typeface myTypeface;
@ -273,12 +269,10 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
String userFullNameNav = tinyDB.getString("userFullname");
String userAvatarNav = tinyDB.getString("userAvatar");
blurView = hView.findViewById(R.id.blurView);
userEmail = hView.findViewById(R.id.userEmail);
userFullName = hView.findViewById(R.id.userFullname);
userAvatar = hView.findViewById(R.id.userAvatar);
userAvatarBackground = hView.findViewById(R.id.userAvatarBackground);
navHeaderFrame = hView.findViewById(R.id.navHeaderFrame);
List<UserAccount> userAccountsList;
userAccountsList = new ArrayList<>();
@ -323,24 +317,18 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
PicassoService.getInstance(ctx).get()
.load(userAvatarNav)
.transform(new BlurTransformation(ctx))
.into(userAvatarBackground, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
int textColor = new ColorInverter().getImageViewContrastColor(userAvatarBackground);
userFullName.setTextColor(textColor);
userEmail.setTextColor(textColor);
blurView.setupWith(navHeaderFrame)
.setBlurAlgorithm(new RenderScriptBlur(ctx))
.setBlurRadius(5)
.setHasFixedTransformationMatrix(false);
}
@Override
public void onError(Exception e) {}
@Override public void onError(Exception e) {}
});
}
@ -350,6 +338,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
navigationView.setCheckedItem(R.id.nav_profile);
drawer.closeDrawers();
});
getNotificationsCount(instanceToken);
@ -403,22 +392,21 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
switch(launchFragmentByHandler) {
case "repos":
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new RepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_repositories);
return;
case "org":
case "org":
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OrganizationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_organizations);
return;
case "notification":
case "notification":
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new NotificationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_notifications);
return;
case "explore":
case "explore":
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ExploreFragment()).commit();
navigationView.setCheckedItem(R.id.nav_explore);
return;
@ -438,49 +426,48 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
switch(tinyDB.getInt("homeScreenId")) {
case 1:
toolbarTitle.setText(getResources().getString(R.string.pageTitleStarredRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new StarredRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_starred_repos);
break;
case 2:
case 2:
toolbarTitle.setText(getResources().getString(R.string.pageTitleOrganizations));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new OrganizationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_organizations);
break;
case 3:
case 3:
toolbarTitle.setText(getResources().getString(R.string.pageTitleRepositories));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new RepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_repositories);
break;
case 4:
case 4:
toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit();
navigationView.setCheckedItem(R.id.nav_profile);
break;
case 5:
case 5:
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ExploreFragment()).commit();
navigationView.setCheckedItem(R.id.nav_explore);
break;
case 6:
case 6:
toolbarTitle.setText(getResources().getString(R.string.titleDrafts));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new DraftsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_comments_draft);
break;
case 7:
case 7:
toolbarTitle.setText(getResources().getString(R.string.pageTitleNotifications));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new NotificationsFragment()).commit();
navigationView.setCheckedItem(R.id.nav_notifications);
break;
default:
default:
toolbarTitle.setText(getResources().getString(R.string.pageTitleMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyRepositoriesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);

View File

@ -21,7 +21,6 @@ import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Objects;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
@ -170,12 +169,12 @@ public class MergePullRequestActivity extends BaseActivity {
MergePullRequest mergePR = new MergePullRequest(Do, mergePRDT, mergeTitle);
Call<ResponseBody> call = RetrofitClient.getApiInterface(ctx).mergePullRequest(Authorization.get(ctx), repoOwner, repoName, prIndex, mergePR);
Call<Void> call = RetrofitClient.getApiInterface(ctx).mergePullRequest(Authorization.get(ctx), repoOwner, repoName, prIndex, mergePR);
call.enqueue(new Callback<ResponseBody>() {
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
if(response.code() == 200) {
@ -244,7 +243,7 @@ public class MergePullRequestActivity extends BaseActivity {
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();

View File

@ -27,7 +27,7 @@ import org.mian.gitnex.adapters.RepoForksAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityRepoForksBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
@ -46,7 +46,7 @@ public class RepoForksActivity extends BaseActivity {
private TextView noData;
private ProgressBar progressBar;
private String TAG = "RepositoryForks";
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private int pageSize = 1;
private RecyclerView recyclerView;
@ -90,7 +90,7 @@ public class RepoForksActivity extends BaseActivity {
// if gitea is 1.12 or higher use the new limit (resultLimitNewGiteaInstances)
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
recyclerView = activityRepoForksBinding.recyclerView;

View File

@ -1,89 +0,0 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.switchmaterial.SwitchMaterial;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsFileviewerBinding;
import org.mian.gitnex.helpers.Toasty;
/**
* Author M M Arif
*/
public class SettingsFileViewerActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private static final String[] fileViewerSourceCodeThemesList = {"Sublime", "Arduino Light", "Github", "Far ", "Ir Black", "Android Studio"};
private static int fileViewerSourceCodeThemesSelectedChoice = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySettingsFileviewerBinding activitySettingsFileviewerBinding = ActivitySettingsFileviewerBinding.inflate(getLayoutInflater());
setContentView(activitySettingsFileviewerBinding.getRoot());
ImageView closeActivity = activitySettingsFileviewerBinding.close;
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
TextView fileViewerSourceCodeThemesSelected = activitySettingsFileviewerBinding.sourceCodeThemeSelected; // setter for fileviewer theme
LinearLayout sourceCodeThemeFrame = activitySettingsFileviewerBinding.sourceCodeThemeFrame;
SwitchMaterial pdfModeSwitch = activitySettingsFileviewerBinding.switchPdfMode;
if(!tinyDB.getString("fileviewerSourceCodeThemeStr").isEmpty()) {
fileViewerSourceCodeThemesSelected.setText(tinyDB.getString("fileviewerSourceCodeThemeStr"));
}
if(fileViewerSourceCodeThemesSelectedChoice == 0) {
fileViewerSourceCodeThemesSelectedChoice = tinyDB.getInt("fileviewerThemeId");
}
pdfModeSwitch.setChecked(tinyDB.getBoolean("enablePdfMode"));
// fileviewer srouce code theme selection dialog
sourceCodeThemeFrame.setOnClickListener(view -> {
AlertDialog.Builder fvtsBuilder = new AlertDialog.Builder(SettingsFileViewerActivity.this);
fvtsBuilder.setTitle(R.string.fileViewerSourceCodeThemeSelectorDialogTitle);
fvtsBuilder.setCancelable(fileViewerSourceCodeThemesSelectedChoice != -1);
fvtsBuilder.setSingleChoiceItems(fileViewerSourceCodeThemesList, fileViewerSourceCodeThemesSelectedChoice, (dialogInterfaceTheme, i) -> {
fileViewerSourceCodeThemesSelectedChoice = i;
fileViewerSourceCodeThemesSelected.setText(fileViewerSourceCodeThemesList[i]);
tinyDB.putString("fileviewerSourceCodeThemeStr", fileViewerSourceCodeThemesList[i]);
tinyDB.putInt("fileviewerSourceCodeThemeId", i);
dialogInterfaceTheme.dismiss();
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
AlertDialog cfDialog = fvtsBuilder.create();
cfDialog.show();
});
// pdf night mode switcher
pdfModeSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
tinyDB.putBoolean("enablePdfMode", isChecked);
tinyDB.putString("enablePdfModeInit", "yes");
Toasty.success(appCtx, getResources().getString(R.string.settingsSave));
});
}
private void initCloseListener() {
onClickListener = view -> finish();
}
}

View File

@ -8,7 +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.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.notifications.Notifications;
@ -33,7 +33,7 @@ public class SettingsNotificationsActivity extends BaseActivity {
viewBinding.close.setOnClickListener(onClickListener);
viewBinding.pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay)));
viewBinding.pollingDelaySelected.setText(String.format(getString(R.string.pollingDelaySelectedText), tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay)));
viewBinding.chooseColorState.setCardBackgroundColor(tinyDB.getInt("notificationsLightColor", Color.GREEN));
viewBinding.enableNotificationsMode.setChecked(tinyDB.getBoolean("notificationsEnabled", true));
@ -52,9 +52,9 @@ public class SettingsNotificationsActivity extends BaseActivity {
viewBinding.pollingDelayFrame.setOnClickListener(v -> {
NumberPicker numberPicker = new NumberPicker(ctx);
numberPicker.setMinValue(StaticGlobalVariables.minimumPollingDelay);
numberPicker.setMaxValue(StaticGlobalVariables.maximumPollingDelay);
numberPicker.setValue(tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay));
numberPicker.setMinValue(Constants.minimumPollingDelay);
numberPicker.setMaxValue(Constants.maximumPollingDelay);
numberPicker.setValue(tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay));
numberPicker.setWrapSelectorWheel(true);
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
@ -76,6 +76,7 @@ public class SettingsNotificationsActivity extends BaseActivity {
builder.setNeutralButton(R.string.cancelButton, (dialog, which) -> dialog.dismiss());
builder.setView(numberPicker);
builder.create().show();
});
// lights switcher

View File

@ -7,6 +7,7 @@ import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources;
@ -14,7 +15,6 @@ import androidx.recyclerview.widget.RecyclerView;
import org.apache.commons.io.FileUtils;
import org.gitnex.tea4j.models.Files;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.Toasty;
import java.util.ArrayList;
import java.util.List;
@ -33,14 +33,14 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
public interface FilesAdapterListener {
void onClickDir(String str);
void onClickFile(String str);
void onClickFile(Files file);
}
class FilesViewHolder extends RecyclerView.ViewHolder {
private String fileType;
private Files file;
private final LinearLayout fileFrame;
private final ImageView fileTypeIs;
private final TextView fileName;
private final TextView fileInfo;
@ -49,29 +49,15 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
super(itemView);
fileFrame = itemView.findViewById(R.id.fileFrame);
fileName = itemView.findViewById(R.id.fileName);
fileTypeIs = itemView.findViewById(R.id.fileTypeIs);
fileInfo = itemView.findViewById(R.id.fileInfo);
fileFrame.setOnClickListener(v -> filesListener.onClickFile(file));
//ImageView filesDropdownMenu = itemView.findViewById(R.id.filesDropdownMenu);
fileName.setOnClickListener(v -> {
Context context = v.getContext();
if(fileType.equals("file")) {
filesListener.onClickFile(fileName.getText().toString());
}
else if(fileType.equals("dir")) {
filesListener.onClickDir(fileName.getText().toString());
}
else {
Toasty.warning(context, context.getString(R.string.filesGenericError));
}
});
/*filesDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -170,25 +156,36 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
Files currentItem = alteredFiles.get(position);
holder.fileType = currentItem.getType();
holder.file = currentItem;
holder.fileName.setText(currentItem.getName());
if(currentItem.getType().equals("file")) {
switch(currentItem.getType()) {
case "file":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_file));
holder.fileInfo.setVisibility(View.VISIBLE);
holder.fileInfo.setText(FileUtils.byteCountToDisplaySize(currentItem.getSize()));
break;
case "dir":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_directory));
holder.fileInfo.setVisibility(View.GONE);
break;
case "submodule":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_submodule));
holder.fileInfo.setVisibility(View.GONE);
break;
case "symlink":
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_symlink));
holder.fileInfo.setVisibility(View.GONE);
break;
default:
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_question));
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_file));
holder.fileInfo.setVisibility(View.VISIBLE);
holder.fileInfo.setText(FileUtils.byteCountToDisplaySize(currentItem.getSize()));
}
else if(currentItem.getType().equals("dir")) {
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_directory));
holder.fileInfo.setVisibility(View.GONE);
}
else {
holder.fileTypeIs.setImageDrawable(AppCompatResources.getDrawable(mCtx, R.drawable.ic_question));
}
}
@Override
@ -224,6 +221,7 @@ public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.FilesViewHol
results.values = filteredList;
return results;
}
@Override

View File

@ -102,9 +102,8 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
class IssuesHolder extends RecyclerView.ViewHolder {
private String userLoginId;
private Issues issue;
private final TextView issueNumber;
private final ImageView issueAssigneeAvatar;
private final TextView issueTitle;
private final TextView issueCreatedTime;
@ -114,7 +113,6 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
super(itemView);
issueNumber = itemView.findViewById(R.id.issueNumber);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
@ -126,10 +124,10 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Context context = title.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
intent.putExtra("issueNumber", issue.getNumber());
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
tinyDb.putString("issueNumber", String.valueOf(issue.getNumber()));
tinyDb.putString("issueType", "Issue");
context.startActivity(intent);
@ -140,18 +138,18 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Context context = commentsCount.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
intent.putExtra("issueNumber", issue.getNumber());
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
tinyDb.putString("issueNumber", String.valueOf(issue.getNumber()));
tinyDb.putString("issueType", "Issue");
context.startActivity(intent);
});
issueAssigneeAvatar.setOnClickListener(loginId -> {
Context context = loginId.getContext();
issueAssigneeAvatar.setOnClickListener(v -> {
Context context = v.getContext();
String userLoginId = issue.getUser().getLogin();
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
});
@ -159,40 +157,44 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
@SuppressLint("SetTextI18n")
void bindData(Issues issuesModel) {
void bindData(Issues issue) {
final TinyDB tinyDb = TinyDB.getInstance(context);
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
TinyDB tinyDb = TinyDB.getInstance(context);
String locale = tinyDb.getString("locale");
String timeFormat = tinyDb.getString("dateFormat");
userLoginId = issuesModel.getUser().getLogin();
PicassoService.getInstance(context).get()
.load(issue.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(8, 0))
.resize(120, 120)
.centerCrop()
.into(issueAssigneeAvatar);
PicassoService.getInstance(context).get().load(issuesModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
String issueNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + issue.getNumber() + "</font>";
issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + EmojiParser.parseToUnicode(issue.getTitle()), HtmlCompat.FROM_HTML_MODE_LEGACY));
String issueNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + issuesModel.getNumber() + "</font>";
issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + EmojiParser.parseToUnicode(issuesModel.getTitle()), HtmlCompat.FROM_HTML_MODE_LEGACY));
issueNumber.setText(String.valueOf(issuesModel.getNumber()));
issueCommentsCount.setText(String.valueOf(issuesModel.getComments()));
this.issue = issue;
this.issueCommentsCount.setText(String.valueOf(issue.getComments()));
switch(timeFormat) {
case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issuesModel.getCreated_at()), context));
String createdTime = prettyTime.format(issue.getCreated_at());
this.issueCreatedTime.setText(createdTime);
this.issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issue.getCreated_at()), context));
break;
}
case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime);
String createdTime = formatter.format(issue.getCreated_at());
this.issueCreatedTime.setText(createdTime);
break;
}
case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime);
String createdTime = formatter.format(issue.getCreated_at());
this.issueCreatedTime.setText(createdTime);
break;
}
}

View File

@ -18,8 +18,8 @@ import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.MilestoneActions;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import java.text.DateFormat;
@ -41,7 +41,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false;
private boolean isMoreDataAvailable = true;
private String TAG = StaticGlobalVariables.tagMilestonesAdapter;
private String TAG = Constants.tagMilestonesAdapter;
public MilestonesAdapter(Context context, List<Milestones> dataListMain) {

View File

@ -292,7 +292,7 @@ public class MyReposListAdapter extends RecyclerView.Adapter<MyReposListAdapter.
}
holder.repoFullName.setText(currentItem.getFullName());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock);
holder.repoPrivatePublic.setVisibility(View.VISIBLE);
holder.repoType.setText(R.string.strPrivate);
}
else {

View File

@ -67,15 +67,11 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
isLoading = true;
loadMoreListener.onLoadMore();
}
if(getItemViewType(position) == TYPE_LOAD) {
((PullRequestsAdapter.PullRequestsHolder) holder).bindData(prList.get(position));
}
}
@Override
@ -87,7 +83,6 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
else {
return 1;
}
}
@Override
@ -99,13 +94,8 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
class PullRequestsHolder extends RecyclerView.ViewHolder {
private String userLoginId;
private PullRequests pullRequest;
private final TextView prNumber;
private final TextView prMergeable;
private final TextView prHeadBranch;
private final TextView prIsFork;
private final TextView prForkFullName;
private final ImageView assigneeAvatar;
private final TextView prTitle;
private final TextView prCreatedTime;
@ -115,11 +105,6 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
super(itemView);
prNumber = itemView.findViewById(R.id.prNumber);
prMergeable = itemView.findViewById(R.id.prMergeable);
prHeadBranch = itemView.findViewById(R.id.prHeadBranch);
prIsFork = itemView.findViewById(R.id.prIsFork);
prForkFullName = itemView.findViewById(R.id.prForkFullName);
assigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
prTitle = itemView.findViewById(R.id.prTitle);
prCommentsCount = itemView.findViewById(R.id.prCommentsCount);
@ -131,16 +116,25 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText());
intent.putExtra("prMergeable", prMergeable.getText());
intent.putExtra("prHeadBranch", prHeadBranch.getText());
intent.putExtra("issueNumber", pullRequest.getNumber());
intent.putExtra("prMergeable", pullRequest.isMergeable());
intent.putExtra("prHeadBranch", pullRequest.getHead().getRef());
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("prMergeable", prMergeable.getText().toString());
tinyDb.putString("prHeadBranch", prHeadBranch.getText().toString());
tinyDb.putString("prIsFork", prIsFork.getText().toString());
tinyDb.putString("prForkFullName", prForkFullName.getText().toString());
tinyDb.putString("issueNumber", String.valueOf(pullRequest.getNumber()));
tinyDb.putString("prMergeable", String.valueOf(pullRequest.isMergeable()));
tinyDb.putString("prHeadBranch", pullRequest.getHead().getRef());
if(pullRequest.getHead() != null && pullRequest.getHead().getRepo() != null) {
tinyDb.putString("prIsFork", String.valueOf(pullRequest.getHead().getRepo().isFork()));
tinyDb.putString("prForkFullName", pullRequest.getHead().getRepo().getFull_name());
}
else {
// pull was done from a deleted fork
tinyDb.putString("prIsFork", "true");
tinyDb.putString("prForkFullName", context.getString(R.string.prDeletedFork));
}
tinyDb.putString("issueType", "Pull");
context.startActivity(intent);
@ -151,23 +145,33 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText());
intent.putExtra("prMergeable", prMergeable.getText());
intent.putExtra("prHeadBranch", prHeadBranch.getText());
intent.putExtra("issueNumber", pullRequest.getNumber());
intent.putExtra("prMergeable", pullRequest.isMergeable());
intent.putExtra("prHeadBranch", pullRequest.getHead().getRef());
TinyDB tinyDb = TinyDB.getInstance(context);
tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("prMergeable", prMergeable.getText().toString());
tinyDb.putString("prHeadBranch", prHeadBranch.getText().toString());
tinyDb.putString("prIsFork", prIsFork.getText().toString());
tinyDb.putString("prForkFullName", prForkFullName.getText().toString());
tinyDb.putString("issueNumber", String.valueOf(pullRequest.getNumber()));
tinyDb.putString("prMergeable", String.valueOf(pullRequest.isMergeable()));
tinyDb.putString("prHeadBranch", pullRequest.getHead().getRef());
if(pullRequest.getHead() != null && pullRequest.getHead().getRepo() != null) {
tinyDb.putString("prIsFork", String.valueOf(pullRequest.getHead().getRepo().isFork()));
tinyDb.putString("prForkFullName", pullRequest.getHead().getRepo().getFull_name());
}
else {
// pull was done from a deleted fork
tinyDb.putString("prIsFork", "true");
tinyDb.putString("prForkFullName", context.getString(R.string.prDeletedFork));
}
tinyDb.putString("issueType", "Pull");
context.startActivity(intent);
});
assigneeAvatar.setOnClickListener(loginId -> {
Context context = loginId.getContext();
assigneeAvatar.setOnClickListener(v -> {
Context context = v.getContext();
String userLoginId = pullRequest.getUser().getLogin();
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
});
@ -175,43 +179,32 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
@SuppressLint("SetTextI18n")
void bindData(PullRequests prModel) {
void bindData(PullRequests pullRequest) {
final TinyDB tinyDb = TinyDB.getInstance(context);
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
TinyDB tinyDb = TinyDB.getInstance(context);
String locale = tinyDb.getString("locale");
String timeFormat = tinyDb.getString("dateFormat");
userLoginId = prModel.getUser().getLogin();
PicassoService.getInstance(context).get()
.load(pullRequest.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(8, 0))
.resize(120, 120)
.centerCrop()
.into(this.assigneeAvatar);
PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
this.pullRequest = pullRequest;
String prNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + prModel.getNumber() + "</font>";
prTitle.setText(HtmlCompat.fromHtml(prNumber_ + " " + EmojiParser.parseToUnicode(prModel.getTitle()), HtmlCompat.FROM_HTML_MODE_LEGACY));
String prNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + pullRequest.getNumber() + "</font>";
prNumber.setText(String.valueOf(prModel.getNumber()));
prMergeable.setText(String.valueOf(prModel.isMergeable()));
if(prModel.getHead() != null) {
prHeadBranch.setText(prModel.getHead().getRef());
if(prModel.getHead().getRepo() != null) {
prIsFork.setText(String.valueOf(prModel.getHead().getRepo().isFork()));
prForkFullName.setText(prModel.getHead().getRepo().getFull_name());
}
else {
// pull was done from a deleted fork
prIsFork.setText("true");
prForkFullName.setText(context.getString(R.string.prDeletedFork));
}
}
prCommentsCount.setText(String.valueOf(prModel.getComments()));
prCreatedTime.setText(TimeHelper.formatTime(prModel.getCreated_at(), new Locale(locale), timeFormat, context));
this.prTitle.setText(HtmlCompat.fromHtml(prNumber_ + " " + EmojiParser.parseToUnicode(pullRequest.getTitle()), HtmlCompat.FROM_HTML_MODE_LEGACY));
this.prCommentsCount.setText(String.valueOf(pullRequest.getComments()));
this.prCreatedTime.setText(TimeHelper.formatTime(pullRequest.getCreated_at(), new Locale(locale), timeFormat, context));
if(timeFormat.equals("pretty")) {
prCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(prModel.getCreated_at()), context));
this.prCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(pullRequest.getCreated_at()), context));
}
}
}
static class LoadHolder extends RecyclerView.ViewHolder {

View File

@ -293,7 +293,7 @@ public class ReposListAdapter extends RecyclerView.Adapter<ReposListAdapter.Repo
}
holder.fullName.setText(currentItem.getFullName());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock);
holder.repoPrivatePublic.setVisibility(View.VISIBLE);
holder.repoType.setText(R.string.strPrivate);
}
else {

View File

@ -293,7 +293,7 @@ public class RepositoriesByOrgAdapter extends RecyclerView.Adapter<RepositoriesB
}
holder.fullName.setText(currentItem.getFullName());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock);
holder.repoPrivatePublic.setVisibility(View.VISIBLE);
holder.repoType.setText(R.string.strPrivate);
}
else {

View File

@ -47,39 +47,35 @@ public class SearchIssuesAdapter extends RecyclerView.Adapter<SearchIssuesAdapte
class SearchViewHolder extends RecyclerView.ViewHolder {
private String userLoginId;
private Issues issue;
private final TextView issueNumber;
private final ImageView issueAssigneeAvatar;
private final TextView issueTitle;
private final TextView issueCreatedTime;
private final TextView issueCommentsCount;
private final TextView repoFullName;
private SearchViewHolder(View itemView) {
super(itemView);
issueNumber = itemView.findViewById(R.id.issueNumber);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
repoFullName = itemView.findViewById(R.id.repoFullName);
issueTitle.setOnClickListener(v -> {
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
intent.putExtra("issueNumber", issue.getNumber());
tinyDb.putString("issueNumber", issueNumber.getText().toString());
tinyDb.putString("issueNumber", String.valueOf(issue.getNumber()));
tinyDb.putString("issueType", "Issue");
tinyDb.putString("repoFullName", repoFullName.getText().toString());
tinyDb.putString("repoFullName", issue.getRepository().getFull_name());
String[] parts = repoFullName.getText().toString().split("/");
String[] parts = issue.getRepository().getFull_name().split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
@ -104,14 +100,13 @@ public class SearchIssuesAdapter extends RecyclerView.Adapter<SearchIssuesAdapte
context.startActivity(intent);
});
issueAssigneeAvatar.setOnClickListener(loginId -> {
Context context = loginId.getContext();
issueAssigneeAvatar.setOnClickListener(v -> {
Context context = v.getContext();
String userLoginId = issue.getUser().getLogin();
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId));
});
}
}
@NonNull
@ -130,17 +125,19 @@ public class SearchIssuesAdapter extends RecyclerView.Adapter<SearchIssuesAdapte
String locale = tinyDb.getString("locale");
String timeFormat = tinyDb.getString("dateFormat");
holder.userLoginId = currentItem.getUser().getLogin();
PicassoService
.getInstance(mCtx).get().load(currentItem.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.issueAssigneeAvatar);
PicassoService.getInstance(mCtx).get()
.load(currentItem.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(8, 0))
.resize(120, 120)
.centerCrop()
.into(holder.issueAssigneeAvatar);
String issueNumber_ = "<font color='" + ResourcesCompat.getColor(mCtx.getResources(), R.color.lightGray, null) + "'>" + currentItem.getRepository().getFull_name() + mCtx.getResources().getString(R.string.hash) + currentItem.getNumber() + "</font>";
holder.issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + currentItem.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY));
holder.issueNumber.setText(String.valueOf(currentItem.getNumber()));
holder.issue = currentItem;
holder.issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + currentItem.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY));
holder.issueCommentsCount.setText(String.valueOf(currentItem.getComments()));
holder.repoFullName.setText(currentItem.getRepository().getFull_name());
switch(timeFormat) {
case "pretty": {

View File

@ -296,7 +296,7 @@ public class StarredReposListAdapter extends RecyclerView.Adapter<StarredReposLi
}
holder.fullName.setText(currentItem.getFullName());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock);
holder.repoPrivatePublic.setVisibility(View.VISIBLE);
holder.repoType.setText(R.string.strPrivate);
}
else {

View File

@ -18,7 +18,6 @@ import javax.net.ssl.X509TrustManager;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
@ -32,15 +31,12 @@ public class RetrofitClient {
private static final Map<String, ApiInterface> apiInterfaces = new ConcurrentHashMap<>();
private static final Map<String, WebInterface> webInterfaces = new ConcurrentHashMap<>();
private static Retrofit createRetrofit(Context context, String instanceUrl) {
private static Retrofit createRetrofit(Context context, String instanceUrl, boolean cacheEnabled) {
TinyDB tinyDB = TinyDB.getInstance(context);
int cacheSize = FilesData.returnOnlyNumber(tinyDB.getString("cacheSizeStr")) * 1024 * 1024;
Cache cache = new Cache(new File(context.getCacheDir(), "responses"), cacheSize);
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
try {
@ -49,11 +45,17 @@ public class RetrofitClient {
MemorizingTrustManager memorizingTrustManager = new MemorizingTrustManager(context);
sslContext.init(null, new X509TrustManager[]{ memorizingTrustManager }, new SecureRandom());
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder().cache(cache)
//.addInterceptor(logging)
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder()
// .addInterceptor(logging)
.sslSocketFactory(sslContext.getSocketFactory(), memorizingTrustManager)
.hostnameVerifier(memorizingTrustManager.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()))
.addInterceptor(chain -> {
.hostnameVerifier(memorizingTrustManager.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()));
if(cacheEnabled) {
int cacheSize = FilesData.returnOnlyNumber(tinyDB.getString("cacheSizeStr")) * 1024 * 1024;
Cache cache = new Cache(new File(context.getCacheDir(), "responses"), cacheSize);
okHttpClient.cache(cache).addInterceptor(chain -> {
Request request = chain.request();
@ -64,6 +66,7 @@ public class RetrofitClient {
return chain.proceed(request);
});
}
return new Retrofit.Builder()
.baseUrl(instanceUrl)
@ -101,7 +104,7 @@ public class RetrofitClient {
synchronized(RetrofitClient.class) {
if(!apiInterfaces.containsKey(url)) {
ApiInterface apiInterface = createRetrofit(context, url).create(ApiInterface.class);
ApiInterface apiInterface = createRetrofit(context, url, true).create(ApiInterface.class);
apiInterfaces.put(url, apiInterface);
return apiInterface;
@ -119,7 +122,7 @@ public class RetrofitClient {
synchronized(RetrofitClient.class) {
if(!webInterfaces.containsKey(url)) {
WebInterface webInterface = createRetrofit(context, url).create(WebInterface.class);
WebInterface webInterface = createRetrofit(context, url, false).create(WebInterface.class);
webInterfaces.put(url, webInterface);
return webInterface;

View File

@ -14,8 +14,8 @@ import org.acra.config.MailSenderConfigurationBuilder;
import org.acra.data.StringFormat;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.FontsOverride;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.notifications.Notifications;
@ -28,7 +28,9 @@ import org.mian.gitnex.notifications.Notifications;
resTitle = R.string.crashTitle,
resChannelName = R.string.setCrashReports,
resText = R.string.crashMessage)
@AcraCore(reportContent = { ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL, ReportField.STACK_TRACE })
@AcraCore(reportContent = {
ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL,
ReportField.STACK_TRACE, ReportField.AVAILABLE_MEM_SIZE, ReportField.BRAND })
public class MainApplication extends Application {
@ -69,20 +71,26 @@ public class MainApplication extends Application {
}
Notifications.createChannels(appCtx);
}
@Override
protected void attachBaseContext(Context context) {
super.attachBaseContext(context);
tinyDB = TinyDB.getInstance(context);
if(tinyDB.getBoolean("crashReportingEnabled")) {
CoreConfigurationBuilder ACRABuilder = new CoreConfigurationBuilder(this);
ACRABuilder.setBuildConfigClass(BuildConfig.class).setReportFormat(StringFormat.KEY_VALUE_LIST);
ACRABuilder.getPluginConfigurationBuilder(MailSenderConfigurationBuilder.class).setReportAsFile(true).setMailTo(getResources().getString(R.string.appEmail)).setSubject(getResources().getString(R.string.crashReportEmailSubject, AppUtil.getAppBuildNo(getApplicationContext()))).setEnabled(true);
ACRABuilder.getPluginConfigurationBuilder(MailSenderConfigurationBuilder.class).setReportAsFile(true).setMailTo(getResources().getString(R.string.appEmail)).setSubject(getResources().getString(R.string.crashReportEmailSubject, AppUtil
.getAppBuildNo(context))).setEnabled(true);
ACRABuilder.getPluginConfigurationBuilder(LimiterConfigurationBuilder.class).setEnabled(true);
ACRA.init(this, ACRABuilder);
}
Notifications.startWorker(appCtx);
}
private void setDefaults() {
@ -121,7 +129,7 @@ public class MainApplication extends Application {
// setting default polling delay
if(tinyDB.getInt("pollingDelayMinutes", 0) <= 0) {
tinyDB.putInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay);
tinyDB.putInt("pollingDelayMinutes", Constants.defaultPollingDelay);
}
// disable biometric by default

View File

@ -0,0 +1,140 @@
package org.mian.gitnex.core;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import io.noties.prism4j.GrammarLocator;
import io.noties.prism4j.Prism4j;
import io.noties.prism4j.annotations.PrismBundle;
/**
* @author opyale
*/
@PrismBundle(
includeAll = true,
grammarLocatorClassName = ".DefaultGrammarLocator"
)
public class MainGrammarLocator implements GrammarLocator {
public static final String DEFAULT_FALLBACK_LANGUAGE = "clike";
private static final DefaultGrammarLocator defaultGrammarLocator = new DefaultGrammarLocator();
private static volatile MainGrammarLocator instance;
private MainGrammarLocator() {}
public String fromExtension(String extension) {
switch(extension.toLowerCase()) {
case "b":
case "bf":
return "brainfuck";
case "c":
case "h":
case "hdl":
return "c";
case "clj":
case "cljs":
case "cljc":
case "edn":
return "clojure";
case "cc":
case "cpp":
case "cxx":
case "c++":
case "hh":
case "hpp":
case "hxx":
case "h++":
return "cpp";
case "cs":
case "csx":
return "csharp";
case "groovy":
case "gradle":
case "gvy":
case "gy":
case "gsh":
return "groovy";
case "js":
case "cjs":
case "mjs":
return "javascript";
case "kt":
case "kts":
case "ktm":
return "kotlin";
case "md":
return "markdown";
case "xml":
case "html":
case "htm":
case "mathml":
case "svg":
return "markup";
case "py":
case "pyi":
case "pyc":
case "pyd":
case "pyo":
case "pyw":
case "pyz":
return "python";
case "scala":
case "sc":
return "scala";
case "yaml":
case "yml":
case "properties": // This extension doesn't correspond to YAML, but it's the next best option
case "ini": // This extension doesn't correspond to YAML, but it's the next best option
return "yaml";
}
return extension;
}
@Nullable
@Override
public Prism4j.Grammar grammar(@NotNull Prism4j prism4j, @NotNull String language) {
return defaultGrammarLocator.grammar(prism4j, language);
}
@NotNull
@Override
public Set<String> languages() {
return defaultGrammarLocator.languages();
}
public static MainGrammarLocator getInstance() {
if(instance == null) {
synchronized(MainGrammarLocator.class) {
if(instance == null) {
instance = new MainGrammarLocator();
}
}
}
return instance;
}
}

View File

@ -7,7 +7,7 @@ import org.mian.gitnex.database.dao.DraftsDao;
import org.mian.gitnex.database.db.GitnexDatabase;
import org.mian.gitnex.database.models.Draft;
import org.mian.gitnex.database.models.DraftWithRepository;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import java.util.List;
/**
@ -51,7 +51,7 @@ public class DraftsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.draftsApi, e.toString());
Log.e(Constants.draftsApi, e.toString());
}
return draftId;
@ -67,7 +67,7 @@ public class DraftsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.draftsApi, e.toString());
Log.e(Constants.draftsApi, e.toString());
}
return draftId;
@ -83,7 +83,7 @@ public class DraftsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.draftsApi, e.toString());
Log.e(Constants.draftsApi, e.toString());
}
return checkDraftFlag;

View File

@ -6,7 +6,7 @@ import androidx.lifecycle.LiveData;
import org.mian.gitnex.database.dao.RepositoriesDao;
import org.mian.gitnex.database.db.GitnexDatabase;
import org.mian.gitnex.database.models.Repository;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import java.util.List;
/**
@ -47,7 +47,7 @@ public class RepositoriesApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.repositoriesApi, e.toString());
Log.e(Constants.repositoriesApi, e.toString());
}
return repositoryId;
@ -63,7 +63,7 @@ public class RepositoriesApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.repositoriesApi, e.toString());
Log.e(Constants.repositoriesApi, e.toString());
}
return repository;
@ -89,7 +89,7 @@ public class RepositoriesApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.repositoriesApi, e.toString());
Log.e(Constants.repositoriesApi, e.toString());
}
return checkRepository;
@ -105,7 +105,7 @@ public class RepositoriesApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.repositoriesApi, e.toString());
Log.e(Constants.repositoriesApi, e.toString());
}
return repository;
@ -121,7 +121,7 @@ public class RepositoriesApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.repositoriesApi, e.toString());
Log.e(Constants.repositoriesApi, e.toString());
}
return repository;

View File

@ -6,7 +6,7 @@ import androidx.lifecycle.LiveData;
import org.mian.gitnex.database.dao.UserAccountsDao;
import org.mian.gitnex.database.db.GitnexDatabase;
import org.mian.gitnex.database.models.UserAccount;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import java.util.List;
/**
@ -50,7 +50,7 @@ public class UserAccountsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.userAccountsApi, e.toString());
Log.e(Constants.userAccountsApi, e.toString());
}
return accountId;
@ -81,7 +81,7 @@ public class UserAccountsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.userAccountsApi, e.toString());
Log.e(Constants.userAccountsApi, e.toString());
}
return userAccount;
@ -97,7 +97,7 @@ public class UserAccountsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.userAccountsApi, e.toString());
Log.e(Constants.userAccountsApi, e.toString());
}
return checkAccount;
@ -118,7 +118,7 @@ public class UserAccountsApi {
}
catch(InterruptedException e) {
Log.e(StaticGlobalVariables.userAccountsApi, e.toString());
Log.e(Constants.userAccountsApi, e.toString());
}
return userAccounts;

View File

@ -10,7 +10,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.databinding.BottomSheetDraftsBinding;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
/**
* Author M M Arif
@ -18,7 +18,7 @@ import org.mian.gitnex.helpers.StaticGlobalVariables;
public class BottomSheetDraftsFragment extends BottomSheetDialogFragment {
private String TAG = StaticGlobalVariables.tagDraftsBottomSheet;
private String TAG = Constants.tagDraftsBottomSheet;
private BottomSheetDraftsFragment.BottomSheetListener bmListener;
@Nullable

View File

@ -25,7 +25,7 @@ import org.mian.gitnex.actions.IssueActions;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.database.api.DraftsApi;
import org.mian.gitnex.databinding.BottomSheetReplyLayoutBinding;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.util.Objects;
@ -266,11 +266,11 @@ public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
String draftType;
if(tinyDB.getString("issueType").equalsIgnoreCase("Issue")) {
draftType = StaticGlobalVariables.draftTypeIssue;
draftType = Constants.draftTypeIssue;
}
else if(tinyDB.getString("issueType").equalsIgnoreCase("Pull")) {
draftType = StaticGlobalVariables.draftTypePull;
draftType = Constants.draftTypePull;
}
else {

View File

@ -28,8 +28,8 @@ import org.mian.gitnex.databinding.CustomExploreRepositoriesDialogBinding;
import org.mian.gitnex.databinding.FragmentExploreRepoBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.InfiniteScrollListener;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
@ -80,7 +80,7 @@ public class ExploreRepositoriesFragment extends Fragment {
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
limit = StaticGlobalVariables.resultLimitNewGiteaInstances;
limit = Constants.resultLimitNewGiteaInstances;
}
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx);
@ -104,7 +104,7 @@ public class ExploreRepositoriesFragment extends Fragment {
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
limit = StaticGlobalVariables.resultLimitNewGiteaInstances;
limit = Constants.resultLimitNewGiteaInstances;
}
else {
limit = 10;
@ -134,7 +134,7 @@ public class ExploreRepositoriesFragment extends Fragment {
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
limit = StaticGlobalVariables.resultLimitNewGiteaInstances;
limit = Constants.resultLimitNewGiteaInstances;
}
else {
limit = 10;
@ -156,7 +156,7 @@ public class ExploreRepositoriesFragment extends Fragment {
int apiCallDefaultLimit = 10;
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
apiCallDefaultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
apiCallDefaultLimit = Constants.resultLimitNewGiteaInstances;
}
if(apiCallDefaultLimit > limit) {

View File

@ -11,15 +11,12 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.Files;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.FileViewActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
@ -31,7 +28,6 @@ import org.mian.gitnex.helpers.Path;
import org.mian.gitnex.viewmodels.FilesViewModel;
import java.util.ArrayList;
import java.util.Collections;
import moe.feng.common.view.breadcrumbs.BreadcrumbsView;
import moe.feng.common.view.breadcrumbs.DefaultBreadcrumbsCallback;
import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem;
@ -41,15 +37,11 @@ import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem;
public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapterListener {
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
private TextView noDataFiles;
private LinearLayout filesFrame;
private FragmentFilesBinding binding;
private static final String repoNameF = "param2";
private static final String repoOwnerF = "param1";
private static final String repoRefF = "param3";
private BreadcrumbsView mBreadcrumbsView;
private String repoName;
private String repoOwner;
@ -92,28 +84,21 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentFilesBinding fragmentFilesBinding = FragmentFilesBinding.inflate(inflater, container, false);
binding = FragmentFilesBinding.inflate(inflater, container, false);
setHasOptionsMenu(true);
noDataFiles = fragmentFilesBinding.noDataFiles;
filesFrame = fragmentFilesBinding.filesFrame;
filesAdapter = new FilesAdapter(getContext(), this);
mRecyclerView = fragmentFilesBinding.recyclerView;
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.setAdapter(filesAdapter);
binding.recyclerView.setHasFixedSize(true);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerView.setAdapter(filesAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(binding.recyclerView.getContext(), DividerItemDecoration.VERTICAL);
binding.recyclerView.addItemDecoration(dividerItemDecoration);
mProgressBar = fragmentFilesBinding.progressBar;
mBreadcrumbsView = fragmentFilesBinding.breadcrumbsView;
mBreadcrumbsView.setItems(new ArrayList<>(Collections.singletonList(BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot) + getResources().getString(R.string.colonDivider) + ref))));
binding.breadcrumbsView.setItems(new ArrayList<>(Collections.singletonList(BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot) + getResources().getString(R.string.colonDivider) + ref))));
// noinspection unchecked
mBreadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() {
binding.breadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() {
@SuppressLint("SetTextI18n")
@Override
@ -140,14 +125,14 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
path.clear();
ref = repoBranch;
mBreadcrumbsView.setItems(new ArrayList<>(Collections.singletonList(BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot) + getResources().getString(R.string.colonDivider) + ref))));
binding.breadcrumbsView.setItems(new ArrayList<>(Collections.singletonList(BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot) + getResources().getString(R.string.colonDivider) + ref))));
fetchDataAsync(Authorization.get(getContext()), repoOwner, repoName, repoBranch);
});
fetchDataAsync(Authorization.get(getContext()), repoOwner, repoName, ref);
return fragmentFilesBinding.getRoot();
return binding.getRoot();
}
@Override
@ -157,40 +142,35 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
}
@Override
public void onClickDir(String dirName) {
public void onClickFile(Files file) {
path.add(dirName);
mBreadcrumbsView.addItem(new BreadcrumbItem(Collections.singletonList(dirName)));
switch(file.getType()) {
fetchDataAsyncSub(Authorization.get(getContext()), repoOwner, repoName, path.toString(), ref);
case "dir":
path.add(file.getName());
binding.breadcrumbsView.addItem(new BreadcrumbItem(Collections.singletonList(file.getName())));
}
fetchDataAsyncSub(Authorization.get(getContext()), repoOwner, repoName, path.toString(), ref);
break;
@Override
public void onClickFile(String fileName) {
case "file":
Intent intent = new Intent(getContext(), FileViewActivity.class);
intent.putExtra("file", file);
Intent intent = new Intent(getContext(), FileViewActivity.class);
requireContext().startActivity(intent);
break;
if(path.size() != 0) {
intent.putExtra("singleFileName", path.toString() + "/" + fileName);
}
else {
intent.putExtra("singleFileName", fileName);
}
requireContext().startActivity(intent);
}
private void fetchDataAsync(String instanceToken, String owner, String repo, String ref) {
mRecyclerView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
binding.recyclerView.setVisibility(View.GONE);
binding.progressBar.setVisibility(View.VISIBLE);
FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel.getFilesList(instanceToken, owner, repo, ref, getContext(), mProgressBar, noDataFiles).observe(getViewLifecycleOwner(), filesListMain -> {
filesModel.getFilesList(instanceToken, owner, repo, ref, getContext(), binding.progressBar, binding.noDataFiles).observe(getViewLifecycleOwner(), filesListMain -> {
filesAdapter.getOriginalFiles().clear();
filesAdapter.getOriginalFiles().addAll(filesListMain);
@ -198,16 +178,16 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
if(filesListMain.size() > 0) {
AppUtil.setMultiVisibility(View.VISIBLE, mRecyclerView, filesFrame);
noDataFiles.setVisibility(View.GONE);
AppUtil.setMultiVisibility(View.VISIBLE, binding.recyclerView, binding.filesFrame);
binding.noDataFiles.setVisibility(View.GONE);
}
else {
AppUtil.setMultiVisibility(View.VISIBLE, mRecyclerView, filesFrame, noDataFiles);
AppUtil.setMultiVisibility(View.VISIBLE, binding.recyclerView, binding.filesFrame, binding.noDataFiles);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
binding.filesFrame.setVisibility(View.VISIBLE);
binding.progressBar.setVisibility(View.GONE);
});
@ -215,12 +195,12 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
private void fetchDataAsyncSub(String instanceToken, String owner, String repo, String filesDir, String ref) {
mRecyclerView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
binding.recyclerView.setVisibility(View.GONE);
binding.progressBar.setVisibility(View.VISIBLE);
FilesViewModel filesModel2 = new ViewModelProvider(this).get(FilesViewModel.class);
FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel2.getFilesList2(instanceToken, owner, repo, filesDir, ref, getContext(), mProgressBar, noDataFiles).observe(this, filesListMain2 -> {
filesModel.getFilesList2(instanceToken, owner, repo, filesDir, ref, getContext(), binding.progressBar, binding.noDataFiles).observe(this, filesListMain2 -> {
filesAdapter.getOriginalFiles().clear();
filesAdapter.getOriginalFiles().addAll(filesListMain2);
@ -228,15 +208,15 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
if(filesListMain2.size() > 0) {
AppUtil.setMultiVisibility(View.VISIBLE, mRecyclerView, filesFrame);
noDataFiles.setVisibility(View.GONE);
AppUtil.setMultiVisibility(View.VISIBLE, binding.recyclerView, binding.filesFrame);
binding.noDataFiles.setVisibility(View.GONE);
}
else {
AppUtil.setMultiVisibility(View.VISIBLE, mRecyclerView, filesFrame, noDataFiles);
AppUtil.setMultiVisibility(View.VISIBLE, binding.recyclerView, binding.filesFrame, binding.noDataFiles);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
binding.filesFrame.setVisibility(View.VISIBLE);
binding.progressBar.setVisibility(View.GONE);
});
@ -259,7 +239,7 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter
@Override
public boolean onQueryTextChange(String newText) {
if(mRecyclerView.getAdapter() != null) {
if(binding.recyclerView.getAdapter() != null) {
filesAdapter.getFilter().filter(newText);
}

View File

@ -28,7 +28,7 @@ import org.mian.gitnex.adapters.IssuesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentIssuesBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
@ -49,12 +49,12 @@ public class IssuesFragment extends Fragment {
private List<Issues> issuesList;
private IssuesAdapter adapter;
private Context context;
private int pageSize = StaticGlobalVariables.issuesPageInit;
private int pageSize = Constants.issuesPageInit;
private ProgressBar mProgressBar;
private String TAG = StaticGlobalVariables.tagIssuesList;
private String TAG = Constants.tagIssuesList;
private TextView noDataIssues;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private String requestType = StaticGlobalVariables.issuesRequestType;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private String requestType = Constants.issuesRequestType;
private ProgressBar progressLoadMore;
@Nullable
@ -78,7 +78,7 @@ public class IssuesFragment extends Fragment {
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
recyclerView = fragmentIssuesBinding.recyclerView;

View File

@ -23,7 +23,7 @@ import org.mian.gitnex.adapters.MilestonesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentMilestonesBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
@ -44,9 +44,9 @@ public class MilestonesFragment extends Fragment {
private List<Milestones> dataList;
private MilestonesAdapter adapter;
private Context ctx;
private int pageSize = StaticGlobalVariables.milestonesPageInit;
private String TAG = StaticGlobalVariables.tagMilestonesFragment;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int pageSize = Constants.milestonesPageInit;
private String TAG = Constants.tagMilestonesFragment;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -68,7 +68,7 @@ public class MilestonesFragment extends Fragment {
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
dataList = new ArrayList<>();

View File

@ -29,8 +29,8 @@ import org.mian.gitnex.adapters.NotificationsAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentNotificationsBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.InfiniteScrollListener;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import java.io.IOException;
@ -83,7 +83,7 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
context = getContext();
tinyDB = TinyDB.getInstance(context);
pageResultLimit = StaticGlobalVariables.getCurrentResultLimit(context);
pageResultLimit = Constants.getCurrentResultLimit(context);
tinyDB.putString("notificationsFilterState", currentFilterMode);
markAllAsRead = fragmentNotificationsBinding.markAllAsRead;
@ -204,7 +204,7 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
Call<List<NotificationThread>> call = RetrofitClient
.getApiInterface(context)
.getNotificationThreads(instanceToken, false, filter,
StaticGlobalVariables.defaultOldestTimestamp, "",
Constants.defaultOldestTimestamp, "",
pageCurrentIndex, pageResultLimit);
call.enqueue(new Callback<List<NotificationThread>>() {

View File

@ -30,8 +30,7 @@ import org.mian.gitnex.helpers.ColorInverter;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TinyDB;
import java.util.Locale;
import eightbitlab.com.blurview.BlurView;
import eightbitlab.com.blurview.RenderScriptBlur;
import jp.wasabeef.picasso.transformations.BlurTransformation;
/**
* Author M M Arif
@ -54,7 +53,6 @@ public class ProfileFragment extends Fragment {
TinyDB tinyDb = TinyDB.getInstance(getContext());
BlurView blurView = v.findViewById(R.id.blurView);
TextView userFullName = v.findViewById(R.id.userFullName);
ImageView userAvatarBackground = v.findViewById(R.id.userAvatarBackground);
ImageView userAvatar = v.findViewById(R.id.userAvatar);
@ -77,10 +75,10 @@ public class ProfileFragment extends Fragment {
userLanguage.setText(R.string.notSupported);
}
userAvatar.setOnClickListener(loginId -> {
AppUtil.copyToClipboard(ctx, tinyDb.getString("userLogin"), ctx.getString(R.string.copyLoginIdToClipBoard, tinyDb.getString("userLogin")));
});
userAvatar.setOnClickListener(loginId ->
AppUtil.copyToClipboard(ctx,
tinyDb.getString("userLogin"),
ctx.getString(R.string.copyLoginIdToClipBoard, tinyDb.getString("userLogin"))));
userFullName.setText(Html.fromHtml(tinyDb.getString("userFullname")));
userLogin.setText(getString(R.string.usernameWithAt, tinyDb.getString("userLogin")));
@ -94,11 +92,11 @@ public class ProfileFragment extends Fragment {
PicassoService.getInstance(ctx).get()
.load(tinyDb.getString("userAvatar"))
.transform(new BlurTransformation(ctx))
.into(userAvatarBackground, new Callback() {
@Override
public void onSuccess() {
int invertedColor = new ColorInverter().getImageViewContrastColor(userAvatarBackground);
userFullName.setTextColor(invertedColor);
@ -107,20 +105,11 @@ public class ProfileFragment extends Fragment {
userLanguage.setTextColor(invertedColor);
ImageViewCompat.setImageTintList(userLanguageIcon, ColorStateList.valueOf(invertedColor));
blurView.setupWith(aboutFrame)
.setBlurAlgorithm(new RenderScriptBlur(ctx))
.setBlurRadius(3)
.setHasFixedTransformationMatrix(true);
}
@Override
public void onError(Exception e) {}
@Override public void onError(Exception e) {}
});
ProfileFragment.SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
ViewPager mViewPager = v.findViewById(R.id.container);
@ -181,8 +170,6 @@ public class ProfileFragment extends Fragment {
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0: // followers
@ -196,7 +183,7 @@ public class ProfileFragment extends Fragment {
}
return fragment;
return null;
}

View File

@ -28,7 +28,7 @@ import org.mian.gitnex.adapters.PullRequestsAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentPullRequestsBinding;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
@ -49,11 +49,11 @@ public class PullRequestsFragment extends Fragment {
private RecyclerView recyclerView;
private List<PullRequests> prList;
private PullRequestsAdapter adapter;
private String TAG = StaticGlobalVariables.tagPullRequestsList;
private String TAG = Constants.tagPullRequestsList;
private Context context;
private int pageSize = StaticGlobalVariables.prPageInit;
private int pageSize = Constants.prPageInit;
private TextView noData;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private ProgressBar progressLoadMore;
@Nullable
@ -77,7 +77,7 @@ public class PullRequestsFragment extends Fragment {
// if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
resultLimit = Constants.resultLimitNewGiteaInstances;
}
recyclerView = fragmentPullRequestsBinding.recyclerView;

View File

@ -8,10 +8,7 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
@ -42,36 +39,18 @@ import retrofit2.Callback;
public class RepoInfoFragment extends Fragment {
private Context ctx;
private ProgressBar mProgressBar;
private LinearLayout pageContent;
private static String repoNameF = "param2";
private static String repoOwnerF = "param1";
private FragmentRepoInfoBinding binding;
private String repoName;
private String repoOwner;
private TextView repoMetaName;
private TextView repoMetaDescription;
private TextView repoMetaStars;
private TextView repoMetaPullRequests;
private LinearLayout repoMetaPullRequestsFrame;
private TextView repoMetaForks;
private TextView repoMetaSize;
private TextView repoMetaWatchers;
private TextView repoMetaCreatedAt;
private TextView repoMetaWebsite;
private Button repoAdditionalButton;
private TextView repoFileContents;
private LinearLayout repoMetaFrame;
private ImageView repoMetaDataExpandCollapse;
private ImageView repoFilenameExpandCollapse;
private LinearLayout fileContentsFrameHeader;
private LinearLayout fileContentsFrame;
private OnFragmentInteractionListener mListener;
public RepoInfoFragment() {
}
public RepoInfoFragment() {}
public static RepoInfoFragment newInstance(String param1, String param2) {
RepoInfoFragment fragment = new RepoInfoFragment();
@ -94,44 +73,18 @@ public class RepoInfoFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentRepoInfoBinding fragmentRepoInfoBinding = FragmentRepoInfoBinding.inflate(inflater, container, false);
binding = FragmentRepoInfoBinding.inflate(inflater, container, false);
TinyDB tinyDb = TinyDB.getInstance(getContext());
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
ctx = getContext();
ctx = getActivity();
pageContent = fragmentRepoInfoBinding.repoInfoLayout;
pageContent = binding.repoInfoLayout;
pageContent.setVisibility(View.GONE);
mProgressBar = fragmentRepoInfoBinding.progressBar;
repoMetaName = fragmentRepoInfoBinding.repoMetaName;
repoMetaDescription = fragmentRepoInfoBinding.repoMetaDescription;
repoMetaStars = fragmentRepoInfoBinding.repoMetaStars;
repoMetaPullRequests = fragmentRepoInfoBinding.repoMetaPullRequests;
repoMetaPullRequestsFrame = fragmentRepoInfoBinding.repoMetaPullRequestsFrame;
repoMetaForks = fragmentRepoInfoBinding.repoMetaForks;
repoMetaSize = fragmentRepoInfoBinding.repoMetaSize;
repoMetaWatchers = fragmentRepoInfoBinding.repoMetaWatchers;
repoMetaCreatedAt = fragmentRepoInfoBinding.repoMetaCreatedAt;
repoMetaWebsite = fragmentRepoInfoBinding.repoMetaWebsite;
repoAdditionalButton = fragmentRepoInfoBinding.repoAdditionalButton;
repoFileContents = fragmentRepoInfoBinding.repoFileContents;
repoMetaFrame = fragmentRepoInfoBinding.repoMetaFrame;
LinearLayout repoMetaFrameHeader = fragmentRepoInfoBinding.repoMetaFrameHeader;
repoMetaDataExpandCollapse = fragmentRepoInfoBinding.repoMetaDataExpandCollapse;
repoFilenameExpandCollapse = fragmentRepoInfoBinding.repoFilenameExpandCollapse;
fileContentsFrameHeader = fragmentRepoInfoBinding.fileContentsFrameHeader;
fileContentsFrame = fragmentRepoInfoBinding.fileContentsFrame;
LinearLayout repoMetaStarsFrame = fragmentRepoInfoBinding.repoMetaStarsFrame;
LinearLayout repoMetaForksFrame = fragmentRepoInfoBinding.repoMetaForksFrame;
LinearLayout repoMetaWatchersFrame = fragmentRepoInfoBinding.repoMetaWatchersFrame;
binding.repoMetaFrame.setVisibility(View.GONE);
repoMetaFrame.setVisibility(View.GONE);
getRepoInfo(Authorization.get(getContext()), repoOwner, repoName, locale, timeFormat);
getRepoInfo(Authorization.get(getContext()), repoOwner, repoName, tinyDb.getString("locale"), tinyDb.getString("dateFormat"));
getFileContents(Authorization.get(getContext()), repoOwner, repoName, getResources().getString(R.string.defaultFilename));
if(isExpandViewVisible()) {
@ -142,27 +95,26 @@ public class RepoInfoFragment extends Fragment {
toggleExpandViewMeta();
}
fileContentsFrameHeader.setOnClickListener(v1 -> toggleExpandView());
binding.fileContentsFrameHeader.setOnClickListener(v1 -> toggleExpandView());
binding.repoMetaFrameHeader.setOnClickListener(v12 -> toggleExpandViewMeta());
repoMetaFrameHeader.setOnClickListener(v12 -> toggleExpandViewMeta());
repoMetaStarsFrame.setOnClickListener(metaStars -> {
binding.repoMetaStarsFrame.setOnClickListener(metaStars -> {
Intent intent = new Intent(ctx, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", repoOwner + "/" + repoName);
ctx.startActivity(intent);
});
repoMetaWatchersFrame.setOnClickListener(metaWatchers -> {
binding.repoMetaWatchersFrame.setOnClickListener(metaWatchers -> {
Intent intent = new Intent(ctx, RepoWatchersActivity.class);
intent.putExtra("repoFullNameForWatchers", repoOwner + "/" + repoName);
ctx.startActivity(intent);
});
repoMetaPullRequestsFrame.setOnClickListener(metaPR -> RepoDetailActivity.mViewPager.setCurrentItem(3));
binding.repoMetaPullRequestsFrame.setOnClickListener(metaPR -> RepoDetailActivity.mViewPager.setCurrentItem(3));
return fragmentRepoInfoBinding.getRoot();
return binding.getRoot();
}
public void onButtonPressed(Uri uri) {
@ -183,42 +135,42 @@ public class RepoInfoFragment extends Fragment {
private void toggleExpandView() {
if (repoFileContents.getVisibility() == View.GONE) {
repoFilenameExpandCollapse.setImageResource(R.drawable.ic_chevron_up);
repoFileContents.setVisibility(View.VISIBLE);
if (binding.repoFileContents.getVisibility() == View.GONE) {
binding.repoFilenameExpandCollapse.setImageResource(R.drawable.ic_chevron_up);
binding.repoFileContents.setVisibility(View.VISIBLE);
//Animation slide_down = AnimationUtils.loadAnimation(getContext(), R.anim.slide_down);
//fileContentsFrame.startAnimation(slide_down);
//binding.fileContentsFrame.startAnimation(slide_down);
}
else {
repoFilenameExpandCollapse.setImageResource(R.drawable.ic_chevron_down);
repoFileContents.setVisibility(View.GONE);
binding.repoFilenameExpandCollapse.setImageResource(R.drawable.ic_chevron_down);
binding.repoFileContents.setVisibility(View.GONE);
//Animation slide_up = AnimationUtils.loadAnimation(getContext(), R.anim.slide_up);
//fileContentsFrame.startAnimation(slide_up);
//binding.fileContentsFrame.startAnimation(slide_up);
}
}
private boolean isExpandViewVisible() {
return repoFileContents.getVisibility() == View.VISIBLE;
return binding.repoFileContents.getVisibility() == View.VISIBLE;
}
private void toggleExpandViewMeta() {
if (repoMetaFrame.getVisibility() == View.GONE) {
repoMetaDataExpandCollapse.setImageResource(R.drawable.ic_chevron_up);
repoMetaFrame.setVisibility(View.VISIBLE);
if (binding.repoMetaFrame.getVisibility() == View.GONE) {
binding.repoMetaDataExpandCollapse.setImageResource(R.drawable.ic_chevron_up);
binding.repoMetaFrame.setVisibility(View.VISIBLE);
//Animation slide_down = AnimationUtils.loadAnimation(getContext(), R.anim.slide_down);
//repoMetaFrame.startAnimation(slide_down);
//binding.repoMetaFrame.startAnimation(slide_down);
}
else {
repoMetaDataExpandCollapse.setImageResource(R.drawable.ic_chevron_down);
repoMetaFrame.setVisibility(View.GONE);
binding.repoMetaDataExpandCollapse.setImageResource(R.drawable.ic_chevron_down);
binding.repoMetaFrame.setVisibility(View.GONE);
//Animation slide_up = AnimationUtils.loadAnimation(getContext(), R.anim.slide_up);
//repoMetaFrame.startAnimation(slide_up);
//binding.repoMetaFrame.startAnimation(slide_up);
}
}
private boolean isExpandViewMetaVisible() {
return repoMetaFrame.getVisibility() == View.VISIBLE;
return binding.repoMetaFrame.getVisibility() == View.VISIBLE;
}
private void getRepoInfo(String token, final String owner, String repo, final String locale, final String timeFormat) {
@ -243,39 +195,39 @@ public class RepoInfoFragment extends Fragment {
if (response.code() == 200) {
assert repoInfo != null;
repoMetaName.setText(repoInfo.getName());
binding.repoMetaName.setText(repoInfo.getName());
if(!repoInfo.getDescription().isEmpty()) {
repoMetaDescription.setText(repoInfo.getDescription());
binding.repoMetaDescription.setText(repoInfo.getDescription());
}
else {
repoMetaDescription.setText(getString(R.string.noDataDescription));
binding.repoMetaDescription.setText(getString(R.string.noDataDescription));
}
repoMetaStars.setText(repoInfo.getStars_count());
binding.repoMetaStars.setText(repoInfo.getStars_count());
if(repoInfo.getOpen_pull_count() != null) {
repoMetaPullRequests.setText(repoInfo.getOpen_pull_count());
binding.repoMetaPullRequests.setText(repoInfo.getOpen_pull_count());
}
else {
repoMetaPullRequestsFrame.setVisibility(View.GONE);
binding.repoMetaPullRequestsFrame.setVisibility(View.GONE);
}
repoMetaForks.setText(repoInfo.getForks_count());
repoMetaWatchers.setText(repoInfo.getWatchers_count());
repoMetaSize.setText(FileUtils.byteCountToDisplaySize((int) (repoInfo.getSize() * 1024)));
binding.repoMetaForks.setText(repoInfo.getForks_count());
binding.repoMetaWatchers.setText(repoInfo.getWatchers_count());
binding.repoMetaSize.setText(FileUtils.byteCountToDisplaySize((int) repoInfo.getSize() * 1024));
repoMetaCreatedAt.setText(TimeHelper.formatTime(repoInfo.getCreated_at(), new Locale(locale), timeFormat, ctx));
binding.repoMetaCreatedAt.setText(TimeHelper.formatTime(repoInfo.getCreated_at(), new Locale(locale), timeFormat, ctx));
if(timeFormat.equals("pretty")) {
repoMetaCreatedAt.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(repoInfo.getCreated_at()), ctx));
binding.repoMetaCreatedAt.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(repoInfo.getCreated_at()), ctx));
}
String repoMetaUpdatedAt = TimeHelper.formatTime(repoInfo.getUpdated_at(), new Locale(locale), timeFormat, ctx);
String website = (repoInfo.getWebsite().isEmpty()) ? getResources().getString(R.string.noDataWebsite) : repoInfo.getWebsite();
repoMetaWebsite.setText(website);
binding.repoMetaWebsite.setText(website);
repoAdditionalButton.setOnClickListener(v -> {
binding.repoAdditionalButton.setOnClickListener(v -> {
View view = LayoutInflater.from(ctx).inflate(R.layout.layout_repo_more_info, null);
@ -334,7 +286,7 @@ public class RepoInfoFragment extends Fragment {
tinyDb.putString("repoHtmlUrl", repoInfo.getHtml_url());
mProgressBar.setVisibility(View.GONE);
binding.progressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);
}
@ -369,39 +321,41 @@ public class RepoInfoFragment extends Fragment {
if (isAdded()) {
if (response.code() == 200) {
switch(response.code()) {
new Markdown(ctx, response.body(), repoFileContents);
case 200:
new Markdown(ctx, response.body(), binding.repoFileContents);
break;
} else if (response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
case 401:
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
break;
} else if (response.code() == 403) {
case 403:
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
break;
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
case 404:
binding.fileContentsFrameHeader.setVisibility(View.GONE);
binding.fileContentsFrame.setVisibility(View.GONE);
break;
} else if (response.code() == 404) {
fileContentsFrameHeader.setVisibility(View.GONE);
fileContentsFrame.setVisibility(View.GONE);
} else {
Toasty.error(getContext(), getString(R.string.genericError));
default:
Toasty.error(getContext(), getString(R.string.genericError));
break;
}
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}

View File

@ -15,7 +15,6 @@ import org.mian.gitnex.R;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.activities.SettingsAppearanceActivity;
import org.mian.gitnex.activities.SettingsDraftsActivity;
import org.mian.gitnex.activities.SettingsFileViewerActivity;
import org.mian.gitnex.activities.SettingsGeneralActivity;
import org.mian.gitnex.activities.SettingsNotificationsActivity;
import org.mian.gitnex.activities.SettingsReportsActivity;
@ -54,8 +53,6 @@ public class SettingsFragment extends Fragment {
fragmentSettingsBinding.appearanceFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsAppearanceActivity.class)));
fragmentSettingsBinding.fileViewerFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsFileViewerActivity.class)));
fragmentSettingsBinding.draftsFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsDraftsActivity.class)));
fragmentSettingsBinding.securityFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsSecurityActivity.class)));
@ -71,6 +68,7 @@ public class SettingsFragment extends Fragment {
fragmentSettingsBinding.aboutAppFrame.setOnClickListener(aboutApp -> requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).commit());
return fragmentSettingsBinding.getRoot();
}
public void rateThisApp() {

View File

@ -13,17 +13,20 @@ import android.util.TypedValue;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.core.content.pm.PackageInfoCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Author M M Arif
@ -31,31 +34,38 @@ import java.util.Objects;
public class AppUtil {
public enum FileType { IMAGE, DOCUMENT, TEXT, UNKNOWN }
public enum FileType { IMAGE, AUDIO, VIDEO, DOCUMENT, TEXT, EXECUTABLE, UNKNOWN }
private static final HashMap<List<String>, FileType> extensions = new HashMap<>();
private static final HashMap<String[], FileType> extensions = new HashMap<>();
// AppUtil should not be instantiated.
private AppUtil() {}
static {
extensions.put(Arrays.asList("jpg", "jpeg", "gif", "png", "ico"), FileType.IMAGE);
extensions.put(Arrays.asList("doc", "docx", "ppt", "pptx", "xls", "xlsx", "xlsm", "odt", "ott", "odf", "ods", "ots", "exe", "jar", "odg", "otg", "odp", "otp", "bin", "dmg", "psd", "xcf", "pdf"), FileType.DOCUMENT);
extensions.put(Arrays.asList("txt", "md", "json", "java", "go", "php", "c", "cc", "cpp", "h", "cxx", "cyc", "m", "cs", "bash", "sh", "bsh", "cv", "python", "perl", "pm", "rb", "ruby", "javascript", "coffee", "rc", "rs", "rust", "basic", "clj", "css", "dart", "lisp", "erl", "hs", "lsp", "rkt", "ss", "llvm", "ll", "lua", "matlab", "pascal", "r", "scala", "sql", "latex", "tex", "vb", "vbs", "vhd", "tcl", "wiki.meta", "yaml", "yml", "markdown", "xml", "proto", "regex", "py", "pl", "js", "html", "htm", "volt", "ini", "htaccess", "conf", "gitignore", "gradle", "txt", "properties", "bat", "twig", "cvs", "cmake", "in", "info", "spec", "m4", "am", "dist", "pam", "hx", "ts"), FileType.TEXT);
extensions.put(new String[]{"jpg", "jpeg", "gif", "png", "ico", "tif", "tiff", "bmp"}, FileType.IMAGE);
extensions.put(new String[]{"mp3", "wav", "opus", "flac", "wma", "aac", "m4a", "oga", "mpc", "ogg"}, FileType.AUDIO);
extensions.put(new String[]{"mp4", "mkv", "avi", "mov", "wmv", "qt", "mts", "m2ts", "webm", "flv", "ogv", "amv", "mpg", "mpeg", "mpv", "m4v", "3gp", "wmv"}, FileType.VIDEO);
extensions.put(new String[]{"doc", "docx", "ppt", "pptx", "xls", "xlsx", "xlsm", "odt", "ott", "odf", "ods", "ots", "odg", "otg", "odp", "otp", "bin", "psd", "xcf", "pdf"}, FileType.DOCUMENT);
extensions.put(new String[]{"exe", "msi", "jar", "dmg", "deb", "apk"}, FileType.EXECUTABLE);
extensions.put(new String[]{"txt", "md", "json", "java", "go", "php", "c", "cc", "cpp", "h", "cxx", "cyc", "m", "cs", "bash", "sh", "bsh", "cv", "python", "perl", "pm", "rb", "ruby", "javascript", "coffee", "rc", "rs", "rust", "basic", "clj", "css", "dart", "lisp", "erl", "hs", "lsp", "rkt", "ss", "llvm", "ll", "lua", "matlab", "pascal", "r", "scala", "sql", "latex", "tex", "vb", "vbs", "vhd", "tcl", "wiki.meta", "yaml", "yml", "markdown", "xml", "proto", "regex", "py", "pl", "js", "html", "htm", "volt", "ini", "htaccess", "conf", "gitignore", "gradle", "txt", "properties", "bat", "twig", "cvs", "cmake", "in", "info", "spec", "m4", "am", "dist", "pam", "hx", "ts", "kt", "kts"}, FileType.TEXT);
}
public static FileType getFileType(String extension) {
for(List<String> e : extensions.keySet()) {
if(extension != null && !extension.isEmpty()) {
for(String[] testExtensions : extensions.keySet()) {
for(String testExtension : testExtensions) {
if(e.contains(extension)) {
return extensions.get(e);
if(testExtension.equalsIgnoreCase(extension))
return extensions.get(testExtensions);
}
}
}
return FileType.UNKNOWN;
}
public static boolean hasNetworkConnection(Context context) {
@ -63,6 +73,45 @@ public class AppUtil {
return NetworkStatusObserver.getInstance(context).hasNetworkConnection();
}
public static void copyProgress(InputStream inputStream, OutputStream outputStream, long totalSize, ProgressListener progressListener) throws IOException {
byte[] buffer = new byte[4096];
int read;
long totalSteps = (long) Math.ceil((double) totalSize / buffer.length);
long stepsPerPercent = (long) Math.floor((double) totalSteps / 100);
short percent = 0;
long stepCount = 0;
progressListener.onActionStarted();
while((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
stepCount++;
if(stepCount == stepsPerPercent) {
percent++;
if(percent <= 100) progressListener.onProgressChanged(percent);
stepCount = 0;
}
}
if(percent < 100) {
progressListener.onProgressChanged((short) 100);
}
progressListener.onActionFinished();
}
public interface ProgressListener {
default void onActionStarted() {}
default void onActionFinished() {}
void onProgressChanged(short progress);
}
public static int getAppBuildNo(Context context) {
try {
@ -248,6 +297,20 @@ public class AppUtil {
return (int) (context.getResources().getDisplayMetrics().scaledDensity * sp);
}
public static int getLineCount(String s) {
int lines = 0;
Pattern pattern = Pattern.compile("(\r\n|\r|\n)");
Matcher matcher = pattern.matcher(s);
while(matcher.find())
lines++;
return lines;
}
public static void copyToClipboard(Context ctx, CharSequence data, String message) {
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(Context.CLIPBOARD_SERVICE);

View File

@ -23,4 +23,12 @@ public class Authorization {
return "token " + tinyDb.getString(loginUid + "-token");
}
public static String getWeb(Context context) {
TinyDB tinyDb = TinyDB.getInstance(context);
return Credentials.basic("", tinyDb.getString(tinyDb.getString("loginUid") + "-token"));
}
}

View File

@ -5,6 +5,7 @@ import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
/**
* Author M M Arif
@ -17,45 +18,36 @@ public class ColorInverter {
double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
int d;
if (a < 0.5) {
d = 30; // almost black
} else {
d = 255; // white
}
int d = (a < 0.30) ?
30 : // almost black
255; // white
return Color.rgb(d, d, d);
}
@ColorInt
public int getImageViewContrastColor(ImageView imageView) {
public int getBitmapContrastColor(@NonNull Bitmap bitmap) {
if(imageView != null) {
int colorSum = 0;
int divisionValue = 0;
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
for(int height=0; height<bitmap.getHeight(); height += 10) {
for(int width=0; width<bitmap.getWidth(); width += 10) {
int colorSum = 0;
int divisionValue = 0;
for(int height=0; height<bitmap.getHeight(); height += 10) {
for(int width=0; width<bitmap.getWidth(); width += 10) {
colorSum += bitmap.getPixel(width, height);
divisionValue++;
}
colorSum += bitmap.getPixel(width, height);
divisionValue++;
}
// Calculate average color
return getContrastColor(colorSum / divisionValue);
}
else {
return Color.rgb(255, 255, 255);
}
// Calculate average color
return getContrastColor(colorSum / divisionValue);
}
@ColorInt
public int getImageViewContrastColor(@NonNull ImageView imageView) {
return getBitmapContrastColor(((BitmapDrawable) imageView.getDrawable()).getBitmap());
}
}

View File

@ -0,0 +1,61 @@
package org.mian.gitnex.helpers;
import android.content.Context;
/**
* Author M M Arif
*/
public class Constants {
// generic values
public static final int resultLimitNewGiteaInstances = 25; // Gitea 1.12 and above
public static final int resultLimitOldGiteaInstances = 10; // Gitea 1.11 and below
public static final String defaultOldestTimestamp = "1970-01-01T00:00:00+00:00";
public static int getCurrentResultLimit(Context context) {
Version version = new Version(TinyDB.getInstance(context).getString("giteaVersion"));
return version.higherOrEqual("1.12") ? resultLimitNewGiteaInstances : resultLimitOldGiteaInstances;
}
// tags
public static final String tagMilestonesFragment = "MilestonesFragment";
public static final String tagPullRequestsList = "PullRequestsListFragment";
public static final String tagIssuesList = "IssuesListFragment";
public static final String tagMilestonesAdapter = "MilestonesAdapter";
public static final String draftsApi = "DraftsApi";
public static final String repositoriesApi = "RepositoriesApi";
public static final String replyToIssueActivity = "ReplyToIssueActivity";
public static final String tagDraftsBottomSheet = "BottomSheetDraftsFragment";
public static final String userAccountsApi = "UserAccountsApi";
// issues variables
public static final int issuesPageInit = 1;
public static final String issuesRequestType = "issues";
// pull request
public static final int prPageInit = 1;
// milestone
public static final int milestonesPageInit = 1;
// drafts
public static final String draftTypeComment = "comment";
public static final String draftTypeIssue = "Issue";
public static final String draftTypePull = "Pull";
// polling - notifications
public static final int minimumPollingDelay = 1;
public static final int defaultPollingDelay = 15;
public static final int maximumPollingDelay = 720;
public static final int maximumFileViewerSize = 3 * 1024 * 1024;
public static final String mainNotificationChannelId = "main_channel";
public static final String downloadNotificationChannelId = "dl_channel";
public static final String[] fallbackReactions = new String[]{"+1", "-1", "laugh", "hooray", "confused", "heart", "rocket", "eyes"};
}

View File

@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.core.MainGrammarLocator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import io.noties.markwon.AbstractMarkwonPlugin;
@ -25,16 +26,11 @@ import io.noties.markwon.syntax.Prism4jThemeDarkula;
import io.noties.markwon.syntax.Prism4jThemeDefault;
import io.noties.markwon.syntax.SyntaxHighlightPlugin;
import io.noties.prism4j.Prism4j;
import io.noties.prism4j.annotations.PrismBundle;
/**
* @author opyale
*/
@PrismBundle(
includeAll = true,
grammarLocatorClassName = ".CustomGrammarLocator"
)
public class Markdown {
private static final ExecutorService executorService = Executors.newCachedThreadPool();
@ -65,12 +61,12 @@ public class Markdown {
Markwon.Builder builder = Markwon.builder(context)
.usePlugin(CorePlugin.create())
.usePlugin(HtmlPlugin.create())
.usePlugin(LinkifyPlugin.create())
.usePlugin(LinkifyPlugin.create(true))
.usePlugin(TablePlugin.create(context))
.usePlugin(TaskListPlugin.create(context))
.usePlugin(StrikethroughPlugin.create())
.usePlugin(PicassoImagesPlugin.create(PicassoService.getInstance(context).get()))
.usePlugin(SyntaxHighlightPlugin.create(new Prism4j(new CustomGrammarLocator()), prism4jTheme))
.usePlugin(SyntaxHighlightPlugin.create(new Prism4j(MainGrammarLocator.getInstance()), prism4jTheme, MainGrammarLocator.DEFAULT_FALLBACK_LANGUAGE))
.usePlugin(new AbstractMarkwonPlugin() {
@Override

View File

@ -113,7 +113,7 @@ public class ParseDiff {
// parse "-1,2 +2,3" and "-1 -3" and so on
int oldStart = 0, newStart = 0;
String diffPos[] = statsLine.split(" \\+");
String[] diffPos = statsLine.split(" \\+");
if(diffPos.length == 2) {
oldStart = Integer.parseInt(diffPos[0].split(",")[0]);
newStart = Integer.parseInt(diffPos[1].split(",")[0]);

View File

@ -1,53 +0,0 @@
package org.mian.gitnex.helpers;
import android.content.Context;
/**
* Author M M Arif
*/
public abstract class StaticGlobalVariables {
// generic values
public static int resultLimitNewGiteaInstances = 25; // Gitea 1.12 and above
public static int resultLimitOldGiteaInstances = 10; // Gitea 1.11 and below
public static String defaultOldestTimestamp = "1970-01-01T00:00:00+00:00";
public static int getCurrentResultLimit(Context context) {
Version version = new Version(TinyDB.getInstance(context).getString("giteaVersion"));
return version.higherOrEqual("1.12") ? resultLimitNewGiteaInstances : resultLimitOldGiteaInstances;
}
// tags
public static String tagMilestonesFragment = "MilestonesFragment";
public static String tagPullRequestsList = "PullRequestsListFragment";
public static String tagIssuesList = "IssuesListFragment";
public static String tagMilestonesAdapter = "MilestonesAdapter";
public static String draftsApi = "DraftsApi";
public static String repositoriesApi = "RepositoriesApi";
public static String replyToIssueActivity = "ReplyToIssueActivity";
public static String tagDraftsBottomSheet = "BottomSheetDraftsFragment";
public static String userAccountsApi = "UserAccountsApi";
// issues variables
public static int issuesPageInit = 1;
public static String issuesRequestType = "issues";
// pull request
public static int prPageInit = 1;
// milestone
public static int milestonesPageInit = 1;
// drafts
public static String draftTypeComment = "comment";
public static String draftTypeIssue = "Issue";
public static String draftTypePull = "Pull";
// polling - notifications
public static int minimumPollingDelay = 1;
public static int defaultPollingDelay = 15;
public static int maximumPollingDelay = 720;
}

View File

@ -0,0 +1,209 @@
package org.mian.gitnex.helpers;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.mian.gitnex.core.MainGrammarLocator;
import io.noties.markwon.syntax.Prism4jSyntaxHighlight;
import io.noties.markwon.syntax.Prism4jTheme;
import io.noties.markwon.syntax.Prism4jThemeDarkula;
import io.noties.markwon.syntax.Prism4jThemeDefault;
import io.noties.prism4j.Prism4j;
/**
* @author opyale
*/
public class SyntaxHighlightedArea extends LinearLayout {
private Prism4jTheme prism4jTheme;
private TextView sourceView;
private LinesView linesView;
public SyntaxHighlightedArea(@NonNull Context context) {
super(context);
setup();
}
public SyntaxHighlightedArea(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setup();
}
public SyntaxHighlightedArea(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup();
}
public void setup() {
prism4jTheme = TinyDB.getInstance(getContext()).getString("currentTheme").equals("dark") ?
Prism4jThemeDarkula.create() :
Prism4jThemeDefault.create();
sourceView = new TextView(getContext());
sourceView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
sourceView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
sourceView.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/sourcecodeproregular.ttf"));
sourceView.setTextColor(prism4jTheme.textColor());
int padding = AppUtil.getPixelsFromDensity(getContext(), 5);
sourceView.setPadding(padding, 0, padding, 0);
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(getContext());
horizontalScrollView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
horizontalScrollView.addView(sourceView);
linesView = new LinesView(getContext());
linesView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
linesView.setPadding(
AppUtil.getPixelsFromDensity(getContext(), 3), 0,
AppUtil.getPixelsFromDensity(getContext(), 6), 0);
linesView.getPaint().setTypeface(sourceView.getTypeface());
linesView.getPaint().setTextSize(sourceView.getTextSize());
linesView.setBackgroundColor(prism4jTheme.background());
linesView.setTextColor(prism4jTheme.textColor());
linesView.setLineColor(prism4jTheme.textColor());
setOrientation(HORIZONTAL);
setBackgroundColor(prism4jTheme.background());
addView(linesView);
addView(horizontalScrollView);
}
public void setContent(@NonNull String source, @NonNull String extension) {
if(source.length() > 0) {
linesView.setLineCount(AppUtil.getLineCount(source));
try {
MainGrammarLocator mainGrammarLocator = MainGrammarLocator.getInstance();
Prism4j prism4j = new Prism4j(mainGrammarLocator);
CharSequence highlightedSource = Prism4jSyntaxHighlight.create(prism4j, prism4jTheme, MainGrammarLocator.DEFAULT_FALLBACK_LANGUAGE)
.highlight(mainGrammarLocator.fromExtension(extension), source);
if(highlightedSource.charAt(highlightedSource.length() - 1) == '\n') {
// Removes a line break which is probably added by Prism4j but not actually present in the source.
// This line should be altered in case this gets fixed.
sourceView.setText(highlightedSource.subSequence(0, highlightedSource.length() - 1));
}
else {
sourceView.setText(highlightedSource);
}
} catch(Throwable ignored) {
// Fall back to plaintext if something fails
sourceView.setText(source);
}
}
}
public String getContent() {
return sourceView.getText().toString();
}
private static class LinesView extends View {
private final Paint paint = new Paint();
private final Rect textBounds = new Rect();
@ColorInt private int backgroundColor;
@ColorInt private int textColor;
@ColorInt private int lineColor;
private int lineCount;
public LinesView(Context context) {
super(context);
}
public void setLineCount(int lineCount) {
this.lineCount = lineCount;
}
@Override
public void setBackgroundColor(@ColorInt int backgroundColor) {
this.backgroundColor = backgroundColor;
}
public void setTextColor(@ColorInt int textColor) {
this.textColor = textColor;
}
public void setLineColor(@ColorInt int lineColor) {
this.lineColor = lineColor;
}
public Paint getPaint() {
return paint;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
String highestLineNumber = String.valueOf(lineCount);
paint.getTextBounds(highestLineNumber, 0, highestLineNumber.length(), textBounds);
setMeasuredDimension(getPaddingLeft() + textBounds.width() + getPaddingRight(), MeasureSpec.getSize(heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
paint.setColor(backgroundColor);
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
float marginTopBottom = (float) (getHeight() - (textBounds.height() / 2)) / lineCount;
paint.setColor(textColor);
canvas.save();
canvas.translate(getPaddingLeft(), marginTopBottom);
for(int currentLine = 1; currentLine <= lineCount; currentLine++) {
canvas.drawText(String.valueOf(currentLine), 0, 0, paint);
canvas.translate(0, marginTopBottom);
}
paint.setColor(lineColor);
int dividerX = getWidth() - 1;
int dividerY = getHeight();
canvas.restore();
canvas.drawLine(dividerX,0, dividerX, dividerY, paint);
}
}
}

View File

@ -1,112 +0,0 @@
package org.mian.gitnex.helpers.highlightjs;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import org.mian.gitnex.helpers.highlightjs.models.Language;
import org.mian.gitnex.helpers.highlightjs.models.Theme;
import org.mian.gitnex.helpers.highlightjs.utils.SourceUtils;
/**
* This Class was created by Patrick J
* on 09.06.16. (modified by opyale)
*/
public class HighlightJsView extends WebView {
private Language language = Language.AUTO_DETECT;
private Theme theme = Theme.DEFAULT;
private boolean zoomSupport = false;
private boolean showLineNumbers = true;
private TextWrap textWrap = TextWrap.NO_WRAP;
public HighlightJsView(Context context) {
super(context);
setup();
}
public HighlightJsView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
public HighlightJsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup();
}
@SuppressLint("SetJavaScriptEnabled")
private void setup() {
WebSettings settings = getSettings();
settings.setJavaScriptEnabled(true);
settings.setBuiltInZoomControls(true);
settings.setSupportZoom(zoomSupport);
settings.setDisplayZoomControls(false);
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
}
private void changeZoomSettings(boolean enable) {
this.zoomSupport = enable;
getSettings().setSupportZoom(enable);
}
public void setSource(String source) {
source = (source == null) ? " " : source;
String html_content = SourceUtils.generateContent(source, theme.getName(), language.getName(), zoomSupport, showLineNumbers, textWrap);
loadDataWithBaseURL("file:///android_asset/", html_content, "text/html", "utf-8", null);
}
public void refresh() {
super.reload();
}
public void setHighlightLanguage(Language language) {
this.language = language;
}
public void setTheme(Theme theme) {
this.theme = theme;
}
public void setTextWrap(TextWrap textWrap) {
this.textWrap = textWrap;
}
public Language getHighlightLanguage() {
return language;
}
public Theme getTheme() {
return theme;
}
public void setZoomSupportEnabled(boolean supportZoom) {
changeZoomSettings(supportZoom);
}
public void setShowLineNumbers(boolean showLineNumbers) {
this.showLineNumbers = showLineNumbers;
}
public enum TextWrap {
NO_WRAP, WORD_WRAP, BREAK_ALL
}
}

View File

@ -1,181 +0,0 @@
package org.mian.gitnex.helpers.highlightjs.models;
/**
* This Class was created by Patrick J
* on 09.06.16.
*/
public enum Language {
AUTO_DETECT(null),
DISABLE_HIGHLIGHT("nohighlight"),
_1C("1c"),
ABNF("abnf"),
ACCESS_LOGS("accesslog"),
ADA("ada"),
ARM_ASSEMBLER("arm"),
AVR_ASSEMBLER("avrasm"),
ACTION_SCRIPT("actionscript"),
APACHE("apache"),
APPLE_SCRIPT("applescript"),
ASCII_DOC("asciidoc"),
ASPECT_J("aspectj"),
AUTO_HOTKEY("autohotkey"),
AUTO_IT("autoit"),
AXAPTA("axapta"),
AWK("awk"),
BASH("bash"),
SHELL("sh"),
ZSH("zsh"),
BASIC("basic"),
BNF("bnf"),
BRAINFUCK("brainfuck"),
C("c"),
C_SHARP("csharp"),
C_PLUS_PLUS("cpp"),
CACHE_OBJECT_SCRIPT("cos"),
C_MAKE("cmake"),
COQ("coq"),
CSP("csp"),
CSS("css"),
CAPTAIN_PROTO("capnproto"),
CLEAN("clean"),
CLOJURE("clojure"),
COFFEE_SCRIPT("coffeescript"),
CRMSH("crmsh"),
CRYSTAL("crystal"),
D("d"),
DNS_ZONE_FILE("dns"),
DOS("dos"),
BATCH("bat"),
DART("dart"),
DELPHI("delphi"),
DIFF("diff"),
DJANGO("django"),
DOCKER_FILE("dockerfile"),
DSCONFIG("dsconfig"),
DTS("dts"),
DUST("dust"),
EBNF("ebnf"),
ELIXIR("elixir"),
ELM("elm"),
ERLANG("erlang"),
EXCEL("excel"),
F_SHARP("fsharp"),
FIX("fix"),
FLIX("flix"),
FORTRAN("fortran"),
G_CODE("gcode"),
GAMS("gams"),
GAUSS("gauss"),
GHERKIN("gherkin"),
GO("go"),
GOLO("golo"),
GRADLE("gradle"),
GROOVY("groovy"),
HTML("html"),
XML("xml"),
HTTP("http"),
HAML("haml"),
HANDLEBARS("hbs"),
HASKELL("hs"),
HAXE("hx"),
HY("hy"),
INI("ini"),
INFORM7("i7"),
IRPF90("irpf90"),
JSON("json"),
JAVA("java"),
JAVA_SCRIPT("javascript"),
LASSO("lasso"),
LEAF("leaf"),
LESS("less"),
LDIF("ldif"),
LISP("lisp"),
LIVE_CODE_SERVER("livecodeserver"),
LIVE_SCRIPT("livescript"),
LLVM("llvm"),
LUA("lua"),
MAKEFILE("makefile"),
MARKDOWN("md"),
MATHEMATICA("mma"),
MATLAB("matlab"),
MAXIMA("maxima"),
MAYA_EMBEDDED_LANGUAGE("mel"),
MERCURY("mercury"),
MIZAR("mizar"),
MOJOLICIOUS("mojolicious"),
MONKEY("monkey"),
MOONSCRIPT("moonscript"),
N1QL("n1ql"),
NSIS("nsis"),
NGINX("nginx"),
NIMROD("nimrod"),
NIX("nix"),
O_CAML("ocaml"),
OBJECTIVE_C("objectivec"),
OPENGL_SHADING_LANGUAGE("glsl"),
OPEN_SCAD("scad"),
ORACLE_RULES_LANGUAGE("ruleslanguage"),
OXYGENE("oxygene"),
PF("pf"),
PHP("php"),
PARSER3("parser3"),
PERL("perl"),
PONY("pony"),
POWER_SHELL("ps"),
PROCESSING("processing"),
PROLOG("prolog"),
PROTOCOL_BUFFERS("protobuf"),
PUPPET("pp"),
PYTHON("python"),
PYTHON_PROFILER_RESULTS("profile"),
Q("k"),
QML("qml"),
R("r"),
RENDER_MAN_RIB("rib"),
RENDER_MAN_RSL("rsl"),
ROBOCONF("roboconf"),
RUBY("ruby"),
RUST("rust"),
SCSS("scss"),
SQL("sql"),
STEP_PART_21("p21"),
SCALA("scala"),
SCHEME("scheme"),
SCILAB("sci"),
SMALI("smali"),
SMALLTALK("smalltalk"),
STAN("stan"),
STATA("stata"),
STYLUS("stylus"),
SUB_UNIT("subunit"),
SWIFT("swift"),
TEST_ANYTHING_PROTOCOL("tap"),
TCL("tcl"),
TEX("tex"),
THRIFT("thrift"),
TP("tp"),
TWIG("twig"),
TYPE_SCRIPT("typescript"),
VB_NET("vbnet"),
VB_SCRIPT("vbscript"),
VHDL("vhdl"),
VALA("vala"),
VERILOG("v"),
VIM("vim"),
X86_ASSEMBLY("x86asm"),
XL("xl"),
X_QUERY("xq"),
ZEPHIR("zep");
private final String className;
Language(String name) {
this.className = name;
}
public String getName() {
return className;
}
}

View File

@ -1,96 +0,0 @@
package org.mian.gitnex.helpers.highlightjs.models;
/**
* This Class was created by Patrick J
* on 09.06.16.
*/
public enum Theme {
AGATE("agate"),
ANDROID_STUDIO("androidstudio"),
ARDUINO_LIGHT("arduino-light"),
ARTA("arta"),
ASCETIC("ascetic"),
ATELIER_CAVE_DARK("atelier-cave-dark"),
ATELIER_CAVE_LIGHT("atelier-cave-light"),
ATELIER_DUNE_DARK("atelier-dune-dark"),
ATELIER_DUNE_LIGHT("atelier-dune-light"),
ATELIER_ESTUARY_DARK("atelier-estuary-dark"),
ATELIER_ESTUARY_LIGHT("atelier-estuary-light"),
ATELIER_FOREST_DARK("atelier-forest-dark"),
ATELIER_FOREST_LIGHT("atelier-forest-light"),
ATELIER_HEATH_DARK("atelier-heath-dark"),
ATELIER_HEATH_LIGHT("atelier-heath-light"),
ATELIER_LAKESIDE_DARK("atelier-lakeside-dark"),
ATELIER_LAKESIDE_LIGHT("atelier-lakeside-light"),
ATELIER_PLATEAU_DARK("atelier-plateau-dark"),
ATELIER_PLATEAU_LIGHT("atelier-plateau-light"),
ATELIER_SAVANNA_DARK("atelier-savanna-dark"),
ATELIER_SAVANNA_LIGHT("atelier-savanna-light"),
ATELIER_SEASIDE_DARK("atelier-seaside-dark"),
ATELIER_SEASIDE_LIGHT("atelier-seaside-light"),
ATELIER_SULPHURPOOL_DARK("atelier-sulphurpool-dark"),
ATELIER_SULPHURPOOL_LIGHT("atelier-sulphurpool-light"),
ATOM_ONE_DARK("atom-one-dark"),
ATOM_ONE_LIGHT("atom-one-light"),
BROWN_PAPER("brown-paper"),
CODEPEN_EMBED("codepen-embed"),
COLOR_BREWER("color-brewer"),
DARK("dark"),
DARKULA("darkula"),
DEFAULT("default"),
DOCCO("docco"),
DRAKULA("drakula"),
FAR("far"),
FOUNDATION("foundaiton"),
GITHUB("github"),
GITHUB_GIST("github-gist"),
GOOGLECODE("googlecode"),
GRAYSCALE("grayscale"),
GRUVBOX_DARK("gruvbox-dark"),
GRUVBOX_LIGHT("gruvbox-light"),
HOPSCOTCH("hopscotch"),
HYBRID("hybrid"),
IDEA("idea"),
IR_BLACK("ir-black"),
KIMBIE_DARK("kimbie.dark"),
KIMBIE_LIGHT("kimbie.light"),
MAGULA("magula"),
MONO_BLUE("mono-blue"),
MONOKAI("monokai"),
MONOKAI_SUBLIME("monokai-sublime"),
OBSIDIAN("obsidian"),
OCEAN("ocean"),
PARAISO_DARK("paraiso-dark"),
PARAISO_LIGHT("paraiso-light"),
POJOAQUE("pojoaque"),
PURE_BASIC("purebasic"),
QT_CREATOR_DARK("qtcreator_dark"),
QT_CREATOR_LIGHT("qtcreator_light"),
RAILSCASTS("railscasts"),
RAINBOX("rainbow"),
SCHOOL_BOOK("school-book"),
SOLARIZED_DARK("solarized-dark"),
SOLARIZED_LIGHT("solarized-light"),
SUNBURST("sunburst"),
TOMORROW("tomorrow"),
TOMORROW_NIGHT_BLUE("tomorrow-night-blue"),
TOMORROW_NIGHT_BRIGHT("tomorrow-night-bright"),
TOMORROW_NIGHT("tomorrow-night"),
TOMORROW_NIGHT_EIGHTIES("tomorrow-night-eighties"),
VS("vs"),
X_CODE("xcode"),
XT256("xt256"),
ZENBURN("zenburn");
private final String themeName;
Theme(String themeName) {
this.themeName = themeName;
}
public String getName() {
return themeName;
}
}

View File

@ -1,98 +0,0 @@
package org.mian.gitnex.helpers.highlightjs.utils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.mian.gitnex.helpers.highlightjs.HighlightJsView;
/**
* This Class was created by Patrick J
* on 09.06.16. (modified by opyale)
*/
public class SourceUtils {
public static String generateContent(String source, @NonNull String theme, @Nullable String language, boolean supportZoom, boolean showLineNumbers,
HighlightJsView.TextWrap textWrap) {
return getStylePageHeader(supportZoom, textWrap) +
getSourceForTheme(theme) +
(showLineNumbers ? getLineNumberStyling() : "") +
getScriptPageHeader(showLineNumbers) +
getSourceForLanguage(source, language) +
getTemplateFooter();
}
private static String getStylePageHeader(boolean enableZoom, HighlightJsView.TextWrap textWrap) {
String preTag;
switch (textWrap) {
case WORD_WRAP:
preTag = "pre { white-space: pre-wrap; word-wrap: break-word; }";
break;
case BREAK_ALL:
preTag = "pre { white-space: pre-wrap; word-break: break-all; }";
break;
default:
preTag = "pre { }";
break;
}
return "<!DOCTYPE html>" +
"<html>" +
"<head>" +
"<meta charset=\"utf-8\">" +
(enableZoom ? "" : "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">") +
"<style>" +
"html, body { width:100%; height: 100%; margin: 0px; padding: 0px; }" +
preTag +
"</style>";
}
private static String getScriptPageHeader(boolean showLineNumbers) {
return "<script src=\"./highlightjs/highlight.pack.js\"></script>" +
(showLineNumbers ? "<script src=\"./highlightjs/highlightjs-line-numbers.min.js\"></script>" : "") +
"<script>hljs.initHighlightingOnLoad();</script>" +
(showLineNumbers ? "<script>hljs.initLineNumbersOnLoad();</script>" : "") +
"</head><body style=\"margin: 0; padding: 0\" class=\"hljs\">";
}
private static String getLineNumberStyling() {
return "<style>" +
".hljs-line-numbers { text-align: right; border-right: 1px solid #ccc; color: #999; user-select: none; }" +
"</style>";
}
private static String getTemplateFooter() {
return "</body></html>";
}
private static String escapeCode(String code) {
return code.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");
}
private static String getSourceForTheme(String theme) {
return String.format("<link rel=\"stylesheet\" href=\"./highlightjs/themes/%s.css\">", theme);
}
private static String getSourceForLanguage(String source, String language) {
if (language != null) {
return String.format("<pre><code class=\"%s\">%s</code></pre>", language, escapeCode(source));
} else {
return String.format("<pre><code>%s</code></pre>", escapeCode(source));
}
}
}

View File

@ -1,13 +1,17 @@
package org.mian.gitnex.notifications;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import androidx.work.Constraints;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.concurrent.TimeUnit;
@ -20,13 +24,52 @@ public class Notifications {
private static int notificationsSupported = -1;
private static void checkVersion(TinyDB tinyDB) {
public static int uniqueNotificationId(Context context) {
String currentVersion = tinyDB.getString("giteaVersion");
TinyDB tinyDB = TinyDB.getInstance(context);
if(tinyDB.getBoolean("loggedInMode") && !currentVersion.isEmpty()) {
int previousNotificationId = tinyDB.getInt("previousNotificationId", 0);
int nextPreviousNotificationId = previousNotificationId == Integer.MAX_VALUE ? 0 : previousNotificationId + 1;
tinyDB.putInt("previousNotificationId", nextPreviousNotificationId);
return previousNotificationId;
}
public static void createChannels(Context context) {
TinyDB tinyDB = TinyDB.getInstance(context);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Delete old notification channels
notificationManager.deleteNotificationChannel(context.getPackageName()); // TODO Can be removed in future versions
// Create new notification channels
NotificationChannel mainChannel = new NotificationChannel(Constants.mainNotificationChannelId, context.getString(R.string.mainNotificationChannelName), NotificationManager.IMPORTANCE_DEFAULT);
mainChannel.setDescription(context.getString(R.string.mainNotificationChannelDescription));
if(tinyDB.getBoolean("notificationsEnableVibration", true)) {
mainChannel.setVibrationPattern(new long[] { 1000, 1000 });
mainChannel.enableVibration(true);
} else {
mainChannel.enableVibration(false);
}
if(tinyDB.getBoolean("notificationsEnableLights", true)) {
mainChannel.setLightColor(tinyDB.getInt("notificationsLightColor", Color.GREEN));
mainChannel.enableLights(true);
} else {
mainChannel.enableLights(false);
}
NotificationChannel downloadChannel = new NotificationChannel(Constants.downloadNotificationChannelId, context.getString(R.string.fileViewerNotificationChannelName), NotificationManager.IMPORTANCE_LOW);
downloadChannel.setDescription(context.getString(R.string.fileViewerNotificationChannelDescription));
notificationManager.createNotificationChannel(mainChannel);
notificationManager.createNotificationChannel(downloadChannel);
notificationsSupported = new Version(currentVersion).higherOrEqual("1.12.3") ? 1 : 0;
}
}
@ -56,7 +99,7 @@ public class Notifications {
constraints.setRequiresDeviceIdle(false);
}
int pollingDelayMinutes = Math.max(tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay), 15);
int pollingDelayMinutes = Math.max(tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay), 15);
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(NotificationsWorker.class, pollingDelayMinutes, TimeUnit.MINUTES)
.setConstraints(constraints.build())
@ -68,4 +111,15 @@ public class Notifications {
}
}
}
private static void checkVersion(TinyDB tinyDB) {
String currentVersion = tinyDB.getString("giteaVersion");
if(tinyDB.getBoolean("loggedInMode") && !currentVersion.isEmpty()) {
notificationsSupported = new Version(currentVersion).higherOrEqual("1.12.3") ? 1 : 0;
}
}
}

View File

@ -1,15 +1,11 @@
package org.mian.gitnex.notifications;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
@ -20,7 +16,8 @@ import org.mian.gitnex.R;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import java.util.Date;
import java.util.List;
@ -34,7 +31,6 @@ import retrofit2.Response;
public class NotificationsWorker extends Worker {
private static final int MAXIMUM_NOTIFICATIONS = 100;
private static final long[] VIBRATION_PATTERN = new long[]{ 1000, 1000 };
private final Context context;
private final TinyDB tinyDB;
@ -45,17 +41,16 @@ public class NotificationsWorker extends Worker {
this.context = context;
this.tinyDB = TinyDB.getInstance(context);
}
@NonNull
@Override
public Result doWork() {
String token = "token " + tinyDB.getString(tinyDB.getString("loginUid") + "-token");
int notificationLoops = tinyDB.getInt("pollingDelayMinutes", Constants.defaultPollingDelay) >= 15 ? 1 : Math.min(15 - tinyDB.getInt("pollingDelayMinutes"), 10);
int notificationLoops = tinyDB.getInt("pollingDelayMinutes", StaticGlobalVariables.defaultPollingDelay) >= 15 ? 1 : Math.min(15 - tinyDB.getInt("pollingDelayMinutes"), 10);
for(int i=0; i<notificationLoops; i++) {
for(int i = 0; i < notificationLoops; i++) {
long startPollingTime = System.currentTimeMillis();
@ -65,7 +60,7 @@ public class NotificationsWorker extends Worker {
Call<List<NotificationThread>> call = RetrofitClient
.getApiInterface(context)
.getNotificationThreads(token, false, new String[]{"unread"}, previousRefreshTimestamp,
.getNotificationThreads(Authorization.get(context), false, new String[]{"unread"}, previousRefreshTimestamp,
null, 1, MAXIMUM_NOTIFICATIONS);
Response<List<NotificationThread>> response = call.execute();
@ -76,34 +71,24 @@ public class NotificationsWorker extends Worker {
List<NotificationThread> notificationThreads = response.body();
if(!notificationThreads.isEmpty()) {
if(!notificationThreads.isEmpty())
sendNotification(notificationThreads);
}
tinyDB.putString("previousRefreshTimestamp", AppUtil.getTimestampFromDate(context, new Date()));
}
else {
Log.e("onError", String.valueOf(response.code()));
}
}
catch(Exception e) {
Log.e("onError", e.toString());
}
} catch(Exception ignored) {}
try {
if(notificationLoops > 1 && i < (notificationLoops - 1)) {
Thread.sleep(60000 - (System.currentTimeMillis() - startPollingTime));
}
}
catch (InterruptedException ignored) {}
} catch (InterruptedException ignored) {}
}
return Result.success();
}
private void sendNotification(List<NotificationThread> notificationThreads) {
@ -112,7 +97,6 @@ public class NotificationsWorker extends Worker {
PendingIntent pendingIntent = getPendingIntent();
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
attachNotificationChannel(notificationManagerCompat);
Notification summaryNotification = new NotificationCompat.Builder(context, context.getPackageName())
.setContentTitle(context.getString(R.string.newMessages))
@ -122,15 +106,13 @@ public class NotificationsWorker extends Worker {
.setGroupSummary(true)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setChannelId(Constants.mainNotificationChannelId)
.build();
notificationManagerCompat.notify(summaryId, summaryNotification);
for(NotificationThread notificationThread : notificationThreads) {
NotificationManagerCompat notificationManagerCompat1 = NotificationManagerCompat.from(context);
attachNotificationChannel(notificationManagerCompat1);
String subjectUrl = notificationThread.getSubject().getUrl();
String issueId = context.getResources().getString(R.string.hash) + subjectUrl.substring(subjectUrl.lastIndexOf("/") + 1);
String notificationHeader = issueId + " " + notificationThread.getSubject().getTitle() + " " + String.format(context.getResources().getString(R.string.notificationExtraInfo), notificationThread.getRepository().getFull_name(), notificationThread.getSubject().getType());
@ -140,49 +122,8 @@ public class NotificationsWorker extends Worker {
.setGroup(context.getPackageName())
.setContentIntent(pendingIntent);
pushNotification(notificationManagerCompat1, builder1.build());
}
}
notificationManagerCompat.notify(Notifications.uniqueNotificationId(context), builder1.build());
private void pushNotification(NotificationManagerCompat notificationManagerCompat, Notification notification) {
int previousNotificationId = tinyDB.getInt("previousNotificationId", 0);
int nextPreviousNotificationId = previousNotificationId > 71951418 ? 0 : previousNotificationId + 1;
tinyDB.putInt("previousNotificationId", nextPreviousNotificationId);
notificationManagerCompat.notify(previousNotificationId, notification);
}
private void attachNotificationChannel(NotificationManagerCompat notificationManagerCompat) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(context.getPackageName(), context.getString(R.string.appName),
NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setDescription(context.getString(R.string.notificationChannelDescription));
if(tinyDB.getBoolean("notificationsEnableVibration", true)) {
notificationChannel.setVibrationPattern(VIBRATION_PATTERN);
notificationChannel.enableVibration(true);
}
else {
notificationChannel.enableVibration(false);
}
if(tinyDB.getBoolean("notificationsEnableLights", true)) {
notificationChannel.setLightColor(tinyDB.getInt("notificationsLightColor", Color.GREEN));
notificationChannel.enableLights(true);
}
else {
notificationChannel.enableLights(false);
}
notificationManagerCompat.createNotificationChannel(notificationChannel);
}
}
@ -193,6 +134,7 @@ public class NotificationsWorker extends Worker {
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setChannelId(Constants.mainNotificationChannelId)
.setAutoCancel(true);
if(tinyDB.getBoolean("notificationsEnableLights", true)) {
@ -201,11 +143,8 @@ public class NotificationsWorker extends Worker {
}
if(tinyDB.getBoolean("notificationsEnableVibration", true)) {
builder.setVibrate(VIBRATION_PATTERN);
}
else {
builder.setVibrate(new long[]{ 1000, 1000 });
} else {
builder.setVibrate(null);
}
@ -219,5 +158,6 @@ public class NotificationsWorker extends Worker {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
return PendingIntent.getActivity(context, 0, intent, 0);
}
}

View File

@ -18,6 +18,7 @@ import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.TinyDB;
import java.io.IOException;
import java.util.ArrayList;
@ -222,7 +223,7 @@ public class ReactionSpinner extends HorizontalScrollView {
if(response.isSuccessful() && response.body() != null) {
allowedReactions.addAll(Arrays.asList(response.body().getAllowed_reactions()));
} else {
allowedReactions.addAll(Arrays.asList("+1", "-1", "laugh", "hooray", "confused", "heart", "rocket", "eyes"));
allowedReactions.addAll(Arrays.asList(Constants.fallbackReactions));
}
return allowedReactions;

View File

@ -4,10 +4,7 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M22,19a2,2 0,0 1,-2 2H4a2,2 0,0 1,-2 -2V5a2,2 0,0 1,2 -2h5l2,3h9a2,2 0,0 1,2 2z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
android:fillColor="?attr/iconsColor"
android:pathData="M3.75,4.5a0.25,0.25 0,0 0,-0.25 0.25v14.5c0,0.138 0.112,0.25 0.25,0.25h16.5a0.25,0.25 0,0 0,0.25 -0.25V7.687a0.25,0.25 0,0 0,-0.25 -0.25h-8.471a1.75,1.75 0,0 1,-1.447 -0.765L8.928,4.61a0.25,0.25 0,0 0,-0.208 -0.11H3.75zM2,4.75C2,3.784 2.784,3 3.75,3h4.971c0.58,0 1.12,0.286 1.447,0.765l1.404,2.063a0.25,0.25 0,0 0,0.207 0.11h8.471c0.966,0 1.75,0.783 1.75,1.75V19.25A1.75,1.75 0,0 1,20.25 21H3.75A1.75,1.75 0,0 1,2 19.25V4.75z"
android:fillType="evenOdd"/>
</vector>

View File

@ -4,17 +4,7 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M13,2H6a2,2 0,0 0,-2 2v16a2,2 0,0 0,2 2h12a2,2 0,0 0,2 -2V9z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M13,2l0,7l7,0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
android:fillColor="?attr/iconsColor"
android:pathData="M5,2.5a0.5,0.5 0,0 0,-0.5 0.5v18a0.5,0.5 0,0 0,0.5 0.5h14a0.5,0.5 0,0 0,0.5 -0.5L19.5,8.5h-4a2,2 0,0 1,-2 -2v-4L5,2.5zM15,2.5v4a0.5,0.5 0,0 0,0.5 0.5h4a0.5,0.5 0,0 0,-0.146 -0.336l-4.018,-4.018A0.5,0.5 0,0 0,15 2.5zM3,3a2,2 0,0 1,2 -2h9.982a2,2 0,0 1,1.414 0.586l4.018,4.018A2,2 0,0 1,21 7.018L21,21a2,2 0,0 1,-2 2L5,23a2,2 0,0 1,-2 -2L3,3z"
android:fillType="evenOdd"/>
</vector>

View File

@ -4,24 +4,10 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
android:fillColor="?attr/iconsColor"
android:pathData="M10.97,8.265a1.45,1.45 0,0 0,-0.487 0.57,0.75 0.75,0 0,1 -1.341,-0.67c0.2,-0.402 0.513,-0.826 0.997,-1.148C10.627,6.69 11.244,6.5 12,6.5c0.658,0 1.369,0.195 1.934,0.619a2.45,2.45 0,0 1,1.004 2.006c0,1.033 -0.513,1.72 -1.027,2.215 -0.19,0.183 -0.399,0.358 -0.579,0.508l-0.147,0.123a4.329,4.329 0,0 0,-0.435 0.409v1.37a0.75,0.75 0,1 1,-1.5 0v-1.473c0,-0.237 0.067,-0.504 0.247,-0.736 0.22,-0.28 0.486,-0.517 0.718,-0.714l0.183,-0.153 0.001,-0.001c0.172,-0.143 0.324,-0.27 0.47,-0.412 0.368,-0.355 0.569,-0.676 0.569,-1.136a0.953,0.953 0,0 0,-0.404 -0.806C12.766,8.118 12.384,8 12,8c-0.494,0 -0.814,0.121 -1.03,0.265zM13,17a1,1 0,1 1,-2 0,1 1,0 0,1 2,0z"/>
<path
android:pathData="M9.09,9a3,3 0,0 1,5.83 1c0,2 -3,3 -3,3"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M12,17L12.01,17"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
android:fillColor="?attr/iconsColor"
android:pathData="M12,1C5.925,1 1,5.925 1,12s4.925,11 11,11 11,-4.925 11,-11S18.075,1 12,1zM2.5,12a9.5,9.5 0,1 1,19 0,9.5 9.5,0 0,1 -19,0z"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/iconsColor"
android:pathData="M2,4.75C2,3.784 2.784,3 3.75,3h4.965a1.75,1.75 0,0 1,1.456 0.78l1.406,2.109a0.25,0.25 0,0 0,0.208 0.111h8.465c0.966,0 1.75,0.784 1.75,1.75v11.5A1.75,1.75 0,0 1,20.25 21L3.75,21A1.75,1.75 0,0 1,2 19.25L2,4.75zM14.78,9.72a0.75,0.75 0,1 0,-1.06 1.06l1.72,1.72L6.75,12.5a0.75,0.75 0,0 0,0 1.5h8.69l-1.72,1.72a0.75,0.75 0,1 0,1.06 1.06l3,-3a0.75,0.75 0,0 0,0 -1.06l-3,-3z"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/iconsColor"
android:pathData="M3,3a2,2 0,0 1,2 -2h9.982a2,2 0,0 1,1.414 0.586l4.018,4.018A2,2 0,0 1,21 7.018L21,21a2,2 0,0 1,-2 2L4.75,23a0.75,0.75 0,0 1,0 -1.5L19,21.5a0.5,0.5 0,0 0,0.5 -0.5L19.5,8.5h-4a2,2 0,0 1,-2 -2v-4L5,2.5a0.5,0.5 0,0 0,-0.5 0.5v6.25a0.75,0.75 0,0 1,-1.5 0L3,3zM15,2.5v4a0.5,0.5 0,0 0,0.5 0.5h4a0.5,0.5 0,0 0,-0.146 -0.336l-4.018,-4.018A0.5,0.5 0,0 0,15 2.5zM9.308,14.5l-2.104,-2.236a0.75,0.75 0,1 1,1.092 -1.028l3.294,3.5a0.75,0.75 0,0 1,0 1.028l-3.294,3.5a0.75,0.75 0,1 1,-1.092 -1.028L9.308,16L4.09,16a2.59,2.59 0,0 0,-2.59 2.59v3.16a0.75,0.75 0,0 1,-1.5 0v-3.16a4.09,4.09 0,0 1,4.09 -4.09h5.218z"
android:fillType="evenOdd"/>
</vector>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
@ -64,20 +65,21 @@
android:orientation="vertical">
<LinearLayout
android:id="@+id/singleFileContentsFrame"
android:id="@+id/markdownFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryBackgroundColor"
android:orientation="vertical"
android:padding="16dp"
android:orientation="vertical">
android:visibility="gone">
<TextView
android:id="@+id/singleFileContents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp"
android:textIsSelectable="true" />
<TextView
android:id="@+id/markdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="14sp" />
</LinearLayout>
@ -86,7 +88,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryBackgroundColor"
android:orientation="vertical">
android:orientation="vertical"
android:visibility="gone">
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfView"
@ -96,15 +99,15 @@
</LinearLayout>
<org.mian.gitnex.helpers.highlightjs.HighlightJsView
android:id="@+id/singleCodeContents"
<org.mian.gitnex.helpers.SyntaxHighlightedArea
android:id="@+id/contents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:visibility="gone" />
android:visibility="gone"
tools:visibility="visible" />
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/imageView"
android:id="@+id/photo_view"
android:visibility="gone"
android:padding="16dp"
android:layout_width="match_parent"

View File

@ -1,108 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/layoutFileView"
android:orientation="vertical"
android:background="?attr/primaryBackgroundColor">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Widget.AppCompat.SearchView">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryBackgroundColor"
android:theme="@style/AppTheme.AppBarOverlay">
<ImageView
android:id="@+id/close"
android:layout_width="@dimen/close_button_size"
android:layout_height="@dimen/close_button_size"
android:layout_marginRight="15dp"
android:layout_marginLeft="15dp"
android:gravity="center_vertical"
android:contentDescription="@string/close"
android:src="@drawable/ic_close" />
<TextView
android:id="@+id/toolbar_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/fileViewerHeader"
android:textColor="?attr/primaryTextColor"
android:maxLines="1"
android:textSize="20sp" />
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:id="@+id/sourceCodeThemeFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/sourceCodeThemeHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:layout_marginStart="44dp"
android:layout_marginEnd="24dp"
android:text="@string/settingsFileViewerSourceCodeHeaderText"
android:textColor="?attr/primaryTextColor"/>
<TextView
android:id="@+id/sourceCodeThemeSelected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginStart="44dp"
android:layout_marginEnd="24dp"
android:text="@string/settingsFileViewerSourceCodeSelectedText"
android:textColor="?attr/selectedTextColor"/>
</LinearLayout>
<RelativeLayout
android:id="@+id/pdfMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal">
<TextView
android:id="@+id/pdfModeHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginStart="44dp"
android:layout_marginEnd="24dp"
android:text="@string/settingsPdfModeHeaderText"
android:textColor="?attr/primaryTextColor"/>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switchPdfMode"
android:layout_toEndOf="@+id/pdfModeHeader"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:switchMinWidth="56dp"
android:paddingStart="0dp"
android:paddingEnd="25dp"
android:layout_alignParentEnd="true"
android:gravity="end"
android:layout_gravity="end" />
</RelativeLayout>
</LinearLayout>

View File

@ -46,10 +46,11 @@
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_bar"
style="@style/Widget.MaterialComponents.LinearProgressIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/filesFrame"
android:indeterminate="true"
style="@style/Widget.MaterialComponents.LinearProgressIndicator"
app:indicatorColor="?attr/progressIndicatorColor" />
</RelativeLayout>

View File

@ -21,80 +21,72 @@
android:contentDescription="@string/generalImgContentText"
android:scaleType="centerCrop" />
<eightbitlab.com.blurview.BlurView
android:id="@+id/blurView"
<LinearLayout
android:id="@+id/layoutFrameAccount"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:blurOverlayColor="@color/blurColor">
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="54dp"
android:layout_height="54dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
<TextView
android:id="@+id/userFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
<View
android:id="@+id/divider"
android:layout_width="50dp"
android:layout_height="1dp"
android:layout_marginBottom="10dp"
android:background="@color/colorWhite" />
<LinearLayout
android:id="@+id/layoutFrameAccount"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="54dp"
android:layout_height="54dp"
android:layout_marginBottom="8dp"
android:id="@+id/userLanguageIcon"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginEnd="2dp"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
android:src="@drawable/ic_language"
app:tint="@color/colorWhite" />
<TextView
android:id="@+id/userFullName"
android:id="@+id/userLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
<View
android:id="@+id/divider"
android:layout_width="50dp"
android:layout_height="1dp"
android:layout_marginBottom="10dp"
android:background="@color/colorWhite" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ImageView
android:id="@+id/userLanguageIcon"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginEnd="2dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_language"
app:tint="@color/colorWhite" />
<TextView
android:id="@+id/userLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</eightbitlab.com.blurview.BlurView>
</LinearLayout>
</RelativeLayout>

View File

@ -81,38 +81,6 @@
</LinearLayout>
<LinearLayout
android:id="@+id/fileViewerFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="25dp">
<TextView
android:id="@+id/fileViewer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="24dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:text="@string/fileViewerHeader"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
app:drawableStartCompat="@drawable/ic_file" />
<TextView
android:id="@+id/fileViewerHintText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="60dp"
android:paddingEnd="12dp"
android:text="@string/fileViewerHintText"
android:textColor="?attr/primaryTextColor"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/draftsFrame"
android:layout_width="match_parent"

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryBackgroundColor"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingRight="15dp"
android:paddingBottom="10dp">
<ImageView
android:id="@+id/commiter_avatar"
android:layout_width="35dp"
android:layout_height="35dp"
android:contentDescription="@string/generalImgContentText"
tools:srcCompat="@tools:sample/avatars" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:orientation="vertical">
<TextView
android:id="@+id/commit_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:textColor="?attr/primaryTextColor"
android:textStyle="bold"
tools:text="Voluptatem vero ad quia voluptatum quisquam. Nihil earum et praesentium." />
<TextView
android:id="@+id/commit_sha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="?attr/primaryTextColor"
app:drawableStartCompat="@drawable/ic_commit"
app:drawableTint="?attr/primaryTextColor"
tools:text="afcfb7c15a" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dividerColor" />
</LinearLayout>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fileFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"

View File

@ -4,102 +4,83 @@
android:id="@+id/relativeLayoutFrameIssuesList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="15dp"
android:orientation="vertical"
android:background="?attr/primaryBackgroundColor">
<TextView
android:id="@+id/issueNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
<ImageView
android:id="@+id/assigneeAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="15dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_android" />
<TextView
android:id="@+id/repoFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
<RelativeLayout
android:id="@+id/mainFrame"
<LinearLayout
android:id="@+id/infoSection"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="15dp"
android:layout_toEndOf="@+id/assigneeAvatar"
android:orientation="vertical">
<ImageView
android:id="@+id/assigneeAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="15dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_android" />
<LinearLayout
android:id="@+id/infoSection"
android:id="@+id/frameIssueNameStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/assigneeAvatar"
android:orientation="vertical">
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/issueTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|center_vertical"
android:textAlignment="gravity"
android:text="@string/strFilter"
android:textColor="?attr/primaryTextColor"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/frameCreatedDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/frameIssueNameStatus"
android:layout_width="match_parent"
android:id="@+id/frameCommentsCount"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/issueTitle"
android:id="@+id/issueCommentsCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|center_vertical"
android:textAlignment="gravity"
android:text="@string/strFilter"
android:textColor="?attr/primaryTextColor"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/frameCreatedDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/frameCommentsCount"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/issueCommentsCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:drawablePadding="5dp"
app:drawableStartCompat="@drawable/ic_comment"
android:layout_gravity="center_horizontal"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp" />
</LinearLayout>
<TextView
android:id="@+id/issueCreatedTime"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:gravity="end"
android:gravity="start"
android:drawablePadding="5dp"
app:drawableStartCompat="@drawable/ic_comment"
android:layout_gravity="center_horizontal"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp" />
</LinearLayout>
<TextView
android:id="@+id/issueCreatedTime"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:gravity="end"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -5,119 +5,82 @@
android:id="@+id/relativeLayoutFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="15dp"
android:orientation="vertical"
android:background="?attr/primaryBackgroundColor">
<TextView
android:id="@+id/prNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<ImageView
android:id="@+id/assigneeAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="15dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_android" />
<TextView
android:id="@+id/prMergeable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prHeadBranch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prIsFork"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prForkFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<RelativeLayout
android:id="@+id/mainFrame"
<LinearLayout
android:id="@+id/infoSection"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="15dp"
android:layout_toEndOf="@+id/assigneeAvatar"
android:orientation="vertical">
<ImageView
android:id="@+id/assigneeAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="15dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_android" />
<LinearLayout
android:id="@+id/infoSection"
android:id="@+id/framePrNameStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/assigneeAvatar"
android:orientation="vertical">
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/framePrNameStatus"
android:layout_width="match_parent"
<TextView
android:id="@+id/prTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/prTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|center_vertical"
android:textAlignment="gravity"
android:textColor="?attr/primaryTextColor"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/frameCreatedDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/frameCommentsCount"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/prCommentsCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:drawablePadding="5dp"
android:layout_gravity="center_horizontal"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp"
app:drawableStartCompat="@drawable/ic_comment" />
</LinearLayout>
<TextView
android:id="@+id/prCreatedTime"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:gravity="end"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp" />
</LinearLayout>
android:gravity="top|center_vertical"
android:textAlignment="gravity"
android:textColor="?attr/primaryTextColor"
android:textSize="18sp" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:id="@+id/frameCreatedDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/frameCommentsCount"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/prCommentsCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:drawablePadding="5dp"
android:layout_gravity="center_horizontal"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp"
app:drawableStartCompat="@drawable/ic_comment" />
</LinearLayout>
<TextView
android:id="@+id/prCreatedTime"
android:layout_width="0dp"
android:layout_weight=".25"
android:layout_height="wrap_content"
android:gravity="end"
android:textColor="?attr/primaryTextColor"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navHeaderFrame"
android:layout_width="match_parent"
android:layout_height="200dp">
@ -10,106 +11,79 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generalImgContentText"
android:scaleType="centerCrop" />
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<eightbitlab.com.blurview.BlurView
android:id="@+id/blurView"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:blurOverlayColor="@color/blurColor">
android:gravity="bottom"
android:orientation="vertical"
android:paddingStart="20dp"
android:paddingTop="20dp"
android:paddingEnd="20dp"
android:paddingBottom="20dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:paddingTop="16dp">
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="24dp"
android:maxWidth="24dp"
android:paddingStart="20dp"
android:paddingEnd="5dp"
android:contentDescription="@string/generalImgContentText"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingEnd="25dp"
android:paddingStart="15dp"
android:paddingTop="6dp"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/navRecyclerViewUserAccounts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:reverseLayout="true"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
<LinearLayout
<ImageView
android:id="@+id/userAvatar"
android:layout_width="60dp"
android:layout_height="60dp"
android:contentDescription="@string/generalImgContentText"
tools:srcCompat="@tools:sample/avatars" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/navRecyclerViewUserAccounts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:layout_marginTop="5dp"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".82"
android:orientation="vertical"
android:layout_marginTop="5dp">
<TextView
android:id="@+id/userFullname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:textSize="18sp"
android:textIsSelectable="true"
android:textColor="@color/colorWhite"
android:paddingStart="20dp"
android:paddingEnd="5dp" />
<TextView
android:id="@+id/userEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textIsSelectable="true"
android:textColor="@color/colorWhite"
android:gravity="start"
android:layout_gravity="center_vertical"
android:paddingStart="20dp"
android:paddingEnd="5dp" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="?attr/dividerColor" />
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:reverseLayout="true" />
</LinearLayout>
</eightbitlab.com.blurview.BlurView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:baselineAligned="false"
android:orientation="vertical">
<TextView
android:id="@+id/userFullname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="18sp"
tools:text="Test user" />
<TextView
android:id="@+id/userEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp"
tools:text="example@example.com" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_marginTop="16dp"
android:background="?attr/dividerColor" />
</RelativeLayout>

View File

@ -479,7 +479,7 @@
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -530,7 +530,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -562,6 +562,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -619,4 +621,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Datei herunterladen</string>
<string name="waitLoadingDownloadFile">Bitte warte, bis die Datei in den Speicher geladen wurde</string>
<string name="downloadFileSaved">Datei erfolgreich gespeichert</string>
<string name="excludeFilesInFileViewer">Dieser Dateityp wird nicht vom Datei-Viewer unterstützt. Du kannst sie stattdessen übers Menü herunterladen?</string>
<string name="excludeFilesInFileViewer">Diese(r) Dateityp / Dateigröße wird vom Dateibetrachter nicht unterstützt. Du kannst es über das Menü herunterladen.</string>
<string name="deleteFile">Diese Datei löschen</string>
<string name="editFile">Diese Datei bearbeiten</string>
<string name="deleteFileText">Lösche %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Entwurf wurde automatisch gespeichert.</string>
<string name="appearanceHintText">Themen, Schriften, Abzeichen</string>
<string name="fileViewerHintText">PDF-Modus, Quellcode Theme</string>
<string name="securityHintText">SSL-Zertifikate, Cache</string>
<string name="securityHintText">Biometrische Authentifizierung, SSL-Zertifikate, Cache</string>
<string name="languagesHintText">Sprachen</string>
<string name="reportsHintText">Absturzberichte</string>
<string name="rateAppHintText">Wenn dir GitNex gefällt, hinterlassen Feedback</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Farbe auswählen</string>
<string name="newMessages">Neue Nachrichten</string>
<string name="youHaveGotNewNotifications">Du hast %d neue Nachrichten.</string>
<string name="mainNotificationChannelName">Benachrichtigungen</string>
<string name="mainNotificationChannelDescription">Das ist der Haupt-Nachrichten-Kanal von GitNex.</string>
<string name="isRead">Gelesen</string>
<string name="isUnread">Ungelesen</string>
<string name="repoSettingsTitle">Repository Einstellungen</string>
@ -615,5 +617,14 @@
<string name="biometricNotSupported">Keine biometrischen Funktionen verfügbar</string>
<string name="biometricNotAvailable">Biometrischen Funktionen zur zeit nicht verfügbar</string>
<string name="enrollBiometric">Biometrische Daten in den Telefoneinstellungen registrieren</string>
<string name="copyLoginIdToClipBoard">Login-ID \'%s\' in Zwischenablage kopiert</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' in Zwischenablage kopiert</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download läuft</string>
<string name="fileViewerNotificationDescriptionStarted">Lade %s herunter</string>
<string name="fileViewerNotificationTitleFinished">Download erfolgreich</string>
<string name="fileViewerNotificationDescriptionFinished">%s heruntergeladen</string>
<string name="fileViewerNotificationTitleFailed">Download fehlgeschlagen</string>
<string name="fileViewerNotificationDescriptionFailed">Konnte %s nicht downloaden</string>
<string name="fileViewerNotificationChannelName">Download Manager</string>
<string name="fileViewerNotificationChannelDescription">Zeigt den Fortschritt laufender Downloads an</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Descargar este archivo</string>
<string name="waitLoadingDownloadFile">Por favor espere a que el dispositivo cargue</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">Este tipo de archivo no es compatible con el visor de archivos. ¿Descargarlo en su lugar desde el menú de tres puntos?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -479,7 +479,7 @@
<string name="downloadFile">بارگیری این پرونده</string>
<string name="waitLoadingDownloadFile">لطفا منتظر بمانید تا پرونده در حافظه بارگذاری شود</string>
<string name="downloadFileSaved">پرونده با موفقیت ذخیره شد</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">حذف این پرونده</string>
<string name="editFile">ویرایش این پرونده</string>
<string name="deleteFileText">حذف %1$s</string>
@ -530,7 +530,7 @@
<string name="draftSaved">پیش نویس خودکار ذخیره شد.</string>
<string name="appearanceHintText">پوسته‌ها، فونت‌ها، نشانگرها</string>
<string name="fileViewerHintText">حالت PDF، پوسته کد منبع</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">زبان‌ها</string>
<string name="reportsHintText">گزارش‌های خرابی</string>
<string name="rateAppHintText">اگر GitNex را می‌پسندید می‌توانید به آن امتیاز دهید</string>
@ -562,6 +562,8 @@
<string name="chooseColorSelectorHeader">انتخاب رنگ</string>
<string name="newMessages">پیام‌های جدید</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">خوانده شده</string>
<string name="isUnread">خوانده نشده</string>
<string name="repoSettingsTitle">تنظیمات مخزن</string>
@ -619,4 +621,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Télécharger ce fichier</string>
<string name="waitLoadingDownloadFile">Chargement du fichier dans la mémoire</string>
<string name="downloadFileSaved">Fichier sauvegardé avec succès</string>
<string name="excludeFilesInFileViewer">La visionneuse ne prend pas en charge ce type de fichier. Télécharger ce fichier ?</string>
<string name="excludeFilesInFileViewer">Le fichier incompatible ou trop grand pour la visionneuse. Vous pouvez toutefois le télécharger depuis le menu.</string>
<string name="deleteFile">Supprimer ce fichier</string>
<string name="editFile">Éditer ce fichier</string>
<string name="deleteFileText">Supprimer %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Brouillon sauvegardé automatiquement</string>
<string name="appearanceHintText">Thèmes, polices, badges</string>
<string name="fileViewerHintText">Mode PDF, couleurs du code source</string>
<string name="securityHintText">Certificats SSL, cache</string>
<string name="securityHintText">Biométrie, certificats SSL, cache</string>
<string name="languagesHintText">Langues</string>
<string name="reportsHintText">Rapports de plantage</string>
<string name="rateAppHintText">Vous aimez GitNex ? Mettez-lui un pouce !</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Couleur</string>
<string name="newMessages">Nouveaux messages</string>
<string name="youHaveGotNewNotifications">Vous avez %d nouvelles notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">Le canal de notifications principal de GitNex.</string>
<string name="isRead">Lu</string>
<string name="isUnread">Non lu</string>
<string name="repoSettingsTitle">Paramètres du dépôt</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">La biométrie nest pas disponible pour le moment</string>
<string name="enrollBiometric">Paramétrer la biométrie dans les réglages de l\'appareil</string>
<string name="copyLoginIdToClipBoard">ID \'%s\' copié dans le presse-papier</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Téléchargement en cours</string>
<string name="fileViewerNotificationDescriptionStarted">%s téléchargé</string>
<string name="fileViewerNotificationTitleFinished">Téléchargement terminé</string>
<string name="fileViewerNotificationDescriptionFinished">%s téléchargé</string>
<string name="fileViewerNotificationTitleFailed">Échec du téléchargement</string>
<string name="fileViewerNotificationDescriptionFailed">Impossible de télécharger %s</string>
<string name="fileViewerNotificationChannelName">Gestionnaire de téléchargement</string>
<string name="fileViewerNotificationChannelDescription">Indique la progression des téléchargements</string>
</resources>

View File

@ -478,7 +478,7 @@ autorizzazione</string>
<string name="downloadFile">Scarica Questo File</string>
<string name="waitLoadingDownloadFile">Attendere che il file venga caricato in memoria</string>
<string name="downloadFileSaved">File salvato con successo</string>
<string name="excludeFilesInFileViewer">Questo tipo di file non è supportato nel visualizzatore di file. Scaricarlo invece dal menu con i tre punti?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -529,7 +529,7 @@ autorizzazione</string>
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">Modalità PDF, tema codice sorgente</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Lingue</string>
<string name="reportsHintText">Rapporti crash</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -561,6 +561,8 @@ autorizzazione</string>
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Letto</string>
<string name="isUnread">Non letto</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -618,4 +620,13 @@ autorizzazione</string>
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Pobierz ten plik</string>
<string name="waitLoadingDownloadFile">Poczekaj aż plik załaduje się do pamięci</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">Ten typ pliku nie jest obsługiwany w przeglądarce plików. Pobrać go z trzech kropkowanych menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Baixar este arquivo</string>
<string name="waitLoadingDownloadFile">Aguarde que o arquivo seja carregado para a memória</string>
<string name="downloadFileSaved">Arquivo salvo com êxito</string>
<string name="excludeFilesInFileViewer">Esse tipo de arquivo não é suportado no visualizador de arquivos. Baixe-o no menu de três pontos?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Excluir Este Arquivo</string>
<string name="editFile">Editar Este Arquivo</string>
<string name="deleteFileText">Excluir %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">O rascunho foi salvo automaticamente.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">Modo PDF, tema do código fonte</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Idiomas</string>
<string name="reportsHintText">Relatórios de erros</string>
<string name="rateAppHintText">Se você gosta do GitNex você pode dar um joinha</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Lida</string>
<string name="isUnread">Não Lida</string>
<string name="repoSettingsTitle">Configurações do repositório</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Скачать этот файл</string>
<string name="waitLoadingDownloadFile">Пожалуйста дождитесь загрузки файла</string>
<string name="downloadFileSaved">Файл успешно сохранён</string>
<string name="excludeFilesInFileViewer">Этот тип файла не поддерживается в средстве просмотра файлов. Загрузить его?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Удалить этот файл</string>
<string name="editFile">Редактировать этот файл</string>
<string name="deleteFileText">Удалить %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF режим, исходный код темы</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Языки</string>
<string name="reportsHintText">Отчёты об ошибках</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Прочитано</string>
<string name="isUnread">Непрочитано</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Преузми овај фајл</string>
<string name="waitLoadingDownloadFile">Сачекај да се фајл учита у меморију</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">Прегледач фајлова не подржава овај тип. Да ли желиш да преузмеш фајл?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">Завантажити цей файл</string>
<string name="waitLoadingDownloadFile">Зачекайте, поки файл завантажиться</string>
<string name="downloadFileSaved">Файл успішно збережений</string>
<string name="excludeFilesInFileViewer">Цей тип файлу не підтримується у переглядачі файлів. Завантажити його з меню?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">Draft was saved automatically.</string>
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">Режим PDF-версії, тема відображення коду</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Мови</string>
<string name="reportsHintText">Звіти про падіння</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">Read</string>
<string name="isUnread">Unread</string>
<string name="repoSettingsTitle">Repository Settings</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">Biometric features are currently unavailable</string>
<string name="enrollBiometric">Enroll biometric from phone settings</string>
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -476,7 +476,7 @@
<string name="downloadFile">下载此文件</string>
<string name="waitLoadingDownloadFile">请等待文件加载到内存</string>
<string name="downloadFileSaved">文件保存成功</string>
<string name="excludeFilesInFileViewer">这个文件类型在文件查看器中不支持。从三个虚线菜单下载吗?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">删除此文件</string>
<string name="editFile">编辑此文件</string>
<string name="deleteFileText">删除 %1$s</string>
@ -527,7 +527,7 @@
<string name="draftSaved">草稿已自动保存。</string>
<string name="appearanceHintText">主题、字体、徽章</string>
<string name="fileViewerHintText">PDF 模式,源代码主题</string>
<string name="securityHintText">SSL 证书、缓存</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">语言</string>
<string name="reportsHintText">崩溃报告</string>
<string name="rateAppHintText">如果你喜欢GitNex你可以给它点赞</string>
@ -559,6 +559,8 @@
<string name="chooseColorSelectorHeader">选择颜色</string>
<string name="newMessages">新消息</string>
<string name="youHaveGotNewNotifications">您有%d条新通知</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="isRead">已读</string>
<string name="isUnread">未读</string>
<string name="repoSettingsTitle">存储库设置</string>
@ -616,4 +618,13 @@
<string name="biometricNotAvailable">生物特征功能当前不可用</string>
<string name="enrollBiometric">从手机设置中注册生物识别</string>
<string name="copyLoginIdToClipBoard">登录 ID \'%s\' 已复制到剪贴板</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -578,7 +578,7 @@
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
<string name="downloadFileSaved">File saved successfully</string>
<string name="excludeFilesInFileViewer">This file type is not supported in file viewer. Download it instead from the three dotted menu?</string>
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
@ -639,7 +639,7 @@
<string name="appearanceHintText">Themes, fonts, badges</string>
<string name="fileViewerHintText">PDF mode, source code theme</string>
<string name="securityHintText">SSL certificates, cache</string>
<string name="securityHintText">Biometric authentication, SSL certificates, cache</string>
<string name="languagesHintText">Languages</string>
<string name="reportsHintText">Crash reports</string>
<string name="rateAppHintText">If you like GitNex you can give it a thumbs up</string>
@ -674,7 +674,8 @@
<string name="chooseColorSelectorHeader">Choose Color</string>
<string name="newMessages">New messages</string>
<string name="youHaveGotNewNotifications">You\'ve got %d new notifications.</string>
<string name="notificationChannelDescription" translatable="false">This is the main notification channel of GitNex.</string>
<string name="mainNotificationChannelName">Notifications</string>
<string name="mainNotificationChannelDescription">This is the main notification channel of GitNex.</string>
<string name="notificationExtraInfo" translatable="false">- %s (%s)</string>
<string name="isRead">Read</string>
@ -744,4 +745,15 @@
<string name="copyLoginIdToClipBoard">Login ID \'%s\' copied to clipboard</string>
<!-- file viewer activity -->
<string name="fileViewerNotificationTitleStarted">Download in progress</string>
<string name="fileViewerNotificationDescriptionStarted">Downloading %s</string>
<string name="fileViewerNotificationTitleFinished">Download successful</string>
<string name="fileViewerNotificationDescriptionFinished">Downloaded %s</string>
<string name="fileViewerNotificationTitleFailed">Download failed</string>
<string name="fileViewerNotificationDescriptionFailed">Couldn\'t download %s</string>
<string name="fileViewerNotificationChannelName">Download manager</string>
<string name="fileViewerNotificationChannelDescription">Indicates the progress of ongoing downloads</string>
</resources>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog>
<release version="3.5.0-dev" versioncode="346">
<release version="4.0.0-dev" versioncode="395">
<change>Under development</change>
</release>

View File

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.android.tools.build:gradle:4.1.3'
}
}

View File

@ -0,0 +1,13 @@
3.5.0
New: Render emoji in issue/pr titles, commit message and markdown files
New: Cron tasks (Admin only)
New: Biometric support to unlock the app
New: Switch to saved instance when coming from email/links
New: Copy user login id to clipboard
New: Progress notification for downloading files
New: Rewrite file viewer in native code to move away from traditional js to load files faster
Release Notes: https://codeberg.org/gitnex/GitNex/releases
Release Blog: https://gitnex.codeberg.page/posts/350.html

Some files were not shown because too many files have changed in this diff Show More