diff --git a/README.md b/README.md index bc8be288..eeaedf1a 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Thanks to all the open source libraries, contributors, and donors. - [ocpsoft/prettytime](https://github.com/ocpsoft/prettytime) - [ramseth001/TextDrawable](https://github.com/ramseth001/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) +- [skydoves/ColorPickerView](https://github.com/skydoves/ColorPickerView) - [HamidrezaAmz/BreadcrumbsView](https://github.com/HamidrezaAmz/BreadcrumbsView) - [Baseflow/PhotoView](https://github.com/Baseflow/PhotoView) - [apache/commons](https://github.com/apache/commons-io) diff --git a/app/build.gradle b/app/build.gradle index 1988c22a..3dc10f92 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,7 +4,6 @@ plugins { apply plugin: 'com.android.application' android { - compileSdkVersion 34 defaultConfig { applicationId "org.mian.gitnex" minSdkVersion 23 @@ -13,8 +12,9 @@ android { versionName "5.3.0-dev" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + compileSdk 34 } - flavorDimensions "default" + flavorDimensions = ["default"] productFlavors { free { applicationId "org.mian.gitnex" @@ -57,13 +57,13 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.11.0-alpha03' - implementation 'androidx.compose.material3:material3:1.2.0-alpha08' - implementation 'androidx.compose.material3:material3-window-size-class:1.2.0-alpha08' + implementation 'com.google.android.material:material:1.11.0' + implementation 'androidx.compose.material3:material3:1.2.0-beta02' + implementation 'androidx.compose.material3:material3-window-size-class:1.2.0-beta02' implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation "androidx.lifecycle:lifecycle-viewmodel:2.6.2" + implementation "androidx.lifecycle:lifecycle-viewmodel:2.7.0" testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' @@ -76,7 +76,7 @@ dependencies { implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2' implementation 'org.ocpsoft.prettytime:prettytime:5.0.7.Final' - implementation 'com.github.Pes8:android-material-color-picker-dialog:master' + implementation "com.github.skydoves:colorpickerview:2.3.0" implementation "io.noties.markwon:core:4.6.2" implementation "io.noties.markwon:ext-latex:4.6.2" implementation "io.noties.markwon:ext-strikethrough:4.6.2" @@ -99,18 +99,18 @@ dependencies { implementation 'ch.acra:acra-mail:5.11.2' implementation 'ch.acra:acra-limiter:5.11.2' implementation 'ch.acra:acra-notification:5.11.2' - implementation 'androidx.room:room-runtime:2.5.2' - annotationProcessor 'androidx.room:room-compiler:2.5.2' - implementation "androidx.work:work-runtime:2.8.1" + implementation 'androidx.room:room-runtime:2.6.1' + annotationProcessor 'androidx.room:room-compiler:2.6.1' + implementation "androidx.work:work-runtime:2.9.0" implementation "io.mikael:urlbuilder:2.0.9" implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2" //noinspection GradleDependency coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" implementation 'androidx.biometric:biometric:1.1.0' implementation 'com.github.chrisvest:stormpot:2.4.2' - implementation 'androidx.browser:browser:1.6.0' + implementation 'androidx.browser:browser:1.7.0' implementation 'com.google.android.flexbox:flexbox:3.0.0' - implementation('org.codeberg.gitnex:tea4j-autodeploy:65f700d036') { + implementation('org.codeberg.gitnex:tea4j-autodeploy:4646f53557') { exclude module: 'org.apache.oltu.oauth2.common' } implementation 'io.github.amrdeveloper:codeview:1.3.8' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 27eafece..9d0af8f6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> @@ -69,13 +73,16 @@ android:theme="@style/AppTheme.NoActionBar"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> + android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" + android:windowSoftInputMode="adjustResize"/> @@ -165,7 +176,7 @@ + android:windowSoftInputMode="adjustResize"/> processAddNewEmail(); private ActivityAccountSettingsEmailBinding activityAccountSettingsEmailBinding; @Override @@ -41,56 +35,42 @@ public class AccountSettingsEmailActivity extends BaseActivity { ActivityAccountSettingsEmailBinding.inflate(getLayoutInflater()); setContentView(activityAccountSettingsEmailBinding.getRoot()); - boolean connToInternet = AppUtil.hasNetworkConnection(appCtx); + activityAccountSettingsEmailBinding.topAppBar.setNavigationOnClickListener(v -> finish()); - InputMethodManager imm = - (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + activityAccountSettingsEmailBinding.topAppBar.setOnMenuItemClickListener( + menuItem -> { + int id = menuItem.getItemId(); - activityAccountSettingsEmailBinding.userEmail.requestFocus(); - assert imm != null; - imm.showSoftInput( - activityAccountSettingsEmailBinding.userEmail, InputMethodManager.SHOW_IMPLICIT); - - initCloseListener(); - activityAccountSettingsEmailBinding.close.setOnClickListener(onClickListener); - - if (!connToInternet) { - - disableProcessButton(); - } else { - - activityAccountSettingsEmailBinding.addEmailButton.setOnClickListener(addEmailListener); - } + if (id == R.id.save) { + processAddNewEmail(); + return true; + } else { + return super.onOptionsItemSelected(menuItem); + } + }); } private void processAddNewEmail() { - boolean connToInternet = AppUtil.hasNetworkConnection(appCtx); - String newUserEmail = Objects.requireNonNull(activityAccountSettingsEmailBinding.userEmail.getText()) .toString() .trim(); - if (!connToInternet) { - - Toasty.error(ctx, getResources().getString(R.string.checkNetConnection)); - return; - } - if (newUserEmail.equals("")) { - Toasty.error(ctx, getString(R.string.emailErrorEmpty)); + SnackBar.error( + ctx, findViewById(android.R.id.content), getString(R.string.emailErrorEmpty)); return; } else if (!Patterns.EMAIL_ADDRESS.matcher(newUserEmail).matches()) { - Toasty.warning(ctx, getString(R.string.emailErrorInvalid)); + SnackBar.error( + ctx, findViewById(android.R.id.content), getString(R.string.emailErrorInvalid)); return; } List newEmailList = new ArrayList<>(Arrays.asList(newUserEmail.split(","))); - disableProcessButton(); addNewEmail(newEmailList); } @@ -111,54 +91,44 @@ public class AccountSettingsEmailActivity extends BaseActivity { if (response.code() == 201) { - Toasty.success(ctx, getString(R.string.emailAddedText)); + SnackBar.info( + ctx, + findViewById(android.R.id.content), + getString(R.string.emailAddedText)); AccountSettingsEmailsFragment.refreshEmails = true; - enableProcessButton(); - finish(); + new Handler().postDelayed(() -> finish(), 3000); } else if (response.code() == 401) { - enableProcessButton(); AlertDialogs.authorizationTokenRevokedDialog(ctx); } else if (response.code() == 403) { - enableProcessButton(); - Toasty.error(ctx, ctx.getString(R.string.authorizeError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.authorizeError)); } else if (response.code() == 404) { - enableProcessButton(); - Toasty.warning(ctx, ctx.getString(R.string.apiNotFound)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.apiNotFound)); } else if (response.code() == 422) { - enableProcessButton(); - Toasty.warning(ctx, ctx.getString(R.string.emailErrorInUse)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.emailErrorInUse)); } else { - enableProcessButton(); - Toasty.error(ctx, getString(R.string.genericError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.genericError)); } } @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - enableProcessButton(); - } + public void onFailure(@NonNull Call> call, @NonNull Throwable t) {} }); } - - private void initCloseListener() { - - onClickListener = view -> finish(); - } - - private void disableProcessButton() { - - activityAccountSettingsEmailBinding.addEmailButton.setEnabled(false); - } - - private void enableProcessButton() { - - activityAccountSettingsEmailBinding.addEmailButton.setEnabled(true); - } } diff --git a/app/src/main/java/org/mian/gitnex/activities/AddNewAccountActivity.java b/app/src/main/java/org/mian/gitnex/activities/AddNewAccountActivity.java index 822d7453..66fc19b5 100644 --- a/app/src/main/java/org/mian/gitnex/activities/AddNewAccountActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/AddNewAccountActivity.java @@ -3,8 +3,7 @@ package org.mian.gitnex.activities; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; -import android.util.Log; -import android.view.View; +import android.os.Handler; import android.widget.ArrayAdapter; import androidx.annotation.NonNull; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -22,7 +21,7 @@ import org.mian.gitnex.database.models.UserAccount; import org.mian.gitnex.databinding.ActivityAddNewAccountBinding; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.PathsHelper; -import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.UrlHelper; import org.mian.gitnex.helpers.Version; import org.mian.gitnex.structs.Protocol; @@ -34,7 +33,6 @@ import retrofit2.Callback; */ public class AddNewAccountActivity extends BaseActivity { - private View.OnClickListener onClickListener; private ActivityAddNewAccountBinding viewBinding; private String spinnerSelectedValue; @@ -52,8 +50,6 @@ public class AddNewAccountActivity extends BaseActivity { getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT)); - initCloseListener(); - viewBinding.close.setOnClickListener(onClickListener); viewBinding.instanceUrl.setText(getIntent().getStringExtra("instanceUrl")); viewBinding.loginToken.setText(getIntent().getStringExtra("token")); String scheme = getIntent().getStringExtra("scheme"); @@ -68,20 +64,22 @@ public class AddNewAccountActivity extends BaseActivity { ArrayAdapter adapterProtocols = new ArrayAdapter<>(ctx, R.layout.list_spinner_items, Protocol.values()); + viewBinding.topAppBar.setNavigationOnClickListener(v -> finish()); + viewBinding.protocolSpinner.setAdapter(adapterProtocols); viewBinding.protocolSpinner.setOnItemClickListener( (parent, view1, position, id) -> spinnerSelectedValue = String.valueOf(parent.getItemAtPosition(position))); - viewBinding.addNewAccount.setOnClickListener( - login -> { - boolean connToInternet = AppUtil.hasNetworkConnection(appCtx); - if (!connToInternet) { - - Toasty.error(ctx, getResources().getString(R.string.checkNetConnection)); - } else { + viewBinding.topAppBar.setOnMenuItemClickListener( + menuItem -> { + int id = menuItem.getItemId(); + if (id == R.id.addAccount) { processLogin(); + return true; + } else { + return super.onOptionsItemSelected(menuItem); } }); } @@ -102,19 +100,26 @@ public class AddNewAccountActivity extends BaseActivity { if (protocol == null) { - Toasty.error(ctx, getResources().getString(R.string.protocolEmptyError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.protocolEmptyError)); return; } if (instanceUrlET.equals("")) { - Toasty.error(ctx, getResources().getString(R.string.emptyFieldURL)); + SnackBar.error( + ctx, findViewById(android.R.id.content), getString(R.string.emptyFieldURL)); return; } if (loginToken.equals("")) { - Toasty.error(ctx, getResources().getString(R.string.loginTokenError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.loginTokenError)); return; } @@ -132,7 +137,8 @@ public class AddNewAccountActivity extends BaseActivity { } catch (Exception e) { - Toasty.error(ctx, getResources().getString(R.string.malformedUrl)); + SnackBar.error( + ctx, findViewById(android.R.id.content), getString(R.string.malformedUrl)); } } @@ -157,8 +163,10 @@ public class AddNewAccountActivity extends BaseActivity { if (!Version.valid(version.getVersion())) { - Toasty.error( - ctx, getResources().getString(R.string.versionUnknown)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.versionUnknown)); return; } @@ -192,12 +200,18 @@ public class AddNewAccountActivity extends BaseActivity { login(instanceUrl, loginToken); } else { - Toasty.warning( + SnackBar.error( ctx, - getResources().getString(R.string.versionUnsupportedNew)); + findViewById(android.R.id.content), + getString(R.string.versionUnsupportedNew)); login(instanceUrl, loginToken); } + } else if (responseVersion.code() == 401) { + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.unauthorizedApiError)); } else if (responseVersion.code() == 403) { login(instanceUrl, loginToken); @@ -213,9 +227,10 @@ public class AddNewAccountActivity extends BaseActivity { public void onFailure( @NonNull Call callVersion, @NonNull Throwable t) { - Log.e("onFailure-versionCheck", t.toString()); - Toasty.error( - ctx, getResources().getString(R.string.genericServerResponseError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.genericServerResponseError)); } }); } @@ -291,21 +306,20 @@ public class AddNewAccountActivity extends BaseActivity { defaultPagingNumber); UserAccount account = userAccountsApi.getAccountById((int) id); AppUtil.switchToAccount(AddNewAccountActivity.this, account); - Toasty.success( + SnackBar.success( ctx, - getResources().getString(R.string.accountAddedMessage)); + findViewById(android.R.id.content), + getString(R.string.accountAddedMessage)); MainActivity.refActivity = true; - finish(); + new Handler().postDelayed(() -> finish(), 3000); } else { UserAccount account = userAccountsApi.getAccountByName(accountName); if (account.isLoggedIn()) { - Toasty.warning( + SnackBar.error( ctx, - getResources() - .getString( - R.string - .accountAlreadyExistsError)); + findViewById(android.R.id.content), + getString(R.string.accountAlreadyExistsError)); AppUtil.switchToAccount(ctx, account); } else { userAccountsApi.updateTokenByAccountName( @@ -315,34 +329,31 @@ public class AddNewAccountActivity extends BaseActivity { AddNewAccountActivity.this, account); } } - finish(); break; case 401: - Toasty.error( + SnackBar.error( ctx, - getResources().getString(R.string.unauthorizedApiError)); + findViewById(android.R.id.content), + getString(R.string.unauthorizedApiError)); break; default: - Toasty.error( + SnackBar.error( ctx, - getResources() - .getString( - R.string.genericApiError, response.code())); + findViewById(android.R.id.content), + getString(R.string.genericApiError, response.code())); } } @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Toasty.error(ctx, getResources().getString(R.string.genericError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.genericError)); } }); } - - private void initCloseListener() { - - onClickListener = view -> finish(); - } } diff --git a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java index 26c2402e..ce8ee3da 100644 --- a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java @@ -94,7 +94,7 @@ public abstract class BaseActivity extends AppCompatActivity { AppUtil.setAppLocale(getResources(), locale); } - Notifications.startWorker(appCtx); + Notifications.startWorker(ctx); } public void onResume() { diff --git a/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java index 683b716d..1fe379f0 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateFileActivity.java @@ -2,15 +2,13 @@ package org.mian.gitnex.activities; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.util.Log; +import android.os.Handler; +import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.InputMethodManager; import android.widget.ArrayAdapter; -import android.widget.TextView; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; @@ -29,8 +27,7 @@ import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.ActivityCreateFileBinding; import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.AppUtil; -import org.mian.gitnex.helpers.NetworkStatusObserver; -import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.contexts.RepositoryContext; import retrofit2.Call; import retrofit2.Callback; @@ -72,16 +69,14 @@ public class CreateFileActivity extends BaseActivity { repository = RepositoryContext.fromIntent(getIntent()); - TextView toolbarTitle = binding.toolbarTitle; + binding.topAppBar.setNavigationOnClickListener(v -> finish()); - binding.newFileName.requestFocus(); + MenuItem create = binding.topAppBar.getMenu().getItem(0); + MenuItem update = binding.topAppBar.getMenu().getItem(1); + MenuItem delete = binding.topAppBar.getMenu().getItem(2); + update.setVisible(false); + delete.setVisible(false); - InputMethodManager inputMethodManager = - (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - assert inputMethodManager != null; - inputMethodManager.showSoftInput(binding.newFileName, InputMethodManager.SHOW_IMPLICIT); - - binding.close.setOnClickListener(view -> finish()); binding.newFileContent.setOnTouchListener( (touchView, motionEvent) -> { touchView.getParent().requestDisallowInterceptTouchEvent(true); @@ -103,12 +98,13 @@ public class CreateFileActivity extends BaseActivity { filePath = getIntent().getStringExtra("filePath"); fileSha = getIntent().getStringExtra("fileSha"); - toolbarTitle.setText(getString(R.string.deleteGenericTitle, filePath)); - - binding.newFileCreate.setText(R.string.deleteFile); + binding.topAppBar.setTitle(getString(R.string.deleteGenericTitle, filePath)); binding.newFileNameLayout.setVisibility(View.GONE); binding.newFileContentLayout.setVisibility(View.GONE); + delete.setVisible(true); + create.setVisible(false); + update.setVisible(false); } if (getIntent().getStringExtra("filePath") != null @@ -118,20 +114,20 @@ public class CreateFileActivity extends BaseActivity { filePath = getIntent().getStringExtra("filePath"); fileSha = getIntent().getStringExtra("fileSha"); - toolbarTitle.setText(getString(R.string.editFileText, filePath)); + binding.topAppBar.setTitle(getString(R.string.editFileText, filePath)); - binding.newFileCreate.setText(R.string.editFile); binding.newFileName.setText(filePath); binding.newFileName.setEnabled(false); binding.newFileName.setFocusable(false); binding.newFileContent.setText(getIntent().getStringExtra("fileContents")); + update.setVisible(true); + create.setVisible(false); + delete.setVisible(false); } getBranches(repository.getOwner(), repository.getName()); - disableProcessButton(); - binding.openCodeEditor.setOnClickListener( v -> launchCodeEditorActivityForResult( @@ -139,13 +135,23 @@ public class CreateFileActivity extends BaseActivity { FilenameUtils.getExtension( String.valueOf(binding.newFileName.getText())))); - NetworkStatusObserver networkStatusObserver = NetworkStatusObserver.getInstance(ctx); - networkStatusObserver.registerNetworkStatusListener( - hasNetworkConnection -> - runOnUiThread( - () -> binding.newFileCreate.setEnabled(hasNetworkConnection))); + binding.topAppBar.setOnMenuItemClickListener( + menuItem -> { + int id = menuItem.getItemId(); - binding.newFileCreate.setOnClickListener(v -> processNewFile()); + if (id == R.id.create) { + processNewFile(); + return true; + } else if (id == R.id.update) { + processNewFile(); + return true; + } else if (id == R.id.delete) { + processNewFile(); + return true; + } else { + return super.onOptionsItemSelected(menuItem); + } + }); } public void launchCodeEditorActivityForResult(String fileContent, String fileExtension) { @@ -175,29 +181,39 @@ public class CreateFileActivity extends BaseActivity { : ""; if (!AppUtil.hasNetworkConnection(appCtx)) { - Toasty.error(ctx, getResources().getString(R.string.checkNetConnection)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.checkNetConnection)); return; } if (((newFileName.isEmpty() || newFileContent.isEmpty()) && fileAction != FILE_ACTION_DELETE) || newFileCommitMessage.isEmpty()) { - Toasty.error(ctx, getString(R.string.newFileRequiredFields)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.newFileRequiredFields)); return; } if (!AppUtil.checkStringsWithDash(newFileBranchName)) { - Toasty.error(ctx, getString(R.string.newFileInvalidBranchName)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.newFileInvalidBranchName)); return; } if (newFileCommitMessage.length() > 255) { - Toasty.warning(ctx, getString(R.string.newFileCommitMessageError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.newFileCommitMessageError)); return; } - disableProcessButton(); - switch (fileAction) { case FILE_ACTION_CREATE: createNewFile( @@ -264,39 +280,40 @@ public class CreateFileActivity extends BaseActivity { switch (response.code()) { case 201: - enableProcessButton(); - Toasty.success(ctx, getString(R.string.newFileSuccessMessage)); + SnackBar.success( + ctx, + findViewById(android.R.id.content), + getString(R.string.newFileSuccessMessage)); Intent result = new Intent(); result.putExtra("fileModified", true); result.putExtra("fileAction", fileAction); setResult(200, result); RepoDetailActivity.updateFABActions = true; - finish(); + new Handler().postDelayed(() -> finish(), 3000); break; case 401: - enableProcessButton(); AlertDialogs.authorizationTokenRevokedDialog(ctx); break; case 404: - enableProcessButton(); - Toasty.warning(ctx, getString(R.string.apiNotFound)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.apiNotFound)); break; default: - enableProcessButton(); - Toasty.error(ctx, getString(R.string.genericError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.genericError)); break; } } @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - enableProcessButton(); - } + public void onFailure(@NonNull Call call, @NonNull Throwable t) {} }); } @@ -332,9 +349,9 @@ public class CreateFileActivity extends BaseActivity { switch (response.code()) { case 200: - enableProcessButton(); - Toasty.info( + SnackBar.success( ctx, + findViewById(android.R.id.content), getString( R.string.deleteFileMessage, repository.getBranchRef())); @@ -342,33 +359,32 @@ public class CreateFileActivity extends BaseActivity { result.putExtra("fileModified", true); result.putExtra("fileAction", fileAction); setResult(200, result); - finish(); + new Handler().postDelayed(() -> finish(), 3000); break; case 401: - enableProcessButton(); AlertDialogs.authorizationTokenRevokedDialog(ctx); break; case 404: - enableProcessButton(); - Toasty.info(ctx, getString(R.string.apiNotFound)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.apiNotFound)); break; default: - enableProcessButton(); - Toasty.info(ctx, getString(R.string.genericError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.genericError)); break; } } @Override public void onFailure( - @NonNull Call call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - enableProcessButton(); - } + @NonNull Call call, @NonNull Throwable t) {} }); } @@ -406,38 +422,39 @@ public class CreateFileActivity extends BaseActivity { switch (response.code()) { case 200: - enableProcessButton(); - Toasty.info(ctx, getString(R.string.editFileMessage, branchName)); + SnackBar.success( + ctx, + findViewById(android.R.id.content), + getString(R.string.editFileMessage, branchName)); Intent result = new Intent(); result.putExtra("fileModified", true); result.putExtra("fileAction", fileAction); setResult(200, result); - finish(); + new Handler().postDelayed(() -> finish(), 3000); break; case 401: - enableProcessButton(); AlertDialogs.authorizationTokenRevokedDialog(ctx); break; case 404: - enableProcessButton(); - Toasty.info(ctx, getString(R.string.apiNotFound)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.apiNotFound)); break; default: - enableProcessButton(); - Toasty.info(ctx, getString(R.string.genericError)); + SnackBar.error( + ctx, + findViewById(android.R.id.content), + getString(R.string.genericError)); break; } } @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - enableProcessButton(); - } + public void onFailure(@NonNull Call call, @NonNull Throwable t) {} }); } @@ -468,27 +485,14 @@ public class CreateFileActivity extends BaseActivity { binding.newFileBranches.setAdapter(adapter); binding.newFileBranches.setText(repository.getBranchRef(), false); - - enableProcessButton(); } } @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - } + public void onFailure(@NonNull Call> call, @NonNull Throwable t) {} }); } - private void disableProcessButton() { - binding.newFileCreate.setEnabled(false); - } - - private void enableProcessButton() { - binding.newFileCreate.setEnabled(true); - } - @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/org/mian/gitnex/activities/CreateIssueActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateIssueActivity.java index 95171c6b..5fa8727f 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateIssueActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateIssueActivity.java @@ -1,27 +1,37 @@ package org.mian.gitnex.activities; import android.annotation.SuppressLint; -import android.app.DatePickerDialog; -import android.content.Context; +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.InputMethodManager; import android.widget.ArrayAdapter; import android.widget.TextView; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.datepicker.MaterialDatePicker; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.vdurmont.emoji.EmojiParser; +import java.io.File; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Objects; +import java.util.TimeZone; +import okhttp3.MediaType; +import okhttp3.RequestBody; +import org.gitnex.tea4j.v2.models.Attachment; import org.gitnex.tea4j.v2.models.CreateIssueOption; import org.gitnex.tea4j.v2.models.Issue; import org.gitnex.tea4j.v2.models.Label; @@ -31,17 +41,20 @@ import org.mian.gitnex.R; import org.mian.gitnex.actions.AssigneesActions; import org.mian.gitnex.actions.LabelsActions; import org.mian.gitnex.adapters.AssigneesListAdapter; +import org.mian.gitnex.adapters.AttachmentsAdapter; import org.mian.gitnex.adapters.LabelsListAdapter; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.ActivityCreateIssueBinding; +import org.mian.gitnex.databinding.BottomSheetAttachmentsBinding; import org.mian.gitnex.databinding.CustomAssigneesSelectionDialogBinding; import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding; import org.mian.gitnex.fragments.IssuesFragment; import org.mian.gitnex.helpers.AlertDialogs; -import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Markdown; -import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.attachments.AttachmentUtils; +import org.mian.gitnex.helpers.attachments.AttachmentsModel; import org.mian.gitnex.helpers.contexts.RepositoryContext; import retrofit2.Call; import retrofit2.Callback; @@ -50,17 +63,15 @@ import retrofit2.Callback; * @author M M Arif */ public class CreateIssueActivity extends BaseActivity - implements View.OnClickListener, - LabelsListAdapter.LabelsListAdapterListener, - AssigneesListAdapter.AssigneesListAdapterListener { + implements LabelsListAdapter.LabelsListAdapterListener, + AssigneesListAdapter.AssigneesListAdapterListener, + AttachmentsAdapter.AttachmentsReceiverListener { private final List