diff --git a/.drone.yml b/.drone.yml index c3b82520..e00ad6cd 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,8 +15,8 @@ steps: image: zosiab/eclint:latest depends_on: [ clone ] commands: - - git pull origin master - - eclint check $(git diff --name-only origin/master) + - git pull origin main + - eclint check $(git diff --name-only origin/main) # This may be used in the future, because it makes of intellij's native code inspection/formatting capabilities. # Additional information: https://www.jetbrains.com/help/idea/command-line-formatter.html @@ -54,7 +54,7 @@ trigger: event: - push branch: - - master + - main --- kind: pipeline @@ -101,4 +101,4 @@ trigger: event: - push branch: - - master + - main diff --git a/.gitea/issue_template.md b/.gitea/issue_template.md index d1307a05..727faec8 100644 --- a/.gitea/issue_template.md +++ b/.gitea/issue_template.md @@ -31,7 +31,7 @@

-- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/master/CONTRIBUTING.md). +- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md).
#### Thank you for your time. \ No newline at end of file diff --git a/.gitea/pull_request_template.md b/.gitea/pull_request_template.md index dd43dcc3..b9a0ce9a 100644 --- a/.gitea/pull_request_template.md +++ b/.gitea/pull_request_template.md @@ -2,8 +2,8 @@

- + -- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/master/CONTRIBUTING.md). +- [ ] I carefully read the [contribution guidelines](https://codeberg.org/GitNex/GitNex/src/branch/main/CONTRIBUTING.md). - [ ] I'm following the code standards as defined [here](https://codeberg.org/gitnex/GitNex/wiki/Code-Standards). -- [ ] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/master/LICENSE). \ No newline at end of file +- [ ] By submitting this pull request, I permit GitNex to license my work under the [GNU General Public License v3](https://codeberg.org/GitNex/GitNex/src/branch/main/LICENSE). \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 069faff3..391c830d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,10 +4,10 @@ stages: - publish on_setup: - image: tutum/curl + image: curlimages/curl:7.77.0 stage: .pre only: - - master + - main - tags variables: INSTANCE: "https://codeberg.org" @@ -20,7 +20,7 @@ build: image: nextcloudci/android:android-54 stage: build only: - - master + - main - tags script: - ./gradlew assembleFreeRelease @@ -33,7 +33,7 @@ sign: image: nextcloudci/android:android-54 stage: sign only: - - master + - main - tags variables: OUTPUT: "signed.apk" @@ -47,10 +47,10 @@ sign: expire_in: 15 minutes latest: - image: tutum/curl + image: curlimages/curl:7.77.0 stage: publish only: - - master + - main - tags variables: WEBDAV_USERNAME: "GitNexBot" @@ -60,7 +60,7 @@ latest: - curl -T "$PLUGIN_FILE" -u "$WEBDAV_USERNAME":"$WEBDAV_PASSWORD" "$PLUGIN_DESTINATION" release: - image: tutum/curl + image: curlimages/curl:7.77.0 stage: publish only: - tags @@ -72,10 +72,10 @@ release: - curl -T "$PLUGIN_FILE" -u "$WEBDAV_USERNAME":"$WEBDAV_PASSWORD" 'https://cloud.swatian.com/remote.php/dav/files/GitNexBot/gitnex/releases/'"$CI_COMMIT_REF_NAME"'.apk' on_success: - image: tutum/curl + image: curlimages/curl:7.77.0 stage: .post only: - - master + - main - tags variables: INSTANCE: "https://codeberg.org" @@ -86,10 +86,10 @@ on_success: when: on_success on_failure: - image: tutum/curl + image: curlimages/curl:7.77.0 stage: .post only: - - master + - main - tags variables: INSTANCE: "https://codeberg.org" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43385f65..de3a1a9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ It is documented in the Wiki: [Code-Standards](https://codeberg.org/gitnex/GitNe 2. Clone the forked repository from your namespace to your local machine. 3. Create a new branch and work on your feature, enhancement or patch. 4. Push your commits to your forked version. -5. You can now create a PR using the web interface against **master** branch. +5. You can now create a PR using the web interface against **main** branch. For more information, click [here](http://makeapullrequest.com/). diff --git a/README.md b/README.md index b0b4de81..a71f4ef4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Pipeline status](https://img.shields.io/gitlab/pipeline/opyale/gitnex/master)](https://gitlab.com/opyale/gitnex/-/pipelines) [![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://codeberg.org/api/v1/repos/gitnex/GitNex/releases&query=$[0].tag_name)](https://codeberg.org/gitnex/GitNex/releases) [![Crowdin](https://badges.crowdin.net/gitnex/localized.svg)](https://crowdin.com/project/gitnex) [![Join the Discord chat at https://discord.gg/FbSS4rf](https://img.shields.io/discord/632219664587685908.svg)](https://discord.gg/FbSS4rf) +[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Pipeline status](https://img.shields.io/gitlab/pipeline/opyale/gitnex/main)](https://gitlab.com/opyale/gitnex/-/pipelines) [![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://codeberg.org/api/v1/repos/gitnex/GitNex/releases&query=$[0].tag_name)](https://codeberg.org/gitnex/GitNex/releases) [![Crowdin](https://badges.crowdin.net/gitnex/localized.svg)](https://crowdin.com/project/gitnex) [![Join the Discord chat at https://discord.gg/FbSS4rf](https://img.shields.io/discord/632219664587685908.svg)](https://discord.gg/FbSS4rf) [Become a Patroen](https://www.patreon.com/mmarif) @@ -11,7 +11,7 @@ GitNex is licensed under GPLv3 License. See the LICENSE file for the full licens ## Downloads [Get it on F-droid](https://f-droid.org/en/packages/org.mian.gitnex/) [Get it on Google Play](https://play.google.com/store/apps/details?id=org.mian.gitnex.pro) -[Download builds and releases](https://cloud.swatian.com/s/DN7E5xxtaw4fRbE) +[Download builds and releases](https://cloud.swatian.com/s/DN7E5xxtaw4fRbE) ## Note about Gitea version Please make sure that you are on latest stable release or later for better app experience. @@ -37,7 +37,7 @@ Option 2 - Open terminal(Linux) and cd to the project dir. Run `./gradlew assemb - [MANY MORE](https://codeberg.org/gitnex/GitNex/wiki/Features) ## Contributing -[CONTRIBUTING](https://codeberg.org/gitnex/GitNex/src/branch/master/CONTRIBUTING.md) +[CONTRIBUTING](https://codeberg.org/gitnex/GitNex/src/branch/main/CONTRIBUTING.md) ## Translation Help us translate GitNex to your native language. @@ -48,9 +48,9 @@ We use [Crowdin](https://crowdin.com/project/gitnex) for translation. If your la ## Screenshots: -001.png | 002.png | 003.png | 004.png +001.png | 002.png | 003.png | 004.png ---|---|---|--- -005.png | 006.png | 007.png | 008.png +005.png | 006.png | 007.png | 008.png ## Links [Website](https://gitnex.com) diff --git a/app/build.gradle b/app/build.gradle index 3738d3cb..578f24e6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,12 +56,13 @@ configurations { dependencies { def lifecycle_version = '2.3.1' def markwon_version = '4.6.2' - def work_version = "2.5.0" + def work_version = "2.7.0-alpha04" def acra = "5.7.0" implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'androidx.appcompat:appcompat:1.3.0-rc01' + implementation 'androidx.appcompat:appcompat:1.4.0-alpha02' implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" @@ -103,14 +104,14 @@ dependencies { implementation "ch.acra:acra-mail:$acra" implementation "ch.acra:acra-limiter:$acra" implementation "ch.acra:acra-notification:$acra" - implementation 'androidx.room:room-runtime:2.2.6' - annotationProcessor 'androidx.room:room-compiler:2.2.6' + implementation 'androidx.room:room-runtime:2.3.0' + annotationProcessor 'androidx.room:room-compiler:2.3.0' implementation "androidx.work:work-runtime:$work_version" implementation "io.mikael:urlbuilder:2.0.9" implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2" - implementation "org.codeberg.gitnex:tea4j:1.0.5" + implementation "org.codeberg.gitnex:tea4j:1.0.16" coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" implementation 'androidx.biometric:biometric:1.1.0' - implementation 'com.github.chrisvest:stormpot:2.4.1' + implementation 'com.github.chrisvest:stormpot:2.4.2' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0eab7a1f..1cff1ec6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,7 +51,7 @@ android:name=".activities.CreateNewUserActivity" android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" /> call = RetrofitClient + .getApiInterface(context) + .deleteBranch(Authorization.get(context), repoOwner, repoName, headBranch); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if(response.code() == 204) { + + if(showToasts) Toasty.success(context, context.getString(R.string.deleteBranchSuccess)); + } + else if(response.code() == 401) { + + AlertDialogs + .authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), context.getResources().getString(R.string.alertDialogTokenRevokedMessage), context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton)); + } + else if(response.code() == 403) { + + if(showToasts) Toasty.error(context, context.getString(R.string.authorizeError)); + } + else if(response.code() == 404) { + + if(showToasts) Toasty.warning(context, context.getString(R.string.deleteBranchErrorNotFound)); + } + else { + + if(showToasts) Toasty.error(context, context.getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + if(showToasts) Toasty.error(context, context.getString(R.string.deleteBranchError)); + } + + }); + } + +} 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 8724df32..196f8904 100644 --- a/app/src/main/java/org/mian/gitnex/activities/AddNewAccountActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/AddNewAccountActivity.java @@ -49,6 +49,7 @@ public class AddNewAccountActivity extends BaseActivity { initCloseListener(); viewBinding.close.setOnClickListener(onClickListener); + viewBinding.instanceUrl.setText(getIntent().getStringExtra("instanceUrl")); ArrayAdapter adapterProtocols = new ArrayAdapter<>(ctx, R.layout.list_spinner_items, Protocol.values()); @@ -115,7 +116,7 @@ public class AddNewAccountActivity extends BaseActivity { private void versionCheck(final String instanceUrl, final String loginToken) { Call callVersion; - callVersion = RetrofitClient.getApiInterface(ctx).getGiteaVersionWithToken("token " + loginToken); + callVersion = RetrofitClient.getApiInterface(ctx, instanceUrl).getGiteaVersionWithToken("token " + loginToken); callVersion.enqueue(new Callback() { @Override 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 c5642a6c..ba0c36dc 100644 --- a/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/BaseActivity.java @@ -8,6 +8,7 @@ import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.notifications.Notifications; +import java.util.Locale; /** * Author M M Arif @@ -37,7 +38,7 @@ public abstract class BaseActivity extends AppCompatActivity { break; case 2: - if(TimeHelper.timeBetweenHours(18, 6)) { // 6pm to 6am + if(TimeHelper.timeBetweenHours(tinyDB.getInt("darkThemeTimeHour"), tinyDB.getInt("lightThemeTimeHour"), tinyDB.getInt("darkThemeTimeMinute"), tinyDB.getInt("lightThemeTimeMinute"))) { tinyDB.putString("currentTheme", "dark"); setTheme(R.style.AppTheme); @@ -54,7 +55,7 @@ public abstract class BaseActivity extends AppCompatActivity { setTheme(R.style.AppThemeRetro); break; case 4: - if(TimeHelper.timeBetweenHours(18, 6)) { // 6pm to 6am + if(TimeHelper.timeBetweenHours(tinyDB.getInt("darkThemeTimeHour"), tinyDB.getInt("lightThemeTimeHour"), tinyDB.getInt("darkThemeTimeMinute"), tinyDB.getInt("lightThemeTimeMinute"))) { tinyDB.putString("currentTheme", "dark"); setTheme(R.style.AppTheme); @@ -77,7 +78,13 @@ public abstract class BaseActivity extends AppCompatActivity { } - AppUtil.setAppLocale(getResources(), tinyDB.getString("locale")); + String locale = tinyDB.getString("locale"); + if (locale.isEmpty()) { + AppUtil.setAppLocale(getResources(), Locale.getDefault().getLanguage()); + } + else { + AppUtil.setAppLocale(getResources(), locale); + } Notifications.startWorker(appCtx); } diff --git a/app/src/main/java/org/mian/gitnex/activities/CreateRepoActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateRepoActivity.java index a38a2e02..36eb7f43 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateRepoActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateRepoActivity.java @@ -215,7 +215,7 @@ public class CreateRepoActivity extends BaseActivity { Call> call = RetrofitClient .getApiInterface(ctx) - .getOrgOwners(instanceToken); + .getOrgOwners(instanceToken, 1, 50); call.enqueue(new Callback>() { diff --git a/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java b/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java index 8e0a85bd..4bf83726 100644 --- a/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java @@ -9,8 +9,11 @@ import android.util.Log; import android.view.View; import androidx.annotation.NonNull; import org.apache.commons.lang3.StringUtils; +import org.gitnex.tea4j.models.Files; +import org.gitnex.tea4j.models.Organization; import org.gitnex.tea4j.models.PullRequests; import org.gitnex.tea4j.models.UserRepositories; +import org.jetbrains.annotations.NotNull; import org.mian.gitnex.R; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.database.api.BaseApi; @@ -20,13 +23,16 @@ import org.mian.gitnex.database.models.Repository; import org.mian.gitnex.database.models.UserAccount; import org.mian.gitnex.databinding.ActivityDeeplinksBinding; import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.UrlHelper; import java.net.URI; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import io.mikael.urlbuilder.UrlBuilder; import retrofit2.Call; import retrofit2.Callback; +import retrofit2.Response; /** * Author M M Arif @@ -42,6 +48,8 @@ public class DeepLinksActivity extends BaseActivity { private Intent mainIntent; private Intent issueIntent; private Intent repoIntent; + private Intent orgIntent; + private Intent userIntent; @Override public void onCreate(Bundle savedInstanceState) { @@ -54,6 +62,9 @@ public class DeepLinksActivity extends BaseActivity { mainIntent = new Intent(ctx, MainActivity.class); issueIntent = new Intent(ctx, IssueDetailActivity.class); repoIntent = new Intent(ctx, RepoDetailActivity.class); + orgIntent = new Intent(ctx, OrganizationDetailActivity.class); + // TODO: enable if UserProfile Activity exist + //userIntent = new Intent(ctx, ProfileActivity.class) Intent intent = getIntent(); Uri data = intent.getData(); @@ -61,9 +72,10 @@ public class DeepLinksActivity extends BaseActivity { // check for login if(!tinyDB.getBoolean("loggedInMode")) { - + Intent loginIntent = new Intent(ctx, LoginActivity.class); + loginIntent.putExtra("instanceUrl", data.getHost()); + ctx.startActivity(loginIntent); finish(); - ctx.startActivity(new Intent(ctx, LoginActivity.class)); } // check for the links(URI) to be in the db @@ -89,25 +101,83 @@ public class DeepLinksActivity extends BaseActivity { if(accountFound) { - // redirect to proper fragment/activity, If no action is there, show options where user to want to go like repos, profile, notifications etc - if(data.getPathSegments().size() > 0) { - - viewBinding.progressBar.setVisibility(View.GONE); - String[] restOfUrl = Objects.requireNonNull(data.getPath()).split("/"); - - if(data.getPathSegments().contains("issues")) { // issue + // redirect to proper fragment/activity, if no action is there, show options where user to want to go like repos, profile, notifications etc + if(data.getPathSegments().size() == 1) { + if(data.getLastPathSegment().equals("notifications")) { // notifications + mainIntent.putExtra("launchFragmentByLinkHandler", "notification"); + ctx.startActivity(mainIntent); + finish(); + } + else if(data.getLastPathSegment().equals("explore")) { // explore + mainIntent.putExtra("launchFragmentByLinkHandler", "explore"); + ctx.startActivity(mainIntent); + finish(); + } + else if(data.getLastPathSegment().equals(tinyDB.getString("userLogin"))) { // your user profile + mainIntent.putExtra("launchFragmentByLinkHandler", "profile"); + ctx.startActivity(mainIntent); + finish(); + } + else if(data.getLastPathSegment().equals("admin")) { + mainIntent.putExtra("launchFragmentByLinkHandler", "admin"); + ctx.startActivity(mainIntent); + finish(); + } + else { + new Handler(Looper.getMainLooper()).postDelayed(() -> + getUserOrOrg(currentInstance, instanceToken, data.getLastPathSegment()), 500); + } + } + else if(data.getPathSegments().size() == 2) { + if(data.getPathSegments().get(0).equals("explore")) { // specific explore tab + if(data.getPathSegments().get(1).equals("organizations")) { // orgs + mainIntent.putExtra("exploreOrgs", true); + } + mainIntent.putExtra("launchFragmentByLinkHandler", "explore"); + ctx.startActivity(mainIntent); + finish(); + } + else if(data.getPathSegments().get(0).equals("user") && data.getPathSegments().get(1).equals("login")) { // open login + Intent loginIntent = new Intent(ctx, AddNewAccountActivity.class); + loginIntent.putExtra("instanceUrl", data.getHost()); + loginIntent.putExtra("instanceProtocol", data.getScheme()); + ctx.startActivity(loginIntent); + finish(); + } + else if(data.getPathSegments().get(0).equals("admin")) { + mainIntent.putExtra("launchFragmentByLinkHandler", "admin"); + mainIntent.putExtra("giteaAdminAction", data.getLastPathSegment()); + ctx.startActivity(mainIntent); + finish(); + } + else if(!data.getPathSegments().get(0).equals("") & !data.getLastPathSegment().equals("")) { // go to repo + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getLastPathSegment(), "repo"), 500); + } + else { // no action, show options + showNoActionButtons(); + } + } + else if(data.getPathSegments().size() >= 3) { + if(data.getPathSegments().get(2).equals("issues")) { // issue if(!Objects.requireNonNull(data.getLastPathSegment()).contains("issues") & StringUtils.isNumeric(data.getLastPathSegment())) { issueIntent.putExtra("issueNumber", data.getLastPathSegment()); + issueIntent.putExtra("openedFromLink", "true"); + + String[] urlSplitted = data.toString().split("#"); + if (urlSplitted.length == 2) { + issueIntent.putExtra("issueComment", urlSplitted[1]); + } tinyDB.putString("issueNumber", data.getLastPathSegment()); tinyDB.putString("issueType", "Issue"); - tinyDB.putString("repoFullName", restOfUrl[restOfUrl.length - 4] + "/" + restOfUrl[restOfUrl.length - 3]); + tinyDB.putString("repoFullName", data.getPathSegments().get(0) + "/" + data.getPathSegments().get(1)); - final String repoOwner = restOfUrl[restOfUrl.length - 4]; - final String repoName = restOfUrl[restOfUrl.length - 3]; + final String repoOwner = data.getPathSegments().get(0); + final String repoName = data.getPathSegments().get(1); int currentActiveAccountId = tinyDB.getInt("currentActiveAccountId"); RepositoriesApi repositoryData = BaseApi.getInstance(ctx, RepositoriesApi.class); @@ -129,125 +199,121 @@ public class DeepLinksActivity extends BaseActivity { finish(); } else if(Objects.requireNonNull(data.getLastPathSegment()).contains("issues")) { - - new Handler(Looper.getMainLooper()).postDelayed(() -> { - - goToRepoSection(currentInstance, instanceToken, restOfUrl[restOfUrl.length - 3], restOfUrl[restOfUrl.length - 2], "issue"); - }, 500); + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "issue"), 500); + } + else if(data.getLastPathSegment().equals("new")) { + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "issueNew"), 500); } else { - ctx.startActivity(mainIntent); finish(); } } - else if(data.getPathSegments().contains("pulls")) { // pr + else if(data.getPathSegments().get(2).equals("pulls")) { // pr if(!Objects.requireNonNull(data.getLastPathSegment()).contains("pulls") & StringUtils.isNumeric(data.getLastPathSegment())) { new Handler(Looper.getMainLooper()).postDelayed(() -> { - getPullRequest(currentInstance, instanceToken, restOfUrl[restOfUrl.length - 4], restOfUrl[restOfUrl.length - 3], Integer.parseInt(data.getLastPathSegment())); + String[] urlSplitted = data.toString().split("#"); + if (urlSplitted.length == 2) { + issueIntent.putExtra("issueComment", urlSplitted[1]); + } + + getPullRequest(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), Integer.parseInt(data.getLastPathSegment())); }, 500); } else if(Objects.requireNonNull(data.getLastPathSegment()).contains("pulls")) { - + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "pull"), 500); + } + else if(data.getLastPathSegment().equals("files")) { // pr diff new Handler(Looper.getMainLooper()).postDelayed(() -> { - - goToRepoSection(currentInstance, instanceToken, restOfUrl[restOfUrl.length - 3], restOfUrl[restOfUrl.length - 2], "pull"); + issueIntent.putExtra("openPrDiff", "true"); + getPullRequest(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), Integer.parseInt(data.getPathSegments().get(3))); }, 500); } else { - ctx.startActivity(mainIntent); finish(); } } - else if(data.getPathSegments().contains("commit")) { // commits (no API yet to properly implement) - new Handler(Looper.getMainLooper()).postDelayed(() -> { - - goToRepoSection(currentInstance, instanceToken, restOfUrl[restOfUrl.length - 4], restOfUrl[restOfUrl.length - 3], "pull"); - }, 500); + else if(data.getPathSegments().get(2).equals("compare")) { // new pull request + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "pullNew"), 500); } - else if(!restOfUrl[restOfUrl.length - 2].equals("") & !restOfUrl[restOfUrl.length - 1].equals("")) { // go to repo - - new Handler(Looper.getMainLooper()).postDelayed(() -> { - - goToRepoSection(currentInstance, instanceToken, restOfUrl[restOfUrl.length - 2], restOfUrl[restOfUrl.length - 1], "repo"); - }, 500); + else if(data.getPathSegments().get(2).equals("commit")) { // commits (no API yet to properly implement) + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "pull"), 500); + } + else if(data.getPathSegments().get(2).equals("commits")) { // commits list + String branch = data.getLastPathSegment(); + repoIntent.putExtra("branchName", branch); + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "commitsList"), 500); + } + else if(data.getPathSegments().get(2).equals("milestones") && data.getLastPathSegment().equals("new")) { // new milestone + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "milestonesNew"), 500); + } + else if(data.getPathSegments().get(2).equals("milestones")) { // milestones + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "milestones"), 500); + } + else if(data.getPathSegments().get(2).equals("milestone")) { // milestone + repoIntent.putExtra("milestoneId", data.getLastPathSegment()); + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "milestones"), 500); + } + else if(data.getPathSegments().get(2).equals("releases") && data.getLastPathSegment().equals("new")) { // new release + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "newRelease"), 500); + } + else if(data.getPathSegments().get(2).equals("releases") && data.getPathSegments().get(3).equals("tag") && data.getPathSegments().size() == 5) { // release + repoIntent.putExtra("releaseTagName", data.getLastPathSegment()); + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "releases"), 500); + } + else if(data.getPathSegments().get(2).equals("releases")) { // releases + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "releases"), 500); + } + else if(data.getPathSegments().get(2).equals("labels")) { // labels + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "labels"), 500); + } + else if(data.getPathSegments().get(2).equals("settings")) { // repo settings + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "settings"), 500); + } + else if(data.getLastPathSegment().equals("branches")) { // branches list + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "branchesList"), 500); + } + else if(data.getPathSegments().size() == 5 && data.getPathSegments().get(2).equals("src") && data.getPathSegments().get(3).equals("branch")) { // branch + repoIntent.putExtra("selectedBranch", data.getLastPathSegment()); + new Handler(Looper.getMainLooper()).postDelayed(() -> + goToRepoSection(currentInstance, instanceToken, data.getPathSegments().get(0), data.getPathSegments().get(1), "branch"), 500); + } + else if(data.getPathSegments().get(2).equals("src") && data.getPathSegments().get(3).equals("branch")) { // file/dir + StringBuilder filePath = new StringBuilder(); + ArrayList segments = new ArrayList<>(data.getPathSegments()); + segments.subList(0, 5).clear(); + for (String item : segments) { + filePath.append(item); + filePath.append("/"); + } + filePath.deleteCharAt(filePath.toString().length() - 1); + new Handler(Looper.getMainLooper()).postDelayed(() -> + getFile(currentInstance, instanceToken, data.getPathSegments().get(0), + data.getPathSegments().get(1), filePath.toString(), data.getPathSegments().get(4)), 500); } else { // no action, show options - - if(tinyDB.getInt("defaultScreenId") == 1) { // repos - - mainIntent.putExtra("launchFragmentByLinkHandler", "repos"); - ctx.startActivity(mainIntent); - finish(); - } - else if(tinyDB.getInt("defaultScreenId") == 2) { // org - - mainIntent.putExtra("launchFragmentByLinkHandler", "org"); - ctx.startActivity(mainIntent); - finish(); - } - else if(tinyDB.getInt("defaultScreenId") == 3) { // notifications - - mainIntent.putExtra("launchFragmentByLinkHandler", "notification"); - ctx.startActivity(mainIntent); - finish(); - } - else if(tinyDB.getInt("defaultScreenId") == 4) { // explore - - mainIntent.putExtra("launchFragmentByLinkHandler", "explore"); - ctx.startActivity(mainIntent); - finish(); - } - else if(tinyDB.getInt("defaultScreenId") == 0) { // show options - - viewBinding.noActionFrame.setVisibility(View.VISIBLE); - viewBinding.addNewAccountFrame.setVisibility(View.GONE); - - viewBinding.repository.setOnClickListener(repository -> { - - tinyDB.putInt("defaultScreenId", 1); - mainIntent.putExtra("launchFragmentByLinkHandler", "repos"); - ctx.startActivity(mainIntent); - finish(); - }); - - viewBinding.organization.setOnClickListener(organization -> { - - tinyDB.putInt("defaultScreenId", 2); - mainIntent.putExtra("launchFragmentByLinkHandler", "org"); - ctx.startActivity(mainIntent); - finish(); - }); - - viewBinding.notification.setOnClickListener(notification -> { - - tinyDB.putInt("defaultScreenId", 3); - mainIntent.putExtra("launchFragmentByLinkHandler", "notification"); - ctx.startActivity(mainIntent); - finish(); - }); - - viewBinding.explore.setOnClickListener(explore -> { - - tinyDB.putInt("defaultScreenId", 4); - mainIntent.putExtra("launchFragmentByLinkHandler", "explore"); - ctx.startActivity(mainIntent); - finish(); - }); - - viewBinding.launchApp2.setOnClickListener(launchApp2 -> { - - tinyDB.putInt("defaultScreenId", 0); - ctx.startActivity(mainIntent); - finish(); - }); - } + showNoActionButtons(); } } else { @@ -266,6 +332,7 @@ public class DeepLinksActivity extends BaseActivity { viewBinding.addNewAccount.setOnClickListener(addNewAccount -> { Intent accountIntent = new Intent(ctx, AddNewAccountActivity.class); + accountIntent.putExtra("instanceUrl", data.getHost()); startActivity(accountIntent); finish(); }); @@ -316,6 +383,7 @@ public class DeepLinksActivity extends BaseActivity { issueIntent.putExtra("issueNumber", index); issueIntent.putExtra("prMergeable", prInfo.isMergeable()); + issueIntent.putExtra("openedFromLink", "true"); if(prInfo.getHead() != null) { @@ -450,4 +518,184 @@ public class DeepLinksActivity extends BaseActivity { } }); } + + private void getUserOrOrg(String url, String instanceToken, String userOrgName) { + Call call = RetrofitClient.getApiInterface(ctx, url).getOrganization(instanceToken, userOrgName); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if(response.code() == 404) { // org doesn't exist or it's a user user + Log.d("getUserOrOrg-404", String.valueOf(response.code())); + getUser(url, instanceToken, userOrgName); + } + else if(response.code() == 200) { // org + assert response.body() != null; + orgIntent.putExtra("orgName", response.body().getUsername()); + + + TinyDB tinyDb = TinyDB.getInstance(ctx); + tinyDb.putString("orgName", response.body().getUsername()); + tinyDb.putString("organizationId", String.valueOf(response.body().getId())); + tinyDb.putBoolean("organizationAction", true); + ctx.startActivity(orgIntent); + finish(); + } + else { + Log.e("getUserOrOrg-code", String.valueOf(response.code())); + ctx.startActivity(mainIntent); + finish(); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull Throwable t) { + Log.e("onFailure-getUserOrOrg", t.toString()); + } + }); + } + + private void getUser(String url, String instanceToken, String userName) { + // TODO: enable if UserProfile Activity exist + showNoActionButtons(); + /*Call call = RetrofitClient.getApiInterface(ctx, url).getUserProfile(instanceToken, userName); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if(response.code() == 200) { + assert response.body() != null; + userIntent.putExtra("username", response.body().getLogin()); + ctx.startActivity(userIntent); + finish(); + } + else { + Log.e("getUser-code", String.valueOf(response.code())); + ctx.startActivity(mainIntent); + finish(); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull Throwable t) { + Log.e("onFailure-getUser", t.toString()); + ctx.startActivity(mainIntent); + finish(); + } + });*/ + } + + private void getFile(String url, String instanceToken, String owner, String repo, String filePath, String branch) { + Call call = RetrofitClient.getApiInterface(ctx, url).getSingleFileContents(instanceToken, owner, repo, filePath, branch); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if(response.code() == 200) { + // check if file and open file/dir + Files file = response.body(); + assert file != null; + if(file.getType().equals("file")) { + repoIntent.putExtra("file", file); + repoIntent.putExtra("branch", branch); + goToRepoSection(url, instanceToken, owner, repo, "file"); + } + } + else { + Log.e("getFile-onFailure", String.valueOf(response.code())); + ctx.startActivity(mainIntent); + finish(); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull Throwable t) { + Log.e("getFile-onFailure", t.toString()); + // maybe it's a directory + getDir(url, instanceToken, owner, repo, filePath, branch); + } + }); + } + + private void getDir(String url, String instanceToken, String owner, String repo, String filePath, String branch) { + repoIntent.putExtra("branch", branch); + repoIntent.putExtra("dir", filePath); + goToRepoSection(url, instanceToken, owner, repo, "dir"); + } + + private void showNoActionButtons() { + viewBinding.progressBar.setVisibility(View.GONE); + + if(tinyDB.getInt("defaultScreenId") == 1) { // repos + + mainIntent.putExtra("launchFragmentByLinkHandler", "repos"); + ctx.startActivity(mainIntent); + finish(); + } + else if(tinyDB.getInt("defaultScreenId") == 2) { // org + + mainIntent.putExtra("launchFragmentByLinkHandler", "org"); + ctx.startActivity(mainIntent); + finish(); + } + else if(tinyDB.getInt("defaultScreenId") == 3) { // notifications + + mainIntent.putExtra("launchFragmentByLinkHandler", "notification"); + ctx.startActivity(mainIntent); + finish(); + } + else if(tinyDB.getInt("defaultScreenId") == 4) { // explore + + mainIntent.putExtra("launchFragmentByLinkHandler", "explore"); + ctx.startActivity(mainIntent); + finish(); + } + else if(tinyDB.getInt("defaultScreenId") == 0) { // show options + + viewBinding.noActionFrame.setVisibility(View.VISIBLE); + viewBinding.addNewAccountFrame.setVisibility(View.GONE); + + viewBinding.repository.setOnClickListener(repository -> { + + tinyDB.putInt("defaultScreenId", 1); + mainIntent.putExtra("launchFragmentByLinkHandler", "repos"); + ctx.startActivity(mainIntent); + finish(); + }); + + viewBinding.organization.setOnClickListener(organization -> { + + tinyDB.putInt("defaultScreenId", 2); + mainIntent.putExtra("launchFragmentByLinkHandler", "org"); + ctx.startActivity(mainIntent); + finish(); + }); + + viewBinding.notification.setOnClickListener(notification -> { + + tinyDB.putInt("defaultScreenId", 3); + mainIntent.putExtra("launchFragmentByLinkHandler", "notification"); + ctx.startActivity(mainIntent); + finish(); + }); + + viewBinding.explore.setOnClickListener(explore -> { + + tinyDB.putInt("defaultScreenId", 4); + mainIntent.putExtra("launchFragmentByLinkHandler", "explore"); + ctx.startActivity(mainIntent); + finish(); + }); + + viewBinding.launchApp2.setOnClickListener(launchApp2 -> { + + tinyDB.putInt("defaultScreenId", 0); + ctx.startActivity(mainIntent); + finish(); + }); + } + } } diff --git a/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java b/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java index 79182f8b..313cf613 100644 --- a/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java @@ -148,10 +148,18 @@ public class FileViewActivity extends BaseActivity implements BottomSheetFileVie runOnUiThread(() -> { binding.photoView.setVisibility(View.GONE); - binding.markdownFrame.setVisibility(View.GONE); - binding.contents.setVisibility(View.VISIBLE); binding.contents.setContent(text, fileExtension); + + if(tinyDB.getBoolean("enableMarkdownInFileView")) { + Markdown.render(ctx, EmojiParser.parseToUnicode(text), binding.markdown); + + binding.contents.setVisibility(View.GONE); + binding.markdownFrame.setVisibility(View.VISIBLE); + } else { + binding.markdownFrame.setVisibility(View.GONE); + binding.contents.setVisibility(View.VISIBLE); + } }); break; diff --git a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java index 3760ab8a..137a9367 100644 --- a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java @@ -1,6 +1,7 @@ package org.mian.gitnex.activities; import android.app.Dialog; +import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; @@ -196,6 +197,10 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt getSingleIssue(repoOwner, repoName, issueIndex); fetchDataAsync(repoOwner, repoName, issueIndex); + if(getIntent().getStringExtra("openPrDiff") != null && getIntent().getStringExtra("openPrDiff").equals("true")) { + startActivity(new Intent(ctx, FileDiffActivity.class)); + } + } @Override @@ -434,6 +439,11 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt if(id == android.R.id.home) { + if(getIntent().getStringExtra("openedFromLink") != null && getIntent().getStringExtra("openedFromLink").equals("true")) { + Intent intent = new Intent(ctx, RepoDetailActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + } finish(); return true; } @@ -569,7 +579,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt } TinyDB tinyDb = TinyDB.getInstance(appCtx); - final String locale = tinyDb.getString("locale"); + final Locale locale = getResources().getConfiguration().locale; final String timeFormat = tinyDb.getString("dateFormat"); tinyDb.putString("issueState", singleIssue.getState()); tinyDb.putString("issueTitle", singleIssue.getTitle()); @@ -582,6 +592,17 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + EmojiParser.parseToUnicode(singleIssue.getTitle()), HtmlCompat.FROM_HTML_MODE_LEGACY)); String cleanIssueDescription = singleIssue.getBody().trim(); + viewBinding.assigneeAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(ctx, ProfileActivity.class); + intent.putExtra("username", singleIssue.getUser().getLogin()); + ctx.startActivity(intent); + }); + + viewBinding.assigneeAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(ctx, singleIssue.getUser().getLogin(), ctx.getString(R.string.copyLoginIdToClipBoard, singleIssue.getUser().getLogin())); + return true; + }); + Markdown.render(ctx, EmojiParser.parseToUnicode(cleanIssueDescription), viewBinding.issueDescription); RelativeLayout.LayoutParams paramsDesc = (RelativeLayout.LayoutParams) viewBinding.issueDescription.getLayoutParams(); @@ -603,7 +624,20 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.frameAssignees.addView(assigneesView); assigneesView.setLayoutParams(params1); - if(!singleIssue.getAssignees().get(i).getFull_name().equals("")) { + + int finalI = i; + assigneesView.setOnClickListener(loginId -> { + Intent intent = new Intent(ctx, ProfileActivity.class); + intent.putExtra("username", singleIssue.getAssignees().get(finalI).getLogin()); + ctx.startActivity(intent); + }); + + assigneesView.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(ctx, singleIssue.getAssignees().get(finalI).getLogin(), ctx.getString(R.string.copyLoginIdToClipBoard, singleIssue.getAssignees().get(finalI).getLogin())); + return true; + }); + + /*if(!singleIssue.getAssignees().get(i).getFull_name().equals("")) { assigneesView.setOnClickListener( new ClickListener(getString(R.string.assignedTo, singleIssue.getAssignees().get(i).getFull_name()), ctx)); @@ -612,7 +646,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt assigneesView.setOnClickListener( new ClickListener(getString(R.string.assignedTo, singleIssue.getAssignees().get(i).getLogin()), ctx)); - } + }*/ } } else { @@ -660,7 +694,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt if(timeFormat.equals("normal") || timeFormat.equals("pretty")) { - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", new Locale(locale)); + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", locale); String dueDate = formatter.format(singleIssue.getDue_date()); viewBinding.issueDueDate.setText(dueDate); viewBinding.issueDueDate @@ -668,7 +702,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt } else if(timeFormat.equals("normal1")) { - DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", new Locale(locale)); + DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", locale); String dueDate = formatter.format(singleIssue.getDue_date()); viewBinding.issueDueDate.setText(dueDate); } @@ -714,7 +748,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.issueDescription.setLayoutParams(paramsDesc); } - viewBinding.issueCreatedTime.setText(TimeHelper.formatTime(singleIssue.getCreated_at(), new Locale(locale), timeFormat, ctx)); + viewBinding.issueCreatedTime.setText(TimeHelper.formatTime(singleIssue.getCreated_at(), locale, timeFormat, ctx)); viewBinding.issueCreatedTime.setVisibility(View.VISIBLE); if(timeFormat.equals("pretty")) { @@ -750,7 +784,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.issueMilestone.setVisibility(View.GONE); } - if(!singleIssue.getUser().getFull_name().equals("")) { + /*if(!singleIssue.getUser().getFull_name().equals("")) { viewBinding.assigneeAvatar.setOnClickListener( new ClickListener(ctx.getResources().getString(R.string.issueCreator) + singleIssue.getUser().getFull_name(), ctx)); @@ -759,7 +793,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.assigneeAvatar.setOnClickListener( new ClickListener(ctx.getResources().getString(R.string.issueCreator) + singleIssue.getUser().getLogin(), ctx)); - } + }*/ viewBinding.progressBar.setVisibility(View.GONE); } diff --git a/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java b/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java index 2f86521b..8a776067 100644 --- a/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java @@ -77,6 +77,8 @@ public class LoginActivity extends BaseActivity { ArrayAdapter adapterProtocols = new ArrayAdapter<>(LoginActivity.this, R.layout.list_spinner_items, Protocol.values()); + instanceUrlET.setText(getIntent().getStringExtra("instanceUrl")); + protocolSpinner.setAdapter(adapterProtocols); protocolSpinner.setSelection(0); protocolSpinner.setOnItemClickListener((parent, view, position, id) -> { diff --git a/app/src/main/java/org/mian/gitnex/activities/MainActivity.java b/app/src/main/java/org/mian/gitnex/activities/MainActivity.java index 2e6e77e9..d05717a9 100644 --- a/app/src/main/java/org/mian/gitnex/activities/MainActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/MainActivity.java @@ -44,7 +44,7 @@ import org.mian.gitnex.fragments.ExploreFragment; import org.mian.gitnex.fragments.MyRepositoriesFragment; import org.mian.gitnex.fragments.NotificationsFragment; import org.mian.gitnex.fragments.OrganizationsFragment; -import org.mian.gitnex.fragments.ProfileFragment; +import org.mian.gitnex.fragments.MyProfileFragment; import org.mian.gitnex.fragments.RepositoriesFragment; import org.mian.gitnex.fragments.SettingsFragment; import org.mian.gitnex.fragments.StarredRepositoriesFragment; @@ -203,7 +203,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig else if(fragmentById instanceof NotificationsFragment) { toolbarTitle.setText(R.string.pageTitleNotifications); } - else if(fragmentById instanceof ProfileFragment) { + else if(fragmentById instanceof MyProfileFragment) { toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile)); } else if(fragmentById instanceof DraftsFragment) { @@ -309,7 +309,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig userAvatar.setOnClickListener(v -> { toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile)); - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit(); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyProfileFragment()).commit(); navigationView.setCheckedItem(R.id.nav_profile); drawer.closeDrawers(); @@ -380,12 +380,24 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig case "notification": getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new NotificationsFragment()).commit(); navigationView.setCheckedItem(R.id.nav_notifications); + setActionBarTitle(getResources().getString(R.string.pageTitleNotifications)); return; case "explore": getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ExploreFragment()).commit(); navigationView.setCheckedItem(R.id.nav_explore); return; + + case "profile": + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyProfileFragment()).commit(); + navigationView.setCheckedItem(R.id.nav_profile); + return; + + case "admin": + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AdministrationFragment()).commit(); + navigationView.setCheckedItem(R.id.nav_administration); + return; + } } @@ -419,7 +431,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig case 4: toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile)); - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit(); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyProfileFragment()).commit(); navigationView.setCheckedItem(R.id.nav_profile); break; @@ -557,7 +569,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig else if(id == R.id.nav_profile) { toolbarTitle.setText(getResources().getString(R.string.pageTitleProfile)); - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileFragment()).commit(); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyProfileFragment()).commit(); } else if(id == R.id.nav_repositories) { diff --git a/app/src/main/java/org/mian/gitnex/activities/MergePullRequestActivity.java b/app/src/main/java/org/mian/gitnex/activities/MergePullRequestActivity.java index 12b5d48a..e7f53cf7 100644 --- a/app/src/main/java/org/mian/gitnex/activities/MergePullRequestActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/MergePullRequestActivity.java @@ -12,6 +12,7 @@ import com.google.gson.JsonElement; import org.gitnex.tea4j.models.MergePullRequest; import org.gitnex.tea4j.models.MergePullRequestSpinner; import org.mian.gitnex.R; +import org.mian.gitnex.actions.PullRequestActions; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.ActivityMergePullRequestBinding; import org.mian.gitnex.helpers.AlertDialogs; @@ -187,7 +188,7 @@ public class MergePullRequestActivity extends BaseActivity { final String repoOwner = parts[0]; final String repoName = parts[1]; - deleteBranchFunction(repoOwner, repoName); + PullRequestActions.deleteHeadBranch(ctx, repoOwner, repoName, tinyDB.getString("prHeadBranch"), false); Toasty.success(ctx, getString(R.string.mergePRSuccessMsg)); tinyDB.putBoolean("prMerged", true); @@ -201,7 +202,7 @@ public class MergePullRequestActivity extends BaseActivity { final String repoOwner = parts[0]; final String repoName = parts[1]; - deleteBranchFunction(repoOwner, repoName); + PullRequestActions.deleteHeadBranch(ctx, repoOwner, repoName, tinyDB.getString("prHeadBranch"), false); Toasty.success(ctx, getString(R.string.mergePRSuccessMsg)); tinyDB.putBoolean("prMerged", true); @@ -253,36 +254,6 @@ public class MergePullRequestActivity extends BaseActivity { } - private void deleteBranchFunction(String repoOwner, String repoName) { - - String branchName = tinyDB.getString("prHeadBranch"); - - Call call = RetrofitClient - .getApiInterface(ctx) - .deleteBranch(Authorization.get(ctx), repoOwner, repoName, branchName); - - call.enqueue(new Callback() { - - @Override - public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { - - if(response.code() == 204) { - - Log.i("deleteBranch", "Branch deleted successfully"); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - Log.e("onFailure", t.toString()); - enableProcessButton(); - } - - }); - - } - private void disableProcessButton() { viewBinding.mergeButton.setEnabled(false); diff --git a/app/src/main/java/org/mian/gitnex/activities/ProfileEmailActivity.java b/app/src/main/java/org/mian/gitnex/activities/MyProfileEmailActivity.java similarity index 98% rename from app/src/main/java/org/mian/gitnex/activities/ProfileEmailActivity.java rename to app/src/main/java/org/mian/gitnex/activities/MyProfileEmailActivity.java index ef47f0d4..23d51bc9 100644 --- a/app/src/main/java/org/mian/gitnex/activities/ProfileEmailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/MyProfileEmailActivity.java @@ -30,7 +30,7 @@ import retrofit2.Callback; * Author M M Arif */ -public class ProfileEmailActivity extends BaseActivity { +public class MyProfileEmailActivity extends BaseActivity { private View.OnClickListener onClickListener; private EditText userEmail; diff --git a/app/src/main/java/org/mian/gitnex/activities/ProfileActivity.java b/app/src/main/java/org/mian/gitnex/activities/ProfileActivity.java new file mode 100644 index 00000000..93b65de1 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/activities/ProfileActivity.java @@ -0,0 +1,143 @@ +package org.mian.gitnex.activities; + +import android.content.Intent; +import android.graphics.Typeface; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; +import org.mian.gitnex.R; +import org.mian.gitnex.fragments.profile.DetailFragment; +import org.mian.gitnex.fragments.profile.FollowersFragment; +import org.mian.gitnex.fragments.profile.FollowingFragment; +import org.mian.gitnex.fragments.profile.OrganizationsFragment; +import org.mian.gitnex.fragments.profile.RepositoriesFragment; +import org.mian.gitnex.fragments.profile.StarredRepositoriesFragment; +import org.mian.gitnex.helpers.Toasty; +import java.util.Objects; + +/** + * Author M M Arif + */ + +public class ProfileActivity extends BaseActivity { + + private String username; + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_profile); + Intent profileIntent = getIntent(); + Typeface myTypeface; + + Toolbar toolbar = findViewById(R.id.toolbar); + TextView toolbarTitle = findViewById(R.id.toolbarTitle); + + if(profileIntent.getStringExtra("username") != null && !Objects.equals(profileIntent.getStringExtra("username"), "")) { + username = profileIntent.getStringExtra("username"); + } + else { + Toasty.warning(ctx, ctx.getResources().getString(R.string.userInvalidUserName)); + finish(); + } + + setSupportActionBar(toolbar); + Objects.requireNonNull(getSupportActionBar()).setTitle(username); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + ViewPager2 viewPager = findViewById(R.id.profileContainer); + viewPager.setOffscreenPageLimit(1); + TabLayout tabLayout = findViewById(R.id.tabs); + + switch(tinyDB.getInt("customFontId", -1)) { + case 0: + myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/roboto.ttf"); + break; + case 2: + myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/sourcecodeproregular.ttf"); + break; + default: + myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/manroperegular.ttf"); + break; + } + + toolbarTitle.setTypeface(myTypeface); + toolbarTitle.setText(username); + + viewPager.setAdapter(new ViewPagerAdapter(this)); + + String[] tabTitles = {ctx.getResources().getString(R.string.tabTextInfo), ctx.getResources().getString(R.string.navRepos), ctx.getResources().getString(R.string.navStarredRepos), ctx.getResources().getString(R.string.navOrg), ctx.getResources().getString(R.string.profileTabFollowers), ctx.getResources().getString(R.string.profileTabFollowing)}; + new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(tabTitles[position])).attach(); + + ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0); + int tabsCount = vg.getChildCount(); + + for (int j = 0; j < tabsCount; j++) { + + ViewGroup vgTab = (ViewGroup) vg.getChildAt(j); + int tabChildCount = vgTab.getChildCount(); + + for (int i = 0; i < tabChildCount; i++) { + View tabViewChild = vgTab.getChildAt(i); + if (tabViewChild instanceof TextView) { + ((TextView) tabViewChild).setTypeface(myTypeface); + } + } + } + } + + public class ViewPagerAdapter extends FragmentStateAdapter { + + public ViewPagerAdapter(@NonNull FragmentActivity fa) { super(fa); } + + @NonNull + @Override + public Fragment createFragment(int position) { + switch(position) { + case 0: // detail + return DetailFragment.newInstance(username); + case 1: // repos + return RepositoriesFragment.newInstance(username); + case 2: // starred repos + return StarredRepositoriesFragment.newInstance(username); + case 3: // organizations + return OrganizationsFragment.newInstance(username); + case 4: // followers + return FollowersFragment.newInstance(username); + case 5: // following + return FollowingFragment.newInstance(username); + } + return null; + } + + @Override + public int getItemCount() { + return 6; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + int id = item.getItemId(); + + if(id == android.R.id.home) { + finish(); + return true; + } + else { + return super.onOptionsItemSelected(item); + } + } +} diff --git a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java index 31442285..6e611788 100644 --- a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java @@ -232,13 +232,84 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF mainIntent.removeExtra("goToSection"); mainIntent.removeExtra("goToSectionType"); - if(goToSectionType.equals("issue")) { - - RepoDetailActivity.mViewPager.setCurrentItem(2); - } - else if(goToSectionType.equals("pull")) { - - RepoDetailActivity.mViewPager.setCurrentItem(3); + switch(goToSectionType) { + case "branchesList": + RepoDetailActivity.mViewPager.setCurrentItem(1); + chooseBranch(); + break; + case "branch": + RepoDetailActivity.mViewPager.setCurrentItem(1); + String selectedBranch = mainIntent.getStringExtra("selectedBranch"); + tinyDB.putString("repoBranch", selectedBranch); + if(getFragmentRefreshListenerFiles() != null) { + getFragmentRefreshListenerFiles().onRefresh(selectedBranch); + } + break; + case "file": + RepoDetailActivity.mViewPager.setCurrentItem(1); + String branch1 = mainIntent.getStringExtra("branch"); + tinyDB.putString("repoBranch", branch1); + if(getFragmentRefreshListenerFiles() != null) { + getFragmentRefreshListenerFiles().onRefresh(branch1); + } + Intent intent = new Intent(ctx, FileViewActivity.class); + intent.putExtra("file", mainIntent.getSerializableExtra("file")); + startActivity(intent); + break; + case "dir": + RepoDetailActivity.mViewPager.setCurrentItem(1); + String branch2 = mainIntent.getStringExtra("branch"); + tinyDB.putString("repoBranch", branch2); + if(getFragmentRefreshListenerFiles() != null) { + getFragmentRefreshListenerFiles().onRefresh(branch2); + } + //((SectionsPagerAdapter) Objects.requireNonNull(RepoDetailActivity.mViewPager.getAdapter())).getItem(1); + break; + case "commitsList": + RepoDetailActivity.mViewPager.setCurrentItem(1); + String branch = mainIntent.getStringExtra("branchName"); + tinyDB.putString("repoBranch", branch); + if(getFragmentRefreshListenerFiles() != null) { + getFragmentRefreshListenerFiles().onRefresh(branch); + } + Intent intent1 = new Intent(ctx, CommitsActivity.class); + intent1.putExtra("branchName", branch); + ctx.startActivity(intent1); + break; + case "issue": + RepoDetailActivity.mViewPager.setCurrentItem(2); + break; + case "issueNew": + RepoDetailActivity.mViewPager.setCurrentItem(2); + startActivity(new Intent(RepoDetailActivity.this, CreateIssueActivity.class)); + break; + case "pull": + RepoDetailActivity.mViewPager.setCurrentItem(3); + break; + case "pullNew": + RepoDetailActivity.mViewPager.setCurrentItem(3); + startActivity(new Intent(RepoDetailActivity.this, CreatePullRequestActivity.class)); + break; + case "releases": + RepoDetailActivity.mViewPager.setCurrentItem(4); + break; + case "newRelease": + RepoDetailActivity.mViewPager.setCurrentItem(4); + startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class)); + break; + case "milestones": + RepoDetailActivity.mViewPager.setCurrentItem(5); + break; + case "milestonesNew": + RepoDetailActivity.mViewPager.setCurrentItem(5); + startActivity(new Intent(RepoDetailActivity.this, CreateMilestoneActivity.class)); + break; + case "labels": + RepoDetailActivity.mViewPager.setCurrentItem(6); + break; + case "settings": + startActivity(new Intent(RepoDetailActivity.this, RepositorySettingsActivity.class)); + break; } } diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java index 373f0851..04aa0315 100644 --- a/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/SettingsAppearanceActivity.java @@ -1,14 +1,20 @@ package org.mian.gitnex.activities; +import android.app.Dialog; +import android.app.TimePickerDialog; import android.os.Bundle; +import android.text.format.DateFormat; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; +import android.widget.TimePicker; import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; import com.google.android.material.switchmaterial.SwitchMaterial; +import org.jetbrains.annotations.NotNull; import org.mian.gitnex.R; import org.mian.gitnex.databinding.ActivitySettingsAppearanceBinding; +import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; /** @@ -19,13 +25,13 @@ public class SettingsAppearanceActivity extends BaseActivity { private View.OnClickListener onClickListener; - private static final String[] timeList = {"Pretty", "Normal"}; + private static String[] timeList; private static int timeSelectedChoice = 0; - private static final String[] customFontList = {"Roboto", "Manrope", "Source Code Pro"}; + private static String[] customFontList; private static int customFontSelectedChoice = 0; - private static final String[] themeList = {"Dark", "Light", "Auto (Light / Dark)", "Retro", "Auto (Retro / Dark)", "Pitch Black"}; + private static String[] themeList; private static int themeSelectedChoice = 0; @Override @@ -38,48 +44,51 @@ public class SettingsAppearanceActivity extends BaseActivity { ImageView closeActivity = activitySettingsAppearanceBinding.close; - final TextView tvDateTimeSelected = activitySettingsAppearanceBinding.tvDateTimeSelected; // setter for time - final TextView customFontSelected = activitySettingsAppearanceBinding.customFontSelected; // setter for custom font - final TextView themeSelected = activitySettingsAppearanceBinding.themeSelected; // setter for theme - LinearLayout timeFrame = activitySettingsAppearanceBinding.timeFrame; LinearLayout customFontFrame = activitySettingsAppearanceBinding.customFontFrame; LinearLayout themeFrame = activitySettingsAppearanceBinding.themeSelectionFrame; + LinearLayout lightTimeFrame = activitySettingsAppearanceBinding.lightThemeTimeSelectionFrame; + LinearLayout darkTimeFrame = activitySettingsAppearanceBinding.darkThemeTimeSelectionFrame; SwitchMaterial counterBadgesSwitch = activitySettingsAppearanceBinding.switchCounterBadge; + timeList = getResources().getStringArray(R.array.timeFormats); + customFontList = getResources().getStringArray(R.array.fonts); + themeList = getResources().getStringArray(R.array.themes); + initCloseListener(); closeActivity.setOnClickListener(onClickListener); - if(!tinyDB.getString("timeStr").isEmpty()) { + String lightMinute = String.valueOf(tinyDB.getInt("lightThemeTimeMinute")); + String lightHour = String.valueOf(tinyDB.getInt("lightThemeTimeHour")); + if(lightMinute.length() == 1) lightMinute = "0" + lightMinute; + if(lightHour.length() == 1) lightHour = "0" + lightHour; - tvDateTimeSelected.setText(tinyDB.getString("timeStr")); + String darkMinute = String.valueOf(tinyDB.getInt("darkThemeTimeMinute")); + String darkHour = String.valueOf(tinyDB.getInt("darkThemeTimeHour")); + if(darkMinute.length() == 1) darkMinute = "0" + darkMinute; + if(darkHour.length() == 1) darkHour = "0" + darkHour; + + activitySettingsAppearanceBinding.lightThemeSelectedTime.setText(ctx.getResources().getString(R.string.settingsThemeTimeSelectedHint, lightHour, + lightMinute)); + activitySettingsAppearanceBinding.darkThemeSelectedTime.setText(ctx.getResources().getString(R.string.settingsThemeTimeSelectedHint, darkHour, + darkMinute)); + activitySettingsAppearanceBinding.tvDateTimeSelected.setText(tinyDB.getString("timeStr")); + activitySettingsAppearanceBinding.customFontSelected.setText(tinyDB.getString("customFontStr", "Manrope")); + activitySettingsAppearanceBinding.themeSelected.setText(tinyDB.getString("themeStr", "Dark")); + + if(tinyDB.getString("themeStr").startsWith("Auto")) { + darkTimeFrame.setVisibility(View.VISIBLE); + lightTimeFrame.setVisibility(View.VISIBLE); + } + else { + darkTimeFrame.setVisibility(View.GONE); + lightTimeFrame.setVisibility(View.GONE); } - if(!tinyDB.getString("customFontStr").isEmpty()) { - - customFontSelected.setText(tinyDB.getString("customFontStr")); - } - - if(!tinyDB.getString("themeStr").isEmpty()) { - - themeSelected.setText(tinyDB.getString("themeStr")); - } - - if(timeSelectedChoice == 0) { - - timeSelectedChoice = tinyDB.getInt("timeId"); - } - - if(customFontSelectedChoice == 0) { - - customFontSelectedChoice = tinyDB.getInt("customFontId", 1); - } - - if(themeSelectedChoice == 0) { - - themeSelectedChoice = tinyDB.getInt("themeId"); - } + timeSelectedChoice = tinyDB.getInt("timeId"); + customFontSelectedChoice = tinyDB.getInt("customFontId", 1); + themeSelectedChoice = tinyDB.getInt("themeId"); counterBadgesSwitch.setChecked(tinyDB.getBoolean("enableCounterBadges")); @@ -101,7 +110,7 @@ public class SettingsAppearanceActivity extends BaseActivity { tsBuilder.setSingleChoiceItems(themeList, themeSelectedChoice, (dialogInterfaceTheme, i) -> { themeSelectedChoice = i; - themeSelected.setText(themeList[i]); + activitySettingsAppearanceBinding.themeSelected.setText(themeList[i]); tinyDB.putString("themeStr", themeList[i]); tinyDB.putInt("themeId", i); @@ -116,6 +125,16 @@ public class SettingsAppearanceActivity extends BaseActivity { cfDialog.show(); }); + lightTimeFrame.setOnClickListener(view -> { + LightTimePicker timePicker = new LightTimePicker(); + timePicker.show(getSupportFragmentManager(), "timePicker"); + }); + + darkTimeFrame.setOnClickListener(view -> { + DarkTimePicker timePicker = new DarkTimePicker(); + timePicker.show(getSupportFragmentManager(), "timePicker"); + }); + // custom font dialog customFontFrame.setOnClickListener(view -> { @@ -127,7 +146,7 @@ public class SettingsAppearanceActivity extends BaseActivity { cfBuilder.setSingleChoiceItems(customFontList, customFontSelectedChoice, (dialogInterfaceCustomFont, i) -> { customFontSelectedChoice = i; - customFontSelected.setText(customFontList[i]); + activitySettingsAppearanceBinding.customFontSelected.setText(customFontList[i]); tinyDB.putString("customFontStr", customFontList[i]); tinyDB.putInt("customFontId", i); @@ -153,17 +172,17 @@ public class SettingsAppearanceActivity extends BaseActivity { tBuilder.setSingleChoiceItems(timeList, timeSelectedChoice, (dialogInterfaceTime, i) -> { timeSelectedChoice = i; - tvDateTimeSelected.setText(timeList[i]); + activitySettingsAppearanceBinding.tvDateTimeSelected.setText(timeList[i]); tinyDB.putString("timeStr", timeList[i]); tinyDB.putInt("timeId", i); - if("Normal".equals(timeList[i])) { - - tinyDB.putString("dateFormat", "normal"); - } - else { - - tinyDB.putString("dateFormat", "pretty"); + switch(i) { + case 0: + tinyDB.putString("dateFormat", "pretty"); + break; + case 1: + tinyDB.putString("dateFormat", "normal"); + break; } dialogInterfaceTime.dismiss(); @@ -180,4 +199,54 @@ public class SettingsAppearanceActivity extends BaseActivity { onClickListener = view -> finish(); } + public static class LightTimePicker extends DialogFragment implements TimePickerDialog.OnTimeSetListener { + + TinyDB db = TinyDB.getInstance(getContext()); + + @NotNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + int hour = db.getInt("lightThemeTimeHour"); + int minute = db.getInt("lightThemeTimeMinute"); + + return new TimePickerDialog(getActivity(), this, hour, minute, true); + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + db.putInt("lightThemeTimeHour", hourOfDay); + db.putInt("lightThemeTimeMinute", minute); + db.putBoolean("refreshParent", true); + requireActivity().overridePendingTransition(0, 0); + this.dismiss(); + Toasty.success(requireActivity().getApplicationContext(), requireContext().getResources().getString(R.string.settingsSave)); + requireActivity().recreate(); + } + } + + public static class DarkTimePicker extends DialogFragment implements TimePickerDialog.OnTimeSetListener { + + TinyDB db = TinyDB.getInstance(getContext()); + + @NotNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + int hour = db.getInt("darkThemeTimeHour"); + int minute = db.getInt("darkThemeTimeMinute"); + + return new TimePickerDialog(getActivity(), this, hour, minute, true); + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + db.putInt("darkThemeTimeHour", hourOfDay); + db.putInt("darkThemeTimeMinute", minute); + db.putBoolean("refreshParent", true); + requireActivity().overridePendingTransition(0, 0); + this.dismiss(); + Toasty.success(requireActivity().getApplicationContext(), requireContext().getResources().getString(R.string.settingsSave)); + requireActivity().recreate(); + } + } + } diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsGeneralActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsGeneralActivity.java index f63762a5..e718c14a 100644 --- a/app/src/main/java/org/mian/gitnex/activities/SettingsGeneralActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/SettingsGeneralActivity.java @@ -23,7 +23,7 @@ public class SettingsGeneralActivity extends BaseActivity { private List homeScreenList; private static int homeScreenSelectedChoice = 0; - private List defaultScreen; + private List linkHandlerDefaultScreen; private static int defaultLinkHandlerScreenSelectedChoice = 0; @Override @@ -38,20 +38,16 @@ public class SettingsGeneralActivity extends BaseActivity { viewBinding.close.setOnClickListener(onClickListener); // home screen - String[] homeDefaultScreen_ = {getResources().getString(R.string.pageTitleMyRepos), getResources().getString(R.string.pageTitleStarredRepos), getResources().getString(R.string.pageTitleOrganizations), - getResources().getString(R.string.pageTitleRepositories), getResources().getString(R.string.pageTitleProfile), getResources().getString(R.string.pageTitleExplore), - getResources().getString(R.string.titleDrafts)}; + String[] appHomeDefaultScreen = getResources().getStringArray(R.array.appDefaultHomeScreen); - String[] homeDefaultScreenNew = {getResources().getString(R.string.pageTitleMyRepos), getResources().getString(R.string.pageTitleStarredRepos), getResources().getString(R.string.pageTitleOrganizations), - getResources().getString(R.string.pageTitleRepositories), getResources().getString(R.string.pageTitleProfile), getResources().getString(R.string.pageTitleExplore), - getResources().getString(R.string.titleDrafts), getResources().getString(R.string.pageTitleNotifications)}; + String[] appHomeDefaultScreenNew = getResources().getStringArray(R.array.appDefaultHomeScreenNew); if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.12.3")) { - homeDefaultScreen_ = homeDefaultScreenNew; + appHomeDefaultScreen = appHomeDefaultScreenNew; } - homeScreenList = new ArrayList<>(Arrays.asList(homeDefaultScreen_)); + homeScreenList = new ArrayList<>(Arrays.asList(appHomeDefaultScreen)); String[] homeScreenArray = new String[homeScreenList.size()]; homeScreenList.toArray(homeScreenArray); @@ -113,34 +109,14 @@ public class SettingsGeneralActivity extends BaseActivity { // home screen // link handler - String[] defaultScreen_ = {getResources().getString(R.string.generalDeepLinkSelectedText), getResources().getString(R.string.navRepos), getResources().getString(R.string.navOrg), getResources().getString(R.string.pageTitleNotifications), getResources().getString(R.string.navExplore)}; - defaultScreen = new ArrayList<>(Arrays.asList(defaultScreen_)); + String[] linkHandlerDefaultScreenList = getResources().getStringArray(R.array.linkHandlerDefaultScreen); + linkHandlerDefaultScreen = new ArrayList<>(Arrays.asList(linkHandlerDefaultScreenList)); - String[] linksArray = new String[defaultScreen.size()]; - defaultScreen.toArray(linksArray); + String[] linksArray = new String[linkHandlerDefaultScreen.size()]; + linkHandlerDefaultScreen.toArray(linksArray); - if(defaultLinkHandlerScreenSelectedChoice == 0) { - - defaultLinkHandlerScreenSelectedChoice = tinyDB.getInt("defaultScreenId"); - viewBinding.generalDeepLinkSelected.setText(getResources().getString(R.string.generalDeepLinkSelectedText)); - } - - if(defaultLinkHandlerScreenSelectedChoice == 1) { - - viewBinding.generalDeepLinkSelected.setText(getResources().getString(R.string.navRepos)); - } - else if(defaultLinkHandlerScreenSelectedChoice == 2) { - - viewBinding.generalDeepLinkSelected.setText(getResources().getString(R.string.navOrg)); - } - else if(defaultLinkHandlerScreenSelectedChoice == 3) { - - viewBinding.generalDeepLinkSelected.setText(getResources().getString(R.string.pageTitleNotifications)); - } - else if(defaultLinkHandlerScreenSelectedChoice == 4) { - - viewBinding.generalDeepLinkSelected.setText(getResources().getString(R.string.navExplore)); - } + defaultLinkHandlerScreenSelectedChoice = tinyDB.getInt("defaultScreenId"); + viewBinding.generalDeepLinkSelected.setText(linksArray[defaultLinkHandlerScreenSelectedChoice]); viewBinding.setDefaultLinkHandler.setOnClickListener(setDefaultLinkHandler -> { diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java index 0e81ccb0..1573198b 100644 --- a/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/SettingsSecurityActivity.java @@ -31,10 +31,10 @@ public class SettingsSecurityActivity extends BaseActivity { private View.OnClickListener onClickListener; - private static final String[] cacheSizeDataList = {"50 MB", "100 MB", "250 MB", "500 MB", "1 GB"}; + private static String[] cacheSizeDataList; private static int cacheSizeDataSelectedChoice = 0; - private static final String[] cacheSizeImagesList = {"50 MB", "100 MB", "250 MB", "500 MB", "1 GB"}; + private static String[] cacheSizeImagesList; private static int cacheSizeImagesSelectedChoice = 0; @Override @@ -61,6 +61,9 @@ public class SettingsSecurityActivity extends BaseActivity { SwitchMaterial switchBiometric = activitySettingsSecurityBinding.switchBiometric; + cacheSizeDataList = getResources().getStringArray(R.array.cacheSizeList); + cacheSizeImagesList = getResources().getStringArray(R.array.cacheSizeList); + if(!tinyDB.getString("cacheSizeStr").isEmpty()) { cacheSizeDataSelected.setText(tinyDB.getString("cacheSizeStr")); diff --git a/app/src/main/java/org/mian/gitnex/activities/SettingsTranslationActivity.java b/app/src/main/java/org/mian/gitnex/activities/SettingsTranslationActivity.java index 45b3e8ac..8a40543d 100644 --- a/app/src/main/java/org/mian/gitnex/activities/SettingsTranslationActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/SettingsTranslationActivity.java @@ -11,6 +11,9 @@ import androidx.appcompat.app.AlertDialog; import org.mian.gitnex.R; import org.mian.gitnex.databinding.ActivitySettingsTranslationBinding; import org.mian.gitnex.helpers.Toasty; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.TreeMap; /** * Author M M Arif @@ -20,8 +23,6 @@ public class SettingsTranslationActivity extends BaseActivity { private View.OnClickListener onClickListener; - private static String[] langList = {"English", "Arabic", "Chinese", "Czech", "Finnish", "French", "German", "Italian", "Latvian", "Persian", - "Polish", "Portuguese/Brazilian", "Russian", "Serbian", "Spanish", "Turkish", "Ukrainian"}; private static int langSelectedChoice = 0; @Override @@ -29,6 +30,12 @@ public class SettingsTranslationActivity extends BaseActivity { super.onCreate(savedInstanceState); + LinkedHashMap langs = new LinkedHashMap<>(); + langs.put("", getString(R.string.settingsLanguageSystem)); + for(String langCode : getResources().getStringArray(R.array.languages)) { + langs.put(langCode, getLanguageDisplayName(langCode)); + } + ActivitySettingsTranslationBinding activitySettingsTranslationBinding = ActivitySettingsTranslationBinding.inflate(getLayoutInflater()); setContentView(activitySettingsTranslationBinding.getRoot()); @@ -52,15 +59,9 @@ public class SettingsTranslationActivity extends BaseActivity { }); - if(!tinyDB.getString("localeStr").isEmpty()) { + tvLanguageSelected.setText(tinyDB.getString("localeStr")); - tvLanguageSelected.setText(tinyDB.getString("localeStr")); - } - - if(langSelectedChoice == 0) { - - langSelectedChoice = tinyDB.getInt("langId"); - } + langSelectedChoice = tinyDB.getInt("langId"); // language dialog langFrame.setOnClickListener(view -> { @@ -70,89 +71,18 @@ public class SettingsTranslationActivity extends BaseActivity { lBuilder.setTitle(R.string.settingsLanguageSelectorDialogTitle); lBuilder.setCancelable(langSelectedChoice != -1); - lBuilder.setSingleChoiceItems(langList, langSelectedChoice, (dialogInterface, i) -> { + lBuilder.setSingleChoiceItems(langs.values().toArray(new String[0]), langSelectedChoice, (dialogInterface, i) -> { - langSelectedChoice = i; - tvLanguageSelected.setText(langList[i]); - tinyDB.putString("localeStr", langList[i]); + String selectedLanguage = langs.keySet().toArray(new String[0])[i]; + tinyDB.putString("localeStr", langs.get(selectedLanguage)); tinyDB.putInt("langId", i); - - switch(langList[i]) { - case "Arabic": - - tinyDB.putString("locale", "ar"); - break; - case "Chinese": - - tinyDB.putString("locale", "zh"); - break; - case "Czech": - - tinyDB.putString("locale", "cs"); - break; - case "Finnish": - - tinyDB.putString("locale", "fi"); - break; - case "French": - - tinyDB.putString("locale", "fr"); - break; - case "German": - - tinyDB.putString("locale", "de"); - break; - case "Italian": - - tinyDB.putString("locale", "it"); - break; - case "Latvian": - - tinyDB.putString("locale", "lv"); - break; - case "Persian": - - tinyDB.putString("locale", "fa"); - break; - case "Polish": - - tinyDB.putString("locale", "pl"); - break; - case "Portuguese/Brazilian": - - tinyDB.putString("locale", "pt"); - break; - case "Russian": - - tinyDB.putString("locale", "ru"); - break; - case "Serbian": - - tinyDB.putString("locale", "sr"); - break; - case "Spanish": - - tinyDB.putString("locale", "es"); - break; - case "Turkish": - - tinyDB.putString("locale", "tr"); - break; - case "Ukrainian": - - tinyDB.putString("locale", "uk"); - break; - default: - - tinyDB.putString("locale", "en"); - break; - } + tinyDB.putString("locale", selectedLanguage); tinyDB.putBoolean("refreshParent", true); - this.recreate(); this.overridePendingTransition(0, 0); dialogInterface.dismiss(); Toasty.success(appCtx, getResources().getString(R.string.settingsSave)); + this.recreate(); }); lBuilder.setNeutralButton(getString(R.string.cancelButton), null); @@ -167,4 +97,10 @@ public class SettingsTranslationActivity extends BaseActivity { onClickListener = view -> finish(); } + private static String getLanguageDisplayName(String langCode) { + Locale english = new Locale("en"); + Locale translated = new Locale(langCode); + return String.format("%s (%s)", translated.getDisplayName(translated), translated.getDisplayName(english)); + } + } diff --git a/app/src/main/java/org/mian/gitnex/adapters/AdminCronTasksAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/AdminCronTasksAdapter.java index cb53bff4..38d78019 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/AdminCronTasksAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/AdminCronTasksAdapter.java @@ -44,7 +44,7 @@ public class AdminCronTasksAdapter extends RecyclerView.Adapter usersListFull; - static class UsersViewHolder extends RecyclerView.ViewHolder { + class UsersViewHolder extends RecyclerView.ViewHolder { private String userLoginId; @@ -52,10 +54,14 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); - Context context = loginId.getContext(); - + userAvatar.setOnLongClickListener(loginId -> { AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/CollaboratorsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/CollaboratorsAdapter.java index 0f229011..6e90df0f 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/CollaboratorsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/CollaboratorsAdapter.java @@ -2,6 +2,7 @@ package org.mian.gitnex.adapters; import android.annotation.SuppressLint; import android.content.Context; +import android.content.Intent; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -11,6 +12,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.gitnex.tea4j.models.Collaborators; import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.RoundedTransformation; @@ -25,7 +27,7 @@ public class CollaboratorsAdapter extends BaseAdapter { private final List collaboratorsList; private final Context context; - private static class ViewHolder { + private class ViewHolder { private String userLoginId; @@ -38,10 +40,14 @@ public class CollaboratorsAdapter extends BaseAdapter { collaboratorName = v.findViewById(R.id.collaboratorName); collaboratorAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); - Context context = loginId.getContext(); - + collaboratorAvatar.setOnLongClickListener(loginId -> { AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/CommitsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/CommitsAdapter.java index b1729892..e519eebe 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/CommitsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/CommitsAdapter.java @@ -57,13 +57,11 @@ public class CommitsAdapter extends RecyclerView.Adapter= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { - isLoading = true; loadMoreListener.onLoadMore(); } if(getItemViewType(position) == TYPE_LOAD) { - ((CommitsHolder) holder).bindData(commitsList.get(position)); } } @@ -106,18 +104,16 @@ public class CommitsAdapter extends RecyclerView.Adapter context.startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(commitsModel.getHtml_url())))); } @@ -126,36 +122,29 @@ public class CommitsAdapter extends RecyclerView.Adapter list) { - commitsList = list; notifyDataSetChanged(); } - } diff --git a/app/src/main/java/org/mian/gitnex/adapters/SearchIssuesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java similarity index 83% rename from app/src/main/java/org/mian/gitnex/adapters/SearchIssuesAdapter.java rename to app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java index 13f4c13e..5067a22c 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/SearchIssuesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java @@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.gitnex.tea4j.models.Issues; import org.mian.gitnex.R; import org.mian.gitnex.activities.IssueDetailActivity; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.database.api.BaseApi; import org.mian.gitnex.database.api.RepositoriesApi; @@ -33,13 +34,13 @@ import java.util.Locale; * Author M M Arif */ -public class SearchIssuesAdapter extends RecyclerView.Adapter { +public class ExploreIssuesAdapter extends RecyclerView.Adapter { private final List searchedList; private final Context context; private final TinyDB tinyDb; - public SearchIssuesAdapter(List dataList, Context ctx) { + public ExploreIssuesAdapter(List dataList, Context ctx) { this.context = ctx; this.searchedList = dataList; @@ -49,7 +50,6 @@ public class SearchIssuesAdapter extends RecyclerView.Adapter { - - Context context = v.getContext(); - Intent intent = new Intent(context, IssueDetailActivity.class); intent.putExtra("issueNumber", issue.getNumber()); @@ -90,42 +87,44 @@ public class SearchIssuesAdapter extends RecyclerView.Adapter { - Context context = v.getContext(); - String userLoginId = issue.getUser().getLogin(); + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", issue.getUser().getLogin()); + context.startActivity(intent); + }); - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + issueAssigneeAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, issue.getUser().getLogin(), context.getString(R.string.copyLoginIdToClipBoard, issue.getUser().getLogin())); + return true; }); } } @NonNull @Override - public SearchIssuesAdapter.SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + public ExploreIssuesAdapter.SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_issues, parent, false); - return new SearchIssuesAdapter.SearchViewHolder(v); + return new ExploreIssuesAdapter.SearchViewHolder(v); } @Override - public void onBindViewHolder(@NonNull final SearchIssuesAdapter.SearchViewHolder holder, int position) { + public void onBindViewHolder(@NonNull final ExploreIssuesAdapter.SearchViewHolder holder, int position) { Issues currentItem = searchedList.get(position); int imgRadius = AppUtil.getPixelsFromDensity(context, 3); - String locale = tinyDb.getString("locale"); + Locale locale = context.getResources().getConfiguration().locale; String timeFormat = tinyDb.getString("dateFormat"); PicassoService.getInstance(context).get() @@ -144,20 +143,20 @@ public class SearchIssuesAdapter extends RecyclerView.Adapter { + + private final Context context; + private final int TYPE_LOAD = 0; + private List organizationsList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public ExplorePublicOrganizationsAdapter(Context ctx, List organizationsListMain) { + this.context = ctx; + this.organizationsList = organizationsListMain; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if(viewType == TYPE_LOAD) { + return new ExplorePublicOrganizationsAdapter.OrganizationsHolder(inflater.inflate(R.layout.list_organizations, parent, false)); + } + else { + return new ExplorePublicOrganizationsAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((ExplorePublicOrganizationsAdapter.OrganizationsHolder) holder).bindData(organizationsList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(organizationsList.get(position).getFull_name() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return organizationsList.size(); + } + + class OrganizationsHolder extends RecyclerView.ViewHolder { + private Organization organization; + private final ImageView image; + private final TextView orgName; + private final TextView orgDescription; + + OrganizationsHolder(View itemView) { + super(itemView); + image = itemView.findViewById(R.id.imageAvatar); + orgName = itemView.findViewById(R.id.orgName); + orgDescription = itemView.findViewById(R.id.orgDescription); + + itemView.setOnClickListener(v -> { + Context context = v.getContext(); + Intent intent = new Intent(context, OrganizationDetailActivity.class); + intent.putExtra("orgName", organization.getUsername()); + + TinyDB tinyDb = TinyDB.getInstance(context); + tinyDb.putString("orgName", organization.getUsername()); + tinyDb.putString("organizationId", String.valueOf(organization.getId())); + tinyDb.putBoolean("organizationAction", true); + context.startActivity(intent); + }); + } + + @SuppressLint("SetTextI18n") + void bindData(Organization organization) { + this.organization = organization; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + orgName.setText(organization.getUsername()); + PicassoService.getInstance(context).get() + .load(organization.getAvatar_url()) + .placeholder(R.drawable.loader_animated) + .transform(new RoundedTransformation(imgRadius, 0)) + .resize(120, 120) + .centerCrop() + .into(image); + if (!organization.getDescription().equals("")) { + orgDescription.setText(organization.getDescription()); + } + } + } + + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + organizationsList = list; + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java index ee9b5926..2afa3aa9 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java @@ -122,45 +122,32 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter call; - call = RetrofitClient.getApiInterface(context).checkRepoWatchStatus(token, repoOwner, repoName); call.enqueue(new Callback() { - @Override public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { if(response.isSuccessful()) { - assert response.body() != null; tinyDb.putBoolean("repoWatch", response.body().getSubscribed()); - - } else { - - tinyDb.putBoolean("repoWatch", false); - - if(response.code() != 404) { - - Toasty.error(context, context.getString(R.string.genericApiStatusError)); - - } - } - + else { + tinyDb.putBoolean("repoWatch", false); + if(response.code() != 404) { + Toasty.error(context, context.getString(R.string.genericApiStatusError)); + } + } } @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { - tinyDb.putBoolean("repoWatch", false); Toasty.error(context, context.getString(R.string.genericApiStatusError)); } }); - } - context.startActivity(intent); }); @@ -183,7 +170,7 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter issuesComments; private final FragmentManager fragmentManager; private final BottomSheetReplyFragment.OnInteractedListener onInteractedListener; + private final Locale locale; public IssueCommentsAdapter(Context ctx, Bundle bundle, List issuesCommentsMain, FragmentManager fragmentManager, BottomSheetReplyFragment.OnInteractedListener onInteractedListener) { @@ -58,8 +60,8 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { - final Context ctx = v.getContext(); final String loginUid = tinyDB.getString("loginUid"); - @SuppressLint("InflateParams") View vw = LayoutInflater.from(ctx).inflate(R.layout.bottom_sheet_issue_comments, null); + @SuppressLint("InflateParams") View vw = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_issue_comments, null); TextView commentMenuEdit = vw.findViewById(R.id.commentMenuEdit); TextView commentShare = vw.findViewById(R.id.issueCommentShare); @@ -107,7 +108,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { - tinyDB.putBoolean("commentEdited", true); onInteractedListener.onInteracted(); dialog.dismiss(); - }); linearLayout.addView(reactionSpinner); commentMenuEdit.setOnClickListener(v1 -> { - Bundle bundle = new Bundle(); bundle.putInt("commentId", issueComment.getId()); bundle.putString("commentAction", "edit"); @@ -141,56 +139,48 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { - // get comment Url CharSequence commentUrl = issueComment.getHtml_url(); // share issue comment Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); - String intentHeader = tinyDB.getString("issueNumber") + ctx.getResources().getString(R.string.hash) + "issuecomment-" + issueComment.getId() + " " + tinyDB.getString("issueTitle"); + String intentHeader = tinyDB.getString("issueNumber") + context.getResources().getString(R.string.hash) + "issuecomment-" + issueComment.getId() + " " + tinyDB.getString("issueTitle"); sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, intentHeader); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, commentUrl); - ctx.startActivity(Intent.createChooser(sharingIntent, intentHeader)); + context.startActivity(Intent.createChooser(sharingIntent, intentHeader)); dialog.dismiss(); - }); issueCommentCopyUrl.setOnClickListener(v1 -> { - // comment Url CharSequence commentUrl = issueComment.getHtml_url(); - ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(Context.CLIPBOARD_SERVICE); + ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(context).getSystemService(Context.CLIPBOARD_SERVICE); assert clipboard != null; ClipData clip = ClipData.newPlainText(commentUrl, commentUrl); clipboard.setPrimaryClip(clip); dialog.dismiss(); - Toasty.success(ctx, ctx.getString(R.string.copyIssueUrlToastMsg)); - + Toasty.success(context, context.getString(R.string.copyIssueUrlToastMsg)); }); commentMenuQuote.setOnClickListener(v1 -> { - StringBuilder stringBuilder = new StringBuilder(); String commenterName = issueComment.getUser().getUsername(); if(!commenterName.equals(tinyDB.getString("userLogin"))) { - stringBuilder.append("@").append(commenterName).append("\n\n"); } String[] lines = issueComment.getBody().split("\\R"); for(String line : lines) { - stringBuilder.append(">").append(line).append("\n"); } @@ -202,40 +192,37 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { - - ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(Context.CLIPBOARD_SERVICE); + ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(context).getSystemService(Context.CLIPBOARD_SERVICE); assert clipboard != null; ClipData clip = ClipData.newPlainText("Comment on issue #" + tinyDB.getString("issueNumber"), issueComment.getBody()); clipboard.setPrimaryClip(clip); dialog.dismiss(); - Toasty.success(ctx, ctx.getString(R.string.copyIssueCommentToastMsg)); - + Toasty.success(context, context.getString(R.string.copyIssueCommentToastMsg)); }); commentMenuDelete.setOnClickListener(v1 -> { - - deleteIssueComment(ctx, issueComment.getId(), getAdapterPosition()); + deleteIssueComment(context, issueComment.getId(), getAdapterPosition()); dialog.dismiss(); - }); }); avatar.setOnClickListener(loginId -> { - - Context context = loginId.getContext(); - - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); }); + avatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; + }); } - } private void updateAdapter(int position) { @@ -243,7 +230,6 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter TimeHelper.customDateFormatForToastDateFormat(issueComment.getCreated_at())); - } else if(timeFormat.equals("normal")) { - - informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreated_at(), Locale.getDefault(), "normal", context)); + informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreated_at(), locale, "normal", context)); } if(!issueComment.getCreated_at().equals(issueComment.getUpdated_at())) { @@ -374,7 +357,6 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime); itemView.setOnClickListener(layoutView -> { - - Context context = layoutView.getContext(); - Intent intent = new Intent(context, IssueDetailActivity.class); intent.putExtra("issueNumber", issue.getNumber()); @@ -123,19 +121,22 @@ public class IssuesAdapter extends RecyclerView.Adapter }); issueAssigneeAvatar.setOnClickListener(v -> { - Context context = v.getContext(); - String userLoginId = issue.getUser().getLogin(); - - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", issue.getUser().getLogin()); + context.startActivity(intent); }); + issueAssigneeAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, issue.getUser().getLogin(), context.getString(R.string.copyLoginIdToClipBoard, issue.getUser().getLogin())); + return true; + }); } @SuppressLint("SetTextI18n") void bindData(Issues issue) { TinyDB tinyDb = TinyDB.getInstance(context); - String locale = tinyDb.getString("locale"); + Locale locale = context.getResources().getConfiguration().locale; String timeFormat = tinyDb.getString("dateFormat"); int imgRadius = AppUtil.getPixelsFromDensity(context, 3); @@ -156,20 +157,20 @@ public class IssuesAdapter extends RecyclerView.Adapter switch(timeFormat) { case "pretty": { - PrettyTime prettyTime = new PrettyTime(new Locale(locale)); + PrettyTime prettyTime = new PrettyTime(locale); 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)); + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); 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)); + DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); String createdTime = formatter.format(issue.getCreated_at()); this.issueCreatedTime.setText(createdTime); break; diff --git a/app/src/main/java/org/mian/gitnex/adapters/MembersByOrgAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/MembersByOrgAdapter.java index 00f284f1..897cca2f 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/MembersByOrgAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/MembersByOrgAdapter.java @@ -2,6 +2,7 @@ package org.mian.gitnex.adapters; import android.annotation.SuppressLint; import android.content.Context; +import android.content.Intent; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -13,6 +14,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.gitnex.tea4j.models.UserInfo; import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.RoundedTransformation; @@ -29,7 +31,7 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable { private final Context context; private final List membersListFull; - private static class ViewHolder { + private class ViewHolder { private String userLoginId; @@ -42,10 +44,14 @@ public class MembersByOrgAdapter extends BaseAdapter implements Filterable { memberName = v.findViewById(R.id.memberName); memberAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); - Context context = loginId.getContext(); - + memberAvatar.setOnLongClickListener(loginId -> { AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/MilestonesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/MilestonesAdapter.java index f805e570..6c5f4a96 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/MilestonesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/MilestonesAdapter.java @@ -148,7 +148,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter { +public class MyProfileEmailsAdapter extends RecyclerView.Adapter { private final List emailsList; private final Context context; @@ -37,20 +37,20 @@ public class ProfileEmailsAdapter extends RecyclerView.Adapter emailsListMain) { + public MyProfileEmailsAdapter(Context ctx, List emailsListMain) { this.context = ctx; this.emailsList = emailsListMain; } @NonNull @Override - public ProfileEmailsAdapter.EmailsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + public MyProfileEmailsAdapter.EmailsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_emails, parent, false); - return new ProfileEmailsAdapter.EmailsViewHolder(v); + return new MyProfileEmailsAdapter.EmailsViewHolder(v); } @Override - public void onBindViewHolder(@NonNull ProfileEmailsAdapter.EmailsViewHolder holder, int position) { + public void onBindViewHolder(@NonNull MyProfileEmailsAdapter.EmailsViewHolder holder, int position) { Emails currentItem = emailsList.get(position); diff --git a/app/src/main/java/org/mian/gitnex/adapters/ProfileFollowersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java similarity index 72% rename from app/src/main/java/org/mian/gitnex/adapters/ProfileFollowersAdapter.java rename to app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java index 5383ae16..19d5bd9c 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ProfileFollowersAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java @@ -1,6 +1,7 @@ package org.mian.gitnex.adapters; import android.content.Context; +import android.content.Intent; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -11,6 +12,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import org.gitnex.tea4j.models.UserInfo; import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.RoundedTransformation; @@ -20,12 +22,12 @@ import java.util.List; * Author M M Arif */ -public class ProfileFollowersAdapter extends RecyclerView.Adapter { +public class MyProfileFollowersAdapter extends RecyclerView.Adapter { private final List followersList; private final Context context; - static class FollowersViewHolder extends RecyclerView.ViewHolder { + class FollowersViewHolder extends RecyclerView.ViewHolder { private String userLoginId; @@ -41,16 +43,20 @@ public class ProfileFollowersAdapter extends RecyclerView.Adapter { - - Context context = loginId.getContext(); + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); + itemView.setOnLongClickListener(loginId -> { AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; }); } } - public ProfileFollowersAdapter(Context ctx, List followersListMain) { + public MyProfileFollowersAdapter(Context ctx, List followersListMain) { this.context = ctx; this.followersList = followersListMain; @@ -58,14 +64,14 @@ public class ProfileFollowersAdapter extends RecyclerView.Adapter { +public class MyProfileFollowingAdapter extends RecyclerView.Adapter { private final List followingList; private final Context context; - static class FollowingViewHolder extends RecyclerView.ViewHolder { + class FollowingViewHolder extends RecyclerView.ViewHolder { private String userLoginId; @@ -41,16 +43,20 @@ public class ProfileFollowingAdapter extends RecyclerView.Adapter { - - Context context = loginId.getContext(); + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); + itemView.setOnLongClickListener(loginId -> { AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; }); } } - public ProfileFollowingAdapter(Context ctx, List followingListMain) { + public MyProfileFollowingAdapter(Context ctx, List followingListMain) { this.context = ctx; this.followingList = followingListMain; @@ -58,14 +64,14 @@ public class ProfileFollowingAdapter extends RecyclerView.Adapter prListMain) { - this.context = context; this.prList = prListMain; } @@ -84,7 +84,6 @@ public class PullRequestsAdapter extends RecyclerView.Adapter { - - Context context = v.getContext(); - Intent intent = new Intent(context, IssueDetailActivity.class); intent.putExtra("issueNumber", pullRequest.getNumber()); intent.putExtra("prMergeable", pullRequest.isMergeable()); @@ -135,19 +131,22 @@ public class PullRequestsAdapter extends RecyclerView.Adapter { - Context context = v.getContext(); - String userLoginId = pullRequest.getUser().getLogin(); - - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", pullRequest.getUser().getLogin()); + context.startActivity(intent); }); + assigneeAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, pullRequest.getUser().getLogin(), context.getString(R.string.copyLoginIdToClipBoard, pullRequest.getUser().getLogin())); + return true; + }); } @SuppressLint("SetTextI18n") void bindData(PullRequests pullRequest) { TinyDB tinyDb = TinyDB.getInstance(context); - String locale = tinyDb.getString("locale"); + Locale locale = context.getResources().getConfiguration().locale; String timeFormat = tinyDb.getString("dateFormat"); int imgRadius = AppUtil.getPixelsFromDensity(context, 3); @@ -165,7 +164,7 @@ public class PullRequestsAdapter extends RecyclerView.Adapter list) { - prList = list; notifyDataSetChanged(); } - } diff --git a/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java index 03ea3a70..279b420f 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java @@ -1,6 +1,7 @@ package org.mian.gitnex.adapters; import android.content.Context; +import android.content.Intent; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; @@ -14,6 +15,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.gitnex.tea4j.models.Releases; import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.ClickListener; @@ -35,6 +37,8 @@ public class ReleasesAdapter extends RecyclerView.Adapter { + Context context = loginId.getContext(); + + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", releases.getAuthor().getLogin()); + context.startActivity(intent); + }); } } @@ -89,11 +101,12 @@ public class ReleasesAdapter extends RecyclerView.Adapter stargazersList; private final Context context; - private static class ViewHolder { + private class ViewHolder { + + private UserInfo userInfo; private final ImageView memberAvatar; private final TextView memberName; @@ -34,6 +38,17 @@ public class RepoStargazersAdapter extends BaseAdapter { ViewHolder(View v) { memberAvatar = v.findViewById(R.id.memberAvatar); memberName = v.findViewById(R.id.memberName); + + memberAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); + + memberAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); } } @@ -80,6 +95,7 @@ public class RepoStargazersAdapter extends BaseAdapter { private void initData(RepoStargazersAdapter.ViewHolder viewHolder, int position) { UserInfo currentItem = stargazersList.get(position); + viewHolder.userInfo = currentItem; int imgRadius = AppUtil.getPixelsFromDensity(context, 3); PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar); diff --git a/app/src/main/java/org/mian/gitnex/adapters/RepoWatchersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/RepoWatchersAdapter.java index 184a43a9..c340c502 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/RepoWatchersAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/RepoWatchersAdapter.java @@ -2,6 +2,7 @@ package org.mian.gitnex.adapters; import android.annotation.SuppressLint; import android.content.Context; +import android.content.Intent; import android.graphics.Typeface; import android.view.LayoutInflater; import android.view.View; @@ -11,6 +12,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.gitnex.tea4j.models.UserInfo; import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.RoundedTransformation; @@ -26,7 +28,9 @@ public class RepoWatchersAdapter extends BaseAdapter { private final List watchersList; private final Context context; - private static class ViewHolder { + private class ViewHolder { + + private UserInfo userInfo; private final ImageView memberAvatar; private final TextView memberName; @@ -34,6 +38,17 @@ public class RepoWatchersAdapter extends BaseAdapter { ViewHolder(View v) { memberAvatar = v.findViewById(R.id.memberAvatar); memberName = v.findViewById(R.id.memberName); + + memberAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); + + memberAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); } } @@ -80,6 +95,7 @@ public class RepoWatchersAdapter extends BaseAdapter { private void initData(RepoWatchersAdapter.ViewHolder viewHolder, int position) { UserInfo currentItem = watchersList.get(position); + viewHolder.userInfo = currentItem; int imgRadius = AppUtil.getPixelsFromDensity(context, 3); PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(180, 180).centerCrop().into(viewHolder.memberAvatar); diff --git a/app/src/main/java/org/mian/gitnex/adapters/ReposListAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ReposListAdapter.java index fdef9dfd..34921dfd 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ReposListAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ReposListAdapter.java @@ -189,7 +189,7 @@ public class ReposListAdapter extends RecyclerView.Adapter teamMembersList; private final Context context; - private static class ViewHolder { + private class ViewHolder { private String userLoginId; @@ -40,10 +42,14 @@ public class TeamMembersByOrgAdapter extends BaseAdapter { memberName = v.findViewById(R.id.memberName); memberAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); - Context context = loginId.getContext(); - + memberAvatar.setOnLongClickListener(loginId -> { AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/UserSearchAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/UserSearchAdapter.java index 8f3b2999..921afd4f 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/UserSearchAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/UserSearchAdapter.java @@ -1,6 +1,7 @@ package org.mian.gitnex.adapters; import android.content.Context; +import android.content.Intent; import android.text.Html; import android.util.Log; import android.view.LayoutInflater; @@ -16,6 +17,7 @@ import org.gitnex.tea4j.models.Collaborators; import org.gitnex.tea4j.models.UserInfo; import org.mian.gitnex.R; import org.mian.gitnex.actions.CollaboratorActions; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.helpers.AlertDialogs; @@ -42,7 +44,7 @@ public class UserSearchAdapter extends RecyclerView.Adapter { - - final Context context = v.getContext(); - AlertDialog.Builder pBuilder = new AlertDialog.Builder(context); pBuilder.setTitle(R.string.newTeamPermission); @@ -89,9 +88,6 @@ public class UserSearchAdapter extends RecyclerView.Adapter { - - Context context = v.getContext(); - AlertDialogs.collaboratorRemoveDialog(context, userInfo.getUsername(), context.getResources().getString(R.string.removeCollaboratorTitle), context.getResources().getString(R.string.removeCollaboratorMessage), @@ -99,6 +95,16 @@ public class UserSearchAdapter extends RecyclerView.Adapter { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); + + userAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java index ad2ca677..9b2f0a72 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java @@ -1,6 +1,7 @@ package org.mian.gitnex.adapters; import android.content.Context; +import android.content.Intent; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -11,6 +12,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import org.gitnex.tea4j.models.UserInfo; import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.helpers.AlertDialogs; @@ -40,7 +42,7 @@ public class UserSearchForTeamMemberAdapter extends RecyclerView.Adapter { - - Context context = v.getContext(); - AlertDialogs.addMemberDialog(context, userInfo.getLogin(), context.getResources().getString(R.string.addTeamMemberTitle), context.getResources().getString(R.string.addTeamMemberMessage), @@ -71,15 +70,23 @@ public class UserSearchForTeamMemberAdapter extends RecyclerView.Adapter { - - Context context = v.getContext(); - AlertDialogs.removeMemberDialog(context, userInfo.getLogin(), context.getResources().getString(R.string.removeTeamMemberTitle), context.getResources().getString(R.string.removeTeamMemberMessage), context.getResources().getString(R.string.removeButton), context.getResources().getString(R.string.cancelButton), Integer.parseInt(String.valueOf(teamId))); }); + + userAvatar.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); + + userAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/profile/FollowersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/profile/FollowersAdapter.java new file mode 100644 index 00000000..0404b681 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/profile/FollowersAdapter.java @@ -0,0 +1,166 @@ +package org.mian.gitnex.adapters.profile; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.RoundedTransformation; +import java.util.List; + +/** + * Author M M Arif + */ + +public class FollowersAdapter extends RecyclerView.Adapter { + + private final Context context; + private final int TYPE_LOAD = 0; + private List usersList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public FollowersAdapter(Context ctx, List usersListMain) { + this.context = ctx; + this.usersList = usersListMain; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + + LayoutInflater inflater = LayoutInflater.from(context); + + if(viewType == TYPE_LOAD) { + return new UsersHolder(inflater.inflate(R.layout.list_profile_followers_following, parent, false)); + } + else { + return new LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((UsersHolder) holder).bindData(usersList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(usersList.get(position).getUsername() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return usersList.size(); + } + + class UsersHolder extends RecyclerView.ViewHolder { + + private UserInfo userInfo; + + private final ImageView userAvatar; + private final TextView userFullName; + private final TextView userName; + + UsersHolder(View itemView) { + + super(itemView); + Context context = itemView.getContext(); + + userAvatar = itemView.findViewById(R.id.userAvatar); + userFullName = itemView.findViewById(R.id.userFullName); + userName = itemView.findViewById(R.id.userName); + + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); + + itemView.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); + } + + @SuppressLint("SetTextI18n") + void bindData(UserInfo userInfo) { + + this.userInfo = userInfo; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + //Locale locale = context.getResources().getConfiguration().locale; + + if(!userInfo.getFullname().equals("")) { + userFullName.setText(Html.fromHtml(userInfo.getFullname())); + userName.setText(context.getResources().getString(R.string.usernameWithAt, userInfo.getUsername())); + } + else { + userFullName.setText(userInfo.getUsername()); + userName.setVisibility(View.GONE); + } + + PicassoService.getInstance(context) + .get() + .load(userInfo.getAvatar()) + .placeholder(R.drawable.loader_animated) + .transform(new RoundedTransformation(imgRadius, 0)) + .resize(120, 120) + .centerCrop() + .into(userAvatar); + } + } + + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + usersList = list; + notifyDataSetChanged(); + } + +} diff --git a/app/src/main/java/org/mian/gitnex/adapters/profile/FollowingAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/profile/FollowingAdapter.java new file mode 100644 index 00000000..d572197a --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/profile/FollowingAdapter.java @@ -0,0 +1,166 @@ +package org.mian.gitnex.adapters.profile; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; +import org.mian.gitnex.activities.ProfileActivity; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.RoundedTransformation; +import java.util.List; + +/** + * Author M M Arif + */ + +public class FollowingAdapter extends RecyclerView.Adapter { + + private final Context context; + private final int TYPE_LOAD = 0; + private List usersList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public FollowingAdapter(Context ctx, List usersListMain) { + this.context = ctx; + this.usersList = usersListMain; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + + LayoutInflater inflater = LayoutInflater.from(context); + + if(viewType == TYPE_LOAD) { + return new UsersHolder(inflater.inflate(R.layout.list_profile_followers_following, parent, false)); + } + else { + return new LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((UsersHolder) holder).bindData(usersList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(usersList.get(position).getUsername() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return usersList.size(); + } + + class UsersHolder extends RecyclerView.ViewHolder { + + private UserInfo userInfo; + + private final ImageView userAvatar; + private final TextView userFullName; + private final TextView userName; + + UsersHolder(View itemView) { + + super(itemView); + Context context = itemView.getContext(); + + userAvatar = itemView.findViewById(R.id.userAvatar); + userFullName = itemView.findViewById(R.id.userFullName); + userName = itemView.findViewById(R.id.userName); + + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); + + itemView.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); + } + + @SuppressLint("SetTextI18n") + void bindData(UserInfo userInfo) { + + this.userInfo = userInfo; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + //Locale locale = context.getResources().getConfiguration().locale; + + if(!userInfo.getFullname().equals("")) { + userFullName.setText(Html.fromHtml(userInfo.getFullname())); + userName.setText(context.getResources().getString(R.string.usernameWithAt, userInfo.getUsername())); + } + else { + userFullName.setText(userInfo.getUsername()); + userName.setVisibility(View.GONE); + } + + PicassoService + .getInstance(context) + .get() + .load(userInfo.getAvatar()) + .placeholder(R.drawable.loader_animated) + .transform(new RoundedTransformation(imgRadius, 0)) + .resize(120, 120) + .centerCrop() + .into(userAvatar); + } + } + + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + usersList = list; + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/adapters/profile/OrganizationsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/profile/OrganizationsAdapter.java new file mode 100644 index 00000000..86d218a9 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/profile/OrganizationsAdapter.java @@ -0,0 +1,137 @@ +package org.mian.gitnex.adapters.profile; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import org.gitnex.tea4j.models.UserOrganizations; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.RoundedTransformation; +import java.util.List; + +/** + * Author M M Arif + */ + +public class OrganizationsAdapter extends RecyclerView.Adapter { + + private final Context context; + private final int TYPE_LOAD = 0; + private List organizationsList; + private RepositoriesAdapter.OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public OrganizationsAdapter(Context ctx, List organizationsListMain) { + this.context = ctx; + this.organizationsList = organizationsListMain; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + + LayoutInflater inflater = LayoutInflater.from(context); + + if(viewType == TYPE_LOAD) { + return new OrganizationsHolder(inflater.inflate(R.layout.list_organizations, parent, false)); + } + else { + return new LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((OrganizationsHolder) holder).bindData(organizationsList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(organizationsList.get(position).getUsername() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return organizationsList.size(); + } + + class OrganizationsHolder extends RecyclerView.ViewHolder { + + private UserOrganizations userOrganizations; + + private final ImageView image; + private final TextView orgName; + private final TextView orgDescription; + + OrganizationsHolder(View itemView) { + + super(itemView); + orgName = itemView.findViewById(R.id.orgName); + orgDescription = itemView.findViewById(R.id.orgDescription); + image = itemView.findViewById(R.id.imageAvatar); + } + + @SuppressLint("SetTextI18n") + void bindData(UserOrganizations userOrganizations) { + + this.userOrganizations = userOrganizations; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + orgName.setText(userOrganizations.getUsername()); + + PicassoService.getInstance(context).get().load(userOrganizations.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(image); + + if (!userOrganizations.getDescription().equals("")) { + orgDescription.setText(userOrganizations.getDescription()); + } + } + } + + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(RepositoriesAdapter.OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + organizationsList = list; + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/adapters/profile/RepositoriesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/profile/RepositoriesAdapter.java new file mode 100644 index 00000000..7e33b0b1 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/profile/RepositoriesAdapter.java @@ -0,0 +1,196 @@ +package org.mian.gitnex.adapters.profile; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Typeface; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; +import org.gitnex.tea4j.models.UserRepositories; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.ClickListener; +import org.mian.gitnex.helpers.RoundedTransformation; +import org.mian.gitnex.helpers.TimeHelper; +import org.mian.gitnex.helpers.TinyDB; +import java.util.List; +import java.util.Locale; + +/** + * Author M M Arif + */ + +public class RepositoriesAdapter extends RecyclerView.Adapter { + + private final Context context; + private final int TYPE_LOAD = 0; + private List reposList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public RepositoriesAdapter(Context ctx, List reposListMain) { + this.context = ctx; + this.reposList = reposListMain; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + + LayoutInflater inflater = LayoutInflater.from(context); + + if(viewType == TYPE_LOAD) { + return new RepositoriesAdapter.RepositoriesHolder(inflater.inflate(R.layout.list_repositories, parent, false)); + } + else { + return new RepositoriesAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((RepositoriesAdapter.RepositoriesHolder) holder).bindData(reposList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(reposList.get(position).getFullName() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return reposList.size(); + } + + class RepositoriesHolder extends RecyclerView.ViewHolder { + + private UserRepositories userRepositories; + + private final ImageView avatar; + private final TextView repoName; + private final TextView orgName; + private final TextView repoDescription; + private CheckBox isRepoAdmin; + private final TextView repoStars; + private final TextView repoLastUpdated; + + RepositoriesHolder(View itemView) { + + super(itemView); + repoName = itemView.findViewById(R.id.repoName); + orgName = itemView.findViewById(R.id.orgName); + repoDescription = itemView.findViewById(R.id.repoDescription); + isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin); + avatar = itemView.findViewById(R.id.imageAvatar); + repoStars = itemView.findViewById(R.id.repoStars); + repoLastUpdated = itemView.findViewById(R.id.repoLastUpdated); + } + + @SuppressLint("SetTextI18n") + void bindData(UserRepositories userRepositories) { + + this.userRepositories = userRepositories; + TinyDB tinyDb = TinyDB.getInstance(context); + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + Locale locale = context.getResources().getConfiguration().locale; + String timeFormat = tinyDb.getString("dateFormat"); + + orgName.setText(userRepositories.getFullName().split("/")[0]); + repoName.setText(userRepositories.getFullName().split("/")[1]); + repoStars.setText(userRepositories.getStars_count()); + + ColorGenerator generator = ColorGenerator.MATERIAL; + int color = generator.getColor(userRepositories.getName()); + String firstCharacter = String.valueOf(userRepositories.getFullName().charAt(0)); + + TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3); + + if(userRepositories.getAvatar_url() != null) { + if(!userRepositories.getAvatar_url().equals("")) { + PicassoService + .getInstance(context).get().load(userRepositories.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(avatar); + } + else { + avatar.setImageDrawable(drawable); + } + } + else { + avatar.setImageDrawable(drawable); + } + + if(userRepositories.getUpdated_at() != null) { + + repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, TimeHelper.formatTime(userRepositories.getUpdated_at(), locale, timeFormat, context))); + if(timeFormat.equals("pretty")) { + repoLastUpdated.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(userRepositories.getUpdated_at()), context)); + } + } + else { + repoLastUpdated.setVisibility(View.GONE); + } + + if(!userRepositories.getDescription().equals("")) { + repoDescription.setText(userRepositories.getDescription()); + } + else { + repoDescription.setText(context.getString(R.string.noDataDescription)); + } + + if(isRepoAdmin == null) { + isRepoAdmin = new CheckBox(context); + } + isRepoAdmin.setChecked(userRepositories.getPermissions().isAdmin()); + + } + } + + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + reposList = list; + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/adapters/profile/StarredRepositoriesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/profile/StarredRepositoriesAdapter.java new file mode 100644 index 00000000..204a19be --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/profile/StarredRepositoriesAdapter.java @@ -0,0 +1,197 @@ +package org.mian.gitnex.adapters.profile; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Typeface; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; +import org.gitnex.tea4j.models.UserRepositories; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.ClickListener; +import org.mian.gitnex.helpers.RoundedTransformation; +import org.mian.gitnex.helpers.TimeHelper; +import org.mian.gitnex.helpers.TinyDB; +import java.util.List; +import java.util.Locale; + +/** + * Author M M Arif + */ + +public class StarredRepositoriesAdapter extends RecyclerView.Adapter { + + private final Context context; + private final int TYPE_LOAD = 0; + private List reposList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public StarredRepositoriesAdapter(Context ctx, List reposListMain) { + this.context = ctx; + this.reposList = reposListMain; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + + LayoutInflater inflater = LayoutInflater.from(context); + + if(viewType == TYPE_LOAD) { + return new StarredRepositoriesAdapter.StarredRepositoriesHolder(inflater.inflate(R.layout.list_repositories, parent, false)); + } + else { + return new StarredRepositoriesAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((StarredRepositoriesAdapter.StarredRepositoriesHolder) holder).bindData(reposList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(reposList.get(position).getFullName() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return reposList.size(); + } + + class StarredRepositoriesHolder extends RecyclerView.ViewHolder { + + private UserRepositories userRepositories; + + private final ImageView avatar; + private final TextView repoName; + private final TextView orgName; + private final TextView repoDescription; + private CheckBox isRepoAdmin; + private final TextView repoStars; + private final TextView repoLastUpdated; + + StarredRepositoriesHolder(View itemView) { + + super(itemView); + repoName = itemView.findViewById(R.id.repoName); + orgName = itemView.findViewById(R.id.orgName); + repoDescription = itemView.findViewById(R.id.repoDescription); + isRepoAdmin = itemView.findViewById(R.id.repoIsAdmin); + avatar = itemView.findViewById(R.id.imageAvatar); + repoStars = itemView.findViewById(R.id.repoStars); + repoLastUpdated = itemView.findViewById(R.id.repoLastUpdated); + } + + @SuppressLint("SetTextI18n") + void bindData(UserRepositories userRepositories) { + + this.userRepositories = userRepositories; + TinyDB tinyDb = TinyDB.getInstance(context); + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + Locale locale = context.getResources().getConfiguration().locale; + String timeFormat = tinyDb.getString("dateFormat"); + + orgName.setText(userRepositories.getFullName().split("/")[0]); + repoName.setText(userRepositories.getFullName().split("/")[1]); + repoStars.setText(userRepositories.getStars_count()); + + ColorGenerator generator = ColorGenerator.MATERIAL; + int color = generator.getColor(userRepositories.getName()); + String firstCharacter = String.valueOf(userRepositories.getFullName().charAt(0)); + + TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3); + + if(userRepositories.getAvatar_url() != null) { + if(!userRepositories.getAvatar_url().equals("")) { + PicassoService + .getInstance(context).get().load(userRepositories.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(avatar); + } + else { + avatar.setImageDrawable(drawable); + } + } + else { + avatar.setImageDrawable(drawable); + } + + if(userRepositories.getUpdated_at() != null) { + + repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, TimeHelper + .formatTime(userRepositories.getUpdated_at(), locale, timeFormat, context))); + if(timeFormat.equals("pretty")) { + repoLastUpdated.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(userRepositories.getUpdated_at()), context)); + } + } + else { + repoLastUpdated.setVisibility(View.GONE); + } + + if(!userRepositories.getDescription().equals("")) { + repoDescription.setText(userRepositories.getDescription()); + } + else { + repoDescription.setText(context.getString(R.string.noDataDescription)); + } + + if(isRepoAdmin == null) { + isRepoAdmin = new CheckBox(context); + } + isRepoAdmin.setChecked(userRepositories.getPermissions().isAdmin()); + + } + } + + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + reposList = list; + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/core/MainApplication.java b/app/src/main/java/org/mian/gitnex/core/MainApplication.java index cb921174..7142a2e6 100644 --- a/app/src/main/java/org/mian/gitnex/core/MainApplication.java +++ b/app/src/main/java/org/mian/gitnex/core/MainApplication.java @@ -152,5 +152,20 @@ public class MainApplication extends Application { tinyDB.putInt("homeScreenId", 0); } + if(tinyDB.getString("localeStr").isEmpty()) { + tinyDB.putString("localeStr", getString(R.string.settingsLanguageSystem)); + tinyDB.putInt("langId", 0); + } + + if(tinyDB.getInt("darkThemeTimeHour", 100) == 100) { + tinyDB.putInt("lightThemeTimeHour", 6); + tinyDB.putInt("lightThemeTimeMinute", 0); + tinyDB.putInt("darkThemeTimeHour", 18); + tinyDB.putInt("darkThemeTimeMinute", 0); + } + + if(tinyDB.getString("timeStr").isEmpty()) { + tinyDB.putString("timeStr", getString(R.string.settingsDateTimeHeaderDefault)); + } } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/AboutFragment.java b/app/src/main/java/org/mian/gitnex/fragments/AboutFragment.java deleted file mode 100644 index c26aeb9f..00000000 --- a/app/src/main/java/org/mian/gitnex/fragments/AboutFragment.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.mian.gitnex.fragments; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import org.mian.gitnex.R; -import org.mian.gitnex.activities.MainActivity; -import org.mian.gitnex.databinding.FragmentAboutBinding; -import org.mian.gitnex.helpers.AppUtil; -import org.mian.gitnex.helpers.TinyDB; - -/** - * Author M M Arif - */ - -public class AboutFragment extends Fragment { - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - FragmentAboutBinding viewBinding = FragmentAboutBinding.inflate(inflater, container, false); - TinyDB tinyDb = TinyDB.getInstance(getContext()); - - viewBinding.appVersion.setText(AppUtil.getAppVersion(requireContext())); - viewBinding.userServerVersion.setText(tinyDb.getString("giteaVersion")); - viewBinding.appBuild.setText(String.valueOf(AppUtil.getAppBuildNo(requireContext()))); - - ((MainActivity) requireActivity()).setActionBarTitle(getResources().getString(R.string.pageTitleAbout)); - - viewBinding.donationLinkPatreon.setOnClickListener(v12 -> { - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setData(Uri.parse(getResources().getString(R.string.supportLinkPatreon))); - startActivity(intent); - }); - - viewBinding.translateLink.setOnClickListener(v13 -> { - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink))); - startActivity(intent); - }); - - viewBinding.appWebsite.setOnClickListener(v14 -> { - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setData(Uri.parse(getResources().getString(R.string.appWebsiteLink))); - startActivity(intent); - }); - - if(AppUtil.isPro(requireContext())) { - - viewBinding.supportHeader.setVisibility(View.GONE); - viewBinding.dividerSupport.setVisibility(View.GONE); - viewBinding.donationLinkPatreon.setVisibility(View.GONE); - } - - return viewBinding.getRoot(); - } - -} diff --git a/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java b/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java index 976fc950..7377e218 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java @@ -40,6 +40,16 @@ public class AdministrationFragment extends Fragment { fragmentAdministrationBinding.adminCron.setOnClickListener(v1 -> startActivity(new Intent(getContext(), AdminCronTasksActivity.class))); + String action = requireActivity().getIntent().getStringExtra("giteaAdminAction"); + if(action != null) { + if(action.equals("users")) { + startActivity(new Intent(getContext(), AdminGetUsersActivity.class)); + } + else if(action.equals("monitor")) { + startActivity(new Intent(getContext(), AdminCronTasksActivity.class)); + } + } + return fragmentAdministrationBinding.getRoot(); } diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetProfileFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetMyProfileFragment.java similarity index 80% rename from app/src/main/java/org/mian/gitnex/fragments/BottomSheetProfileFragment.java rename to app/src/main/java/org/mian/gitnex/fragments/BottomSheetMyProfileFragment.java index 19fce304..1551baa0 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetProfileFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetMyProfileFragment.java @@ -8,14 +8,14 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; -import org.mian.gitnex.activities.ProfileEmailActivity; +import org.mian.gitnex.activities.MyProfileEmailActivity; import org.mian.gitnex.databinding.BottomSheetProfileBinding; /** * Author M M Arif */ -public class BottomSheetProfileFragment extends BottomSheetDialogFragment { +public class BottomSheetMyProfileFragment extends BottomSheetDialogFragment { @Nullable @Override @@ -25,7 +25,7 @@ public class BottomSheetProfileFragment extends BottomSheetDialogFragment { bottomSheetProfileBinding.addNewEmailAddress.setOnClickListener(v1 -> { - startActivity(new Intent(getContext(), ProfileEmailActivity.class)); + startActivity(new Intent(getContext(), MyProfileEmailActivity.class)); dismiss(); }); diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java index a0e5778d..b678c96a 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java @@ -13,17 +13,24 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.google.gson.JsonElement; import org.mian.gitnex.R; import org.mian.gitnex.actions.IssueActions; +import org.mian.gitnex.actions.PullRequestActions; import org.mian.gitnex.activities.EditIssueActivity; import org.mian.gitnex.activities.FileDiffActivity; import org.mian.gitnex.activities.MergePullRequestActivity; +import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.BottomSheetSingleIssueBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Version; import org.mian.gitnex.views.ReactionSpinner; import java.util.Objects; +import retrofit2.Call; +import retrofit2.Callback; /** * Author M M Arif @@ -50,6 +57,7 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment { TextView copyIssueUrl = bottomSheetSingleIssueBinding.copyIssueUrl; TextView openFilesDiff = bottomSheetSingleIssueBinding.openFilesDiff; TextView mergePullRequest = bottomSheetSingleIssueBinding.mergePullRequest; + TextView deletePullRequestBranch = bottomSheetSingleIssueBinding.deletePrHeadBranch; TextView shareIssue = bottomSheetSingleIssueBinding.shareIssue; TextView subscribeIssue = bottomSheetSingleIssueBinding.subscribeIssue; TextView unsubscribeIssue = bottomSheetSingleIssueBinding.unsubscribeIssue; @@ -85,9 +93,11 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment { if(tinyDB.getBoolean("prMerged") || tinyDB.getString("repoPrState").equals("closed")) { mergePullRequest.setVisibility(View.GONE); + deletePullRequestBranch.setVisibility(View.VISIBLE); } else { mergePullRequest.setVisibility(View.VISIBLE); + deletePullRequestBranch.setVisibility(View.GONE); } if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.13.0")) { @@ -104,6 +114,7 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment { else { mergePullRequest.setVisibility(View.GONE); + deletePullRequestBranch.setVisibility(View.GONE); } mergePullRequest.setOnClickListener(v13 -> { @@ -112,6 +123,12 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment { dismiss(); }); + deletePullRequestBranch.setOnClickListener(v -> { + + PullRequestActions.deleteHeadBranch(ctx, parts[0], parts[1], tinyDB.getString("prHeadBranch"), true); + dismiss(); + }); + openFilesDiff.setOnClickListener(v14 -> { startActivity(new Intent(ctx, FileDiffActivity.class)); diff --git a/app/src/main/java/org/mian/gitnex/fragments/ExploreFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExploreFragment.java index 58544f8f..d9f2629c 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ExploreFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ExploreFragment.java @@ -24,9 +24,6 @@ import org.mian.gitnex.helpers.TinyDB; public class ExploreFragment extends Fragment { - private Context ctx; - private TinyDB tinyDB; - private int tabsCount; public ViewPager mViewPager; @@ -36,8 +33,8 @@ public class ExploreFragment extends Fragment { View view = inflater.inflate(R.layout.fragment_explore, container, false); - ctx = getContext(); - tinyDB = TinyDB.getInstance(ctx); + Context ctx = getContext(); + TinyDB tinyDB = TinyDB.getInstance(ctx); ((MainActivity) requireActivity()).setActionBarTitle(getResources().getString(R.string.navExplore)); @@ -87,6 +84,10 @@ public class ExploreFragment extends Fragment { SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager()); mViewPager.setAdapter(mSectionsPagerAdapter); + if(requireActivity().getIntent().getBooleanExtra("exploreOrgs", false)) { + mViewPager.setCurrentItem(2); + } + return view; } @@ -111,7 +112,11 @@ public class ExploreFragment extends Fragment { break; case 1: // Issues - fragment = new SearchIssuesFragment(); + fragment = new ExploreIssuesFragment(); + break; + + case 2: // Organizations + fragment = new ExplorePublicOrganizationsFragment(); break; } diff --git a/app/src/main/java/org/mian/gitnex/fragments/SearchIssuesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java similarity index 91% rename from app/src/main/java/org/mian/gitnex/fragments/SearchIssuesFragment.java rename to app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java index 374dc47c..47b414c4 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/SearchIssuesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java @@ -13,13 +13,12 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import org.gitnex.tea4j.models.Issues; -import org.mian.gitnex.adapters.SearchIssuesAdapter; +import org.mian.gitnex.adapters.ExploreIssuesAdapter; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentSearchIssuesBinding; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.InfiniteScrollListener; -import org.mian.gitnex.helpers.TinyDB; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -31,30 +30,25 @@ import retrofit2.Response; * Author M M Arif */ -public class SearchIssuesFragment extends Fragment { +public class ExploreIssuesFragment extends Fragment { - private Context ctx; - private TinyDB tinyDb; private FragmentSearchIssuesBinding viewBinding; - private SearchIssuesAdapter adapter; + private ExploreIssuesAdapter adapter; private List dataList; + Context ctx; private int apiCallCurrentValue = 10; private int pageCurrentIndex = 1; - private String type = "issues"; - private String state = "open"; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { viewBinding = FragmentSearchIssuesBinding.inflate(inflater, container, false); setHasOptionsMenu(true); - ctx = getContext(); - tinyDb = TinyDB.getInstance(getContext()); dataList = new ArrayList<>(); - adapter = new SearchIssuesAdapter(dataList, ctx); + adapter = new ExploreIssuesAdapter(dataList, ctx); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx); @@ -65,11 +59,8 @@ public class SearchIssuesFragment extends Fragment { viewBinding.recyclerViewSearchIssues.setAdapter(adapter); viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> { - if(actionId == EditorInfo.IME_ACTION_SEND) { - if(!Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString().equals("")) { - InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0); @@ -79,27 +70,21 @@ public class SearchIssuesFragment extends Fragment { loadData(false, viewBinding.searchKeyword.getText().toString()); } } - return false; }); viewBinding.recyclerViewSearchIssues.addOnScrollListener(new InfiniteScrollListener(pageCurrentIndex, linearLayoutManager) { - @Override public void onScrolledToEnd(int firstVisibleItemPosition) { - pageCurrentIndex++; loadData(true, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString()); - } }); viewBinding.pullToRefresh.setOnRefreshListener(() -> { - pageCurrentIndex = 1; apiCallCurrentValue = 10; loadData(false, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString()); - }); loadData(false, ""); @@ -117,69 +102,50 @@ public class SearchIssuesFragment extends Fragment { } if(pageCurrentIndex == 1 || !append) { - dataList.clear(); adapter.notifyDataSetChanged(); viewBinding.pullToRefresh.setRefreshing(false); viewBinding.progressBar.setVisibility(View.VISIBLE); } else { - viewBinding.loadingMoreView.setVisibility(View.VISIBLE); } Call> call = RetrofitClient.getApiInterface(getContext()) - .queryIssues(Authorization.get(getContext()), searchKeyword, type, state, pageCurrentIndex); + .queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", pageCurrentIndex); call.enqueue(new Callback>() { - @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if(response.code() == 200) { - assert response.body() != null; apiCallCurrentValue = response.body().size(); - if(!append) { - dataList.clear(); } - dataList.addAll(response.body()); adapter.notifyDataSetChanged(); - } else { - dataList.clear(); adapter.notifyDataChanged(); viewBinding.noData.setVisibility(View.VISIBLE); - } - onCleanup(); - } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.e("onFailure", Objects.requireNonNull(t.getMessage())); onCleanup(); - } private void onCleanup() { - AppUtil.setMultiVisibility(View.GONE, viewBinding.loadingMoreView, viewBinding.progressBar); - if(dataList.isEmpty()) { - viewBinding.noData.setVisibility(View.VISIBLE); } } }); } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java new file mode 100644 index 00000000..27a60b71 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java @@ -0,0 +1,160 @@ +package org.mian.gitnex.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.models.Organization; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.ExplorePublicOrganizationsAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentOrganizationsBinding; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Version; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class ExplorePublicOrganizationsFragment extends Fragment { + + private FragmentOrganizationsBinding fragmentPublicOrgBinding; + private List organizationsList; + private ExplorePublicOrganizationsAdapter adapter; + private Context context; + private int pageSize; + private final String TAG = Constants.publicOrganizations; + private int resultLimit = Constants.resultLimitOldGiteaInstances; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + fragmentPublicOrgBinding = FragmentOrganizationsBinding.inflate(inflater, container, false); + context = getContext(); + + TinyDB tinyDb = TinyDB.getInstance(getContext()); + final String loginUid = tinyDb.getString("loginUid"); + final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); + + // if gitea is 1.12 or higher use the new limit + if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + fragmentPublicOrgBinding.addNewOrganization.setVisibility(View.GONE); + organizationsList = new ArrayList<>(); + + fragmentPublicOrgBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentPublicOrgBinding.pullToRefresh.setRefreshing(false); + loadInitial(instanceToken, resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter = new ExplorePublicOrganizationsAdapter(getContext(), organizationsList); + adapter.setLoadMoreListener(() -> fragmentPublicOrgBinding.recyclerView.post(() -> { + if(organizationsList.size() == resultLimit || pageSize == resultLimit) { + int page = (organizationsList.size() + resultLimit) / resultLimit; + loadMore(Authorization.get(getContext()), page, resultLimit); + } + })); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentPublicOrgBinding.recyclerView.getContext(), DividerItemDecoration.VERTICAL); + fragmentPublicOrgBinding.recyclerView.setHasFixedSize(true); + fragmentPublicOrgBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentPublicOrgBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentPublicOrgBinding.recyclerView.setAdapter(adapter); + + loadInitial(Authorization.get(getContext()), resultLimit); + + return fragmentPublicOrgBinding.getRoot(); + } + + private void loadInitial(String token, int resultLimit) { + + Call> call = RetrofitClient + .getApiInterface(context).getAllOrgs(token, Constants.publicOrganizationsPageInit, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + if(response.body() != null && response.body().size() > 0) { + organizationsList.clear(); + organizationsList.addAll(response.body()); + adapter.notifyDataChanged(); + fragmentPublicOrgBinding.noDataOrg.setVisibility(View.GONE); + } + else { + organizationsList.clear(); + adapter.notifyDataChanged(); + fragmentPublicOrgBinding.noDataOrg.setVisibility(View.VISIBLE); + } + fragmentPublicOrgBinding.progressBar.setVisibility(View.GONE); + } + else if(response.code() == 404) { + fragmentPublicOrgBinding.noDataOrg.setVisibility(View.VISIBLE); + fragmentPublicOrgBinding.progressBar.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } + + private void loadMore(String token, int page, int resultLimit) { + + fragmentPublicOrgBinding.progressLoadMore.setVisibility(View.VISIBLE); + Call> call = RetrofitClient.getApiInterface(context).getAllOrgs(token, page, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + List result = response.body(); + if(result != null) { + if(result.size() > 0) { + pageSize = result.size(); + organizationsList.addAll(result); + } + else { + SnackBar.info(context, fragmentPublicOrgBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + } + adapter.notifyDataChanged(); + fragmentPublicOrgBinding.progressLoadMore.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java index e09cbb05..980edc01 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java @@ -261,54 +261,21 @@ public class ExploreRepositoriesFragment extends Fragment { dialogFilterOptions.setContentView(view); filterBinding.includeTopic.setOnClickListener(includeTopic -> { - - if(filterBinding.includeTopic.isChecked()) { - - tinyDb.putBoolean("exploreRepoIncludeTopic", true); - } - else { - - tinyDb.putBoolean("exploreRepoIncludeTopic", false); - } + tinyDb.putBoolean("exploreRepoIncludeTopic", filterBinding.includeTopic.isChecked()); }); filterBinding.includeDesc.setOnClickListener(includeDesc -> { - - if(filterBinding.includeDesc.isChecked()) { - - tinyDb.putBoolean("exploreRepoIncludeDescription", true); - } - else { - - tinyDb.putBoolean("exploreRepoIncludeDescription", false); - } + tinyDb.putBoolean("exploreRepoIncludeDescription", filterBinding.includeDesc.isChecked()); }); filterBinding.includeTemplate.setOnClickListener(includeTemplate -> { - - if(filterBinding.includeTemplate.isChecked()) { - - tinyDb.putBoolean("exploreRepoIncludeTemplate", true); - } - else { - - tinyDb.putBoolean("exploreRepoIncludeTemplate", false); - } + tinyDb.putBoolean("exploreRepoIncludeTemplate", filterBinding.includeTemplate.isChecked()); }); filterBinding.onlyArchived.setOnClickListener(onlyArchived -> { - - if(filterBinding.onlyArchived.isChecked()) { - - tinyDb.putBoolean("exploreRepoOnlyArchived", true); - } - else { - - tinyDb.putBoolean("exploreRepoOnlyArchived", false); - } + tinyDb.putBoolean("exploreRepoOnlyArchived", filterBinding.onlyArchived.isChecked()); }); - filterBinding.includeTopic.setChecked(tinyDb.getBoolean("exploreRepoIncludeTopic")); filterBinding.includeDesc.setChecked(tinyDb.getBoolean("exploreRepoIncludeDescription")); filterBinding.includeTemplate.setChecked(tinyDb.getBoolean("exploreRepoIncludeTemplate")); diff --git a/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java index 4d381550..1f7c0ec4 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/FilesFragment.java @@ -130,7 +130,17 @@ public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapter }); - fetchDataAsync(Authorization.get(getContext()), repoOwner, repoName, ref); + String dir = requireActivity().getIntent().getStringExtra("dir"); + if(dir != null) { + fetchDataAsyncSub(Authorization.get(getContext()), repoOwner, repoName, dir, ref); + for(String segment: dir.split("/")) { + binding.breadcrumbsView.addItem(new BreadcrumbItem(Collections.singletonList(segment))); + path.add(segment); + } + } + else { + fetchDataAsync(Authorization.get(getContext()), repoOwner, repoName, ref); + } return binding.getRoot(); } diff --git a/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java index 88095d88..eda404ac 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java @@ -29,8 +29,8 @@ import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentIssuesBinding; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.TinyDB; -import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; @@ -44,6 +44,7 @@ import retrofit2.Response; public class IssuesFragment extends Fragment { + private FragmentIssuesBinding fragmentIssuesBinding; private Menu menu; private RecyclerView recyclerView; private List issuesList; @@ -51,18 +52,17 @@ public class IssuesFragment extends Fragment { private Context context; private int pageSize = Constants.issuesPageInit; private ProgressBar mProgressBar; - private String TAG = Constants.tagIssuesList; + private final String TAG = Constants.tagIssuesList; private TextView noDataIssues; private int resultLimit = Constants.resultLimitOldGiteaInstances; - private String requestType = Constants.issuesRequestType; + private final String requestType = Constants.issuesRequestType; private ProgressBar progressLoadMore; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - FragmentIssuesBinding fragmentIssuesBinding = FragmentIssuesBinding.inflate(inflater, container, false); - + fragmentIssuesBinding = FragmentIssuesBinding.inflate(inflater, container, false); setHasOptionsMenu(true); context = getContext(); @@ -89,23 +89,17 @@ public class IssuesFragment extends Fragment { noDataIssues = fragmentIssuesBinding.noDataIssues; swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { - swipeRefresh.setRefreshing(false); loadInitial(instanceToken, repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState")); adapter.notifyDataChanged(); - }, 200)); adapter = new IssuesAdapter(getContext(), issuesList); adapter.setLoadMoreListener(() -> recyclerView.post(() -> { - if(issuesList.size() == resultLimit || pageSize == resultLimit) { - int page = (issuesList.size() + resultLimit) / resultLimit; loadMore(Authorization.get(getContext()), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState")); - } - })); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL); @@ -129,12 +123,9 @@ public class IssuesFragment extends Fragment { adapter.setLoadMoreListener(() -> recyclerView.post(() -> { if(issuesList.size() == resultLimit || pageSize == resultLimit) { - int page = (issuesList.size() + resultLimit) / resultLimit; loadMore(Authorization.get(getContext()), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState")); - } - })); tinyDb.putString("repoIssuesState", issueState); @@ -144,13 +135,11 @@ public class IssuesFragment extends Fragment { loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, issueState); recyclerView.setAdapter(adapter); - }); loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState")); return fragmentIssuesBinding.getRoot(); - } @Override @@ -165,11 +154,9 @@ public class IssuesFragment extends Fragment { final String repoName = parts[1]; if(tinyDb.getBoolean("resumeIssues")) { - loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState")); tinyDb.putBoolean("resumeIssues", false); } - } private void loadInitial(String token, String repoOwner, String repoName, int resultLimit, String requestType, String issueState) { @@ -177,49 +164,38 @@ public class IssuesFragment extends Fragment { Call> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, 1, resultLimit, requestType, issueState); call.enqueue(new Callback>() { - @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { if(response.code() == 200) { - assert response.body() != null; if(response.body().size() > 0) { - issuesList.clear(); issuesList.addAll(response.body()); adapter.notifyDataChanged(); noDataIssues.setVisibility(View.GONE); } else { - issuesList.clear(); adapter.notifyDataChanged(); noDataIssues.setVisibility(View.VISIBLE); } - mProgressBar.setVisibility(View.GONE); - } else if(response.code() == 404) { - noDataIssues.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); } else { Log.e(TAG, String.valueOf(response.code())); } - } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.e(TAG, t.toString()); } - }); - } private void loadMore(String token, String repoOwner, String repoName, int page, int resultLimit, String requestType, String issueState) { @@ -232,44 +208,29 @@ public class IssuesFragment extends Fragment { @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if(response.code() == 200) { - List result = response.body(); - assert result != null; if(result.size() > 0) { - pageSize = result.size(); issuesList.addAll(result); - } else { - - Toasty.warning(context, getString(R.string.noMoreData)); + SnackBar.info(context, fragmentIssuesBinding.getRoot(), getString(R.string.noMoreData)); adapter.setMoreDataAvailable(false); - } - adapter.notifyDataChanged(); progressLoadMore.setVisibility(View.GONE); - } else { - Log.e(TAG, String.valueOf(response.code())); - } - } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.e(TAG, t.toString()); - } - }); } @@ -298,19 +259,15 @@ public class IssuesFragment extends Fragment { @Override public boolean onQueryTextSubmit(String query) { - return false; } @Override public boolean onQueryTextChange(String newText) { - filter(newText); return false; } - }); - } private void filter(String text) { @@ -328,5 +285,4 @@ public class IssuesFragment extends Fragment { adapter.updateList(arr); } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/MilestonesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MilestonesFragment.java index ca4512cc..703638a9 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/MilestonesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MilestonesFragment.java @@ -48,6 +48,8 @@ public class MilestonesFragment extends Fragment { private String TAG = Constants.tagMilestonesFragment; private int resultLimit = Constants.resultLimitOldGiteaInstances; + private String milestoneId; + @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -63,6 +65,9 @@ public class MilestonesFragment extends Fragment { final String loginUid = tinyDb.getString("loginUid"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); + milestoneId = requireActivity().getIntent().getStringExtra("milestoneId"); + requireActivity().getIntent().removeExtra("milestoneId"); + viewBinding.recyclerView.setHasFixedSize(true); viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); @@ -188,6 +193,10 @@ public class MilestonesFragment extends Fragment { adapter.notifyDataChanged(); viewBinding.noDataMilestone.setVisibility(View.GONE); + if(milestoneId != null) { + viewBinding.recyclerView.scrollToPosition(getMilestoneIndex(Integer.parseInt(milestoneId), response.body())); + } + } else { @@ -216,6 +225,15 @@ public class MilestonesFragment extends Fragment { } + private static int getMilestoneIndex(int milestoneId, List milestones) { + for (Milestones milestone : milestones) { + if(milestone.getId() == milestoneId) { + return milestones.indexOf(milestone); + } + } + return -1; + } + private void loadMore(String token, String repoOwner, String repoName, int page, int resultLimit, String milestoneState) { viewBinding.progressLoadMore.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/mian/gitnex/fragments/ProfileEmailsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileEmailsFragment.java similarity index 90% rename from app/src/main/java/org/mian/gitnex/fragments/ProfileEmailsFragment.java rename to app/src/main/java/org/mian/gitnex/fragments/MyProfileEmailsFragment.java index 90101c4e..e310e0aa 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ProfileEmailsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileEmailsFragment.java @@ -18,7 +18,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.gitnex.tea4j.models.Emails; -import org.mian.gitnex.adapters.ProfileEmailsAdapter; +import org.mian.gitnex.adapters.MyProfileEmailsAdapter; import org.mian.gitnex.databinding.FragmentProfileEmailsBinding; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.viewmodels.ProfileEmailsViewModel; @@ -28,10 +28,10 @@ import java.util.List; * Author M M Arif */ -public class ProfileEmailsFragment extends Fragment { +public class MyProfileEmailsFragment extends Fragment { private ProgressBar mProgressBar; - private ProfileEmailsAdapter adapter; + private MyProfileEmailsAdapter adapter; private RecyclerView mRecyclerView; private TextView noDataEmails; private static String repoNameF = "param2"; @@ -42,11 +42,11 @@ public class ProfileEmailsFragment extends Fragment { private OnFragmentInteractionListener mListener; - public ProfileEmailsFragment() { + public MyProfileEmailsFragment() { } - public static ProfileEmailsFragment newInstance(String param1, String param2) { - ProfileEmailsFragment fragment = new ProfileEmailsFragment(); + public static MyProfileEmailsFragment newInstance(String param1, String param2) { + MyProfileEmailsFragment fragment = new MyProfileEmailsFragment(); Bundle args = new Bundle(); args.putString(repoOwnerF, param1); args.putString(repoNameF, param2); @@ -102,7 +102,7 @@ public class ProfileEmailsFragment extends Fragment { profileEmailModel.getEmailsList(instanceToken, getContext()).observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(@Nullable List emailsListMain) { - adapter = new ProfileEmailsAdapter(getContext(), emailsListMain); + adapter = new MyProfileEmailsAdapter(getContext(), emailsListMain); if(adapter.getItemCount() > 0) { mRecyclerView.setAdapter(adapter); noDataEmails.setVisibility(View.GONE); diff --git a/app/src/main/java/org/mian/gitnex/fragments/ProfileFollowersFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java similarity index 77% rename from app/src/main/java/org/mian/gitnex/fragments/ProfileFollowersFragment.java rename to app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java index 68d3ebaa..4f42ec81 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ProfileFollowersFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java @@ -16,8 +16,8 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import org.mian.gitnex.adapters.ProfileFollowersAdapter; -import org.mian.gitnex.databinding.FragmentProfileFollowersBinding; +import org.mian.gitnex.adapters.MyProfileFollowersAdapter; +import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.viewmodels.ProfileFollowersViewModel; @@ -25,10 +25,10 @@ import org.mian.gitnex.viewmodels.ProfileFollowersViewModel; * Author M M Arif */ -public class ProfileFollowersFragment extends Fragment { +public class MyProfileFollowersFragment extends Fragment { private ProgressBar mProgressBar; - private ProfileFollowersAdapter adapter; + private MyProfileFollowersAdapter adapter; private RecyclerView mRecyclerView; private TextView noDataFollowers; private static String repoNameF = "param2"; @@ -39,11 +39,11 @@ public class ProfileFollowersFragment extends Fragment { private OnFragmentInteractionListener mListener; - public ProfileFollowersFragment() { + public MyProfileFollowersFragment() { } - public static ProfileFollowersFragment newInstance(String param1, String param2) { - ProfileFollowersFragment fragment = new ProfileFollowersFragment(); + public static MyProfileFollowersFragment newInstance(String param1, String param2) { + MyProfileFollowersFragment fragment = new MyProfileFollowersFragment(); Bundle args = new Bundle(); args.putString(repoOwnerF, param1); args.putString(repoNameF, param2); @@ -64,12 +64,12 @@ public class ProfileFollowersFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - FragmentProfileFollowersBinding fragmentProfileFollowersBinding = FragmentProfileFollowersBinding.inflate(inflater, container, false); + FragmentProfileFollowersFollowingBinding fragmentProfileFollowersFollowingBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); - final SwipeRefreshLayout swipeRefresh = fragmentProfileFollowersBinding.pullToRefresh; + final SwipeRefreshLayout swipeRefresh = fragmentProfileFollowersFollowingBinding.pullToRefresh; - noDataFollowers = fragmentProfileFollowersBinding.noDataFollowers; - mRecyclerView = fragmentProfileFollowersBinding.recyclerView; + noDataFollowers = fragmentProfileFollowersFollowingBinding.noData; + mRecyclerView = fragmentProfileFollowersFollowingBinding.recyclerView; DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL); @@ -77,7 +77,7 @@ public class ProfileFollowersFragment extends Fragment { mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); mRecyclerView.addItemDecoration(dividerItemDecoration); - mProgressBar = fragmentProfileFollowersBinding.progressBar; + mProgressBar = fragmentProfileFollowersFollowingBinding.progressBar; swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { @@ -88,7 +88,7 @@ public class ProfileFollowersFragment extends Fragment { fetchDataAsync(Authorization.get(getContext())); - return fragmentProfileFollowersBinding.getRoot(); + return fragmentProfileFollowersFollowingBinding.getRoot(); } private void fetchDataAsync(String instanceToken) { @@ -97,7 +97,7 @@ public class ProfileFollowersFragment extends Fragment { pfModel.getFollowersList(instanceToken, getContext()).observe(getViewLifecycleOwner(), pfListMain -> { - adapter = new ProfileFollowersAdapter(getContext(), pfListMain); + adapter = new MyProfileFollowersAdapter(getContext(), pfListMain); if(adapter.getItemCount() > 0) { mRecyclerView.setAdapter(adapter); diff --git a/app/src/main/java/org/mian/gitnex/fragments/ProfileFollowingFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java similarity index 75% rename from app/src/main/java/org/mian/gitnex/fragments/ProfileFollowingFragment.java rename to app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java index 7095e096..5aa9ce13 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ProfileFollowingFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java @@ -16,8 +16,8 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import org.mian.gitnex.adapters.ProfileFollowingAdapter; -import org.mian.gitnex.databinding.FragmentProfileFollowingBinding; +import org.mian.gitnex.adapters.MyProfileFollowingAdapter; +import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.viewmodels.ProfileFollowingViewModel; @@ -26,25 +26,25 @@ import org.mian.gitnex.viewmodels.ProfileFollowingViewModel; * Author M M Arif */ -public class ProfileFollowingFragment extends Fragment { +public class MyProfileFollowingFragment extends Fragment { private ProgressBar mProgressBar; - private ProfileFollowingAdapter adapter; + private MyProfileFollowingAdapter adapter; private RecyclerView mRecyclerView; private TextView noDataFollowing; - private static String repoNameF = "param2"; - private static String repoOwnerF = "param1"; + private static final String repoNameF = "param2"; + private static final String repoOwnerF = "param1"; private String repoName; private String repoOwner; private OnFragmentInteractionListener mListener; - public ProfileFollowingFragment() { + public MyProfileFollowingFragment() { } - public static ProfileFollowingFragment newInstance(String param1, String param2) { - ProfileFollowingFragment fragment = new ProfileFollowingFragment(); + public static MyProfileFollowingFragment newInstance(String param1, String param2) { + MyProfileFollowingFragment fragment = new MyProfileFollowingFragment(); Bundle args = new Bundle(); args.putString(repoOwnerF, param1); args.putString(repoNameF, param2); @@ -65,14 +65,14 @@ public class ProfileFollowingFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - FragmentProfileFollowingBinding fragmentProfileFollowingBinding = FragmentProfileFollowingBinding.inflate(inflater, container, false); + FragmentProfileFollowersFollowingBinding fragmentProfileFollowersFollowingBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); TinyDB tinyDb = TinyDB.getInstance(getContext()); - final SwipeRefreshLayout swipeRefresh = fragmentProfileFollowingBinding.pullToRefresh; + final SwipeRefreshLayout swipeRefresh = fragmentProfileFollowersFollowingBinding.pullToRefresh; - noDataFollowing = fragmentProfileFollowingBinding.noDataFollowing; - mRecyclerView = fragmentProfileFollowingBinding.recyclerView; + noDataFollowing = fragmentProfileFollowersFollowingBinding.noData; + mRecyclerView = fragmentProfileFollowersFollowingBinding.recyclerView; DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL); @@ -80,7 +80,7 @@ public class ProfileFollowingFragment extends Fragment { mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); mRecyclerView.addItemDecoration(dividerItemDecoration); - mProgressBar = fragmentProfileFollowingBinding.progressBar; + mProgressBar = fragmentProfileFollowersFollowingBinding.progressBar; swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { @@ -91,7 +91,7 @@ public class ProfileFollowingFragment extends Fragment { fetchDataAsync(Authorization.get(getContext())); - return fragmentProfileFollowingBinding.getRoot(); + return fragmentProfileFollowersFollowingBinding.getRoot(); } private void fetchDataAsync(String instanceToken) { @@ -100,7 +100,7 @@ public class ProfileFollowingFragment extends Fragment { pfModel.getFollowingList(instanceToken, getContext()).observe(getViewLifecycleOwner(), pfListMain -> { - adapter = new ProfileFollowingAdapter(getContext(), pfListMain); + adapter = new MyProfileFollowingAdapter(getContext(), pfListMain); if(adapter.getItemCount() > 0) { mRecyclerView.setAdapter(adapter); diff --git a/app/src/main/java/org/mian/gitnex/fragments/ProfileFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java similarity index 86% rename from app/src/main/java/org/mian/gitnex/fragments/ProfileFragment.java rename to app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java index 4df62072..97e46874 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ProfileFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java @@ -36,7 +36,7 @@ import jp.wasabeef.picasso.transformations.BlurTransformation; * Author M M Arif */ -public class ProfileFragment extends Fragment { +public class MyProfileFragment extends Fragment { private Context ctx; @@ -61,18 +61,14 @@ public class ProfileFragment extends Fragment { TextView userLanguage = v.findViewById(R.id.userLanguage); ImageView userLanguageIcon = v.findViewById(R.id.userLanguageIcon); - ViewGroup aboutFrame = v.findViewById(R.id.aboutFrame); - String[] userLanguageCodes = tinyDb.getString("userLang").split("-"); if(userLanguageCodes.length >= 2) { - Locale locale = new Locale(userLanguageCodes[0], userLanguageCodes[1]); userLanguage.setText(locale.getDisplayLanguage()); } else { - - userLanguage.setText(R.string.notSupported); + userLanguage.setText(getResources().getConfiguration().locale.getDisplayLanguage()); } userAvatar.setOnClickListener(loginId -> @@ -112,7 +108,7 @@ public class ProfileFragment extends Fragment { @Override public void onError(Exception e) {} }); - ProfileFragment.SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager()); + MyProfileFragment.SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager()); ViewPager mViewPager = v.findViewById(R.id.container); mViewPager.setAdapter(mSectionsPagerAdapter); @@ -159,7 +155,6 @@ public class ProfileFragment extends Fragment { tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager)); return v; - } public static class SectionsPagerAdapter extends FragmentStatePagerAdapter { @@ -175,25 +170,23 @@ public class ProfileFragment extends Fragment { switch (position) { case 0: // followers - return ProfileFollowersFragment.newInstance("repoOwner", "repoName"); + return MyProfileFollowersFragment.newInstance("repoOwner", "repoName"); case 1: // following - return ProfileFollowingFragment.newInstance("repoOwner", "repoName"); + return MyProfileFollowingFragment.newInstance("repoOwner", "repoName"); case 2: // emails - return ProfileEmailsFragment.newInstance("repoOwner", "repoName"); + return MyProfileEmailsFragment.newInstance("repoOwner", "repoName"); } return null; - } @Override public int getCount() { return 3; } - } @Override @@ -202,7 +195,6 @@ public class ProfileFragment extends Fragment { menu.clear(); requireActivity().getMenuInflater().inflate(R.menu.profile_dotted_menu, menu); super.onCreateOptionsMenu(menu, inflater); - } @Override @@ -210,21 +202,18 @@ public class ProfileFragment extends Fragment { int id = item.getItemId(); - switch (id) { - - case android.R.id.home: - ((MainActivity)ctx).finish(); - return true; - - case R.id.profileMenu: - BottomSheetProfileFragment bottomSheet = new BottomSheetProfileFragment(); - bottomSheet.show(getChildFragmentManager(), "profileBottomSheet"); - return true; - - default: - return super.onOptionsItemSelected(item); - - } + if(id == android.R.id.home) { + ((MainActivity)ctx).finish(); + return true; + } + else if(id == R.id.profileMenu) { + BottomSheetMyProfileFragment bottomSheet = new BottomSheetMyProfileFragment(); + bottomSheet.show(getChildFragmentManager(), "profileBottomSheet"); + return true; + } + else { + return super.onOptionsItemSelected(item); + } } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java index a62be27d..eaa70b3b 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java @@ -16,6 +16,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -95,12 +96,15 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap notificationsActions = new NotificationsActions(context); notificationsAdapter = new NotificationsAdapter(context, notificationThreads, this, this); + RecyclerView recyclerView = fragmentNotificationsBinding.notifications; LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context); - RecyclerView recyclerView = fragmentNotificationsBinding.notifications; + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL); + recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setAdapter(notificationsAdapter); + recyclerView.addItemDecoration(dividerItemDecoration); recyclerView.addOnScrollListener(new InfiniteScrollListener(pageResultLimit, linearLayoutManager) { @Override @@ -249,6 +253,10 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap if(notificationThreads.isEmpty()) { noDataNotifications.setVisibility(View.VISIBLE); + markAllAsRead.setVisibility(View.GONE); + } + else { + markAllAsRead.setVisibility(View.VISIBLE); } } }); diff --git a/app/src/main/java/org/mian/gitnex/fragments/OrganizationInfoFragment.java b/app/src/main/java/org/mian/gitnex/fragments/OrganizationInfoFragment.java index cab98332..bdef6ca7 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/OrganizationInfoFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/OrganizationInfoFragment.java @@ -29,7 +29,7 @@ import retrofit2.Callback; public class OrganizationInfoFragment extends Fragment { - private Context ctx = getContext(); + private Context ctx; private ProgressBar mProgressBar; private static String orgNameF = "param1"; @@ -67,6 +67,8 @@ public class OrganizationInfoFragment extends Fragment { FragmentOrganizationInfoBinding fragmentOrganizationInfoBinding = FragmentOrganizationInfoBinding.inflate(inflater, container, false); + ctx = getContext(); + mProgressBar = fragmentOrganizationInfoBinding.progressBar; orgAvatar = fragmentOrganizationInfoBinding.orgAvatar; TextView orgNameInfo = fragmentOrganizationInfoBinding.orgNameInfo; diff --git a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java index 30c72f31..e9ce2c34 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java @@ -18,6 +18,7 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import org.gitnex.tea4j.models.IssueComments; import org.gitnex.tea4j.models.Releases; import org.mian.gitnex.adapters.ReleasesAdapter; import org.mian.gitnex.databinding.FragmentReleasesBinding; @@ -41,6 +42,7 @@ public class ReleasesFragment extends Fragment { private String repoName; private String repoOwner; + private String releaseTag; private OnFragmentInteractionListener mListener; @@ -63,6 +65,7 @@ public class ReleasesFragment extends Fragment { repoName = getArguments().getString(repoNameF); repoOwner = getArguments().getString(repoOwnerF); } + releaseTag = requireActivity().getIntent().getStringExtra("releaseTagName"); } @Override @@ -137,6 +140,13 @@ public class ReleasesFragment extends Fragment { adapter = new ReleasesAdapter(getContext(), releasesListMain); if(adapter.getItemCount() > 0) { mRecyclerView.setAdapter(adapter); + if(releasesListMain != null && releaseTag != null) { + int index = getReleaseIndex(releaseTag, releasesListMain); + releaseTag = null; + if(index != -1) { + mRecyclerView.scrollToPosition(index); + } + } noDataReleases.setVisibility(View.GONE); } else { @@ -150,4 +160,13 @@ public class ReleasesFragment extends Fragment { } + private static int getReleaseIndex(String tag, List releases) { + for (Releases release : releases) { + if(release.getTag_name().equals(tag)) { + return releases.indexOf(release); + } + } + return -1; + } + } diff --git a/app/src/main/java/org/mian/gitnex/fragments/RepoInfoFragment.java b/app/src/main/java/org/mian/gitnex/fragments/RepoInfoFragment.java index 8d824157..64a62304 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/RepoInfoFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/RepoInfoFragment.java @@ -42,6 +42,7 @@ public class RepoInfoFragment extends Fragment { private LinearLayout pageContent; private static final String repoNameF = "param2"; private static final String repoOwnerF = "param1"; + private Locale locale; private FragmentRepoInfoBinding binding; @@ -74,17 +75,16 @@ public class RepoInfoFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentRepoInfoBinding.inflate(inflater, container, false); - TinyDB tinyDb = TinyDB.getInstance(getContext()); - ctx = getContext(); + locale = getResources().getConfiguration().locale; pageContent = binding.repoInfoLayout; pageContent.setVisibility(View.GONE); binding.repoMetaFrame.setVisibility(View.GONE); - getRepoInfo(Authorization.get(getContext()), repoOwner, repoName, tinyDb.getString("locale"), tinyDb.getString("dateFormat")); + getRepoInfo(Authorization.get(getContext()), repoOwner, repoName, locale, tinyDb.getString("dateFormat")); getFileContents(Authorization.get(getContext()), repoOwner, repoName, getResources().getString(R.string.defaultFilename)); if(isExpandViewVisible()) { @@ -173,7 +173,7 @@ public class RepoInfoFragment extends Fragment { return binding.repoMetaFrame.getVisibility() == View.VISIBLE; } - private void getRepoInfo(String token, final String owner, String repo, final String locale, final String timeFormat) { + private void getRepoInfo(String token, final String owner, String repo, Locale locale, final String timeFormat) { final TinyDB tinyDb = TinyDB.getInstance(getContext()); @@ -217,12 +217,12 @@ public class RepoInfoFragment extends Fragment { binding.repoMetaWatchers.setText(repoInfo.getWatchers_count()); binding.repoMetaSize.setText(FileUtils.byteCountToDisplaySize((int) repoInfo.getSize() * 1024)); - binding.repoMetaCreatedAt.setText(TimeHelper.formatTime(repoInfo.getCreated_at(), new Locale(locale), timeFormat, ctx)); + binding.repoMetaCreatedAt.setText(TimeHelper.formatTime(repoInfo.getCreated_at(), locale, timeFormat, ctx)); if(timeFormat.equals("pretty")) { binding.repoMetaCreatedAt.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(repoInfo.getCreated_at()), ctx)); } - String repoMetaUpdatedAt = TimeHelper.formatTime(repoInfo.getUpdated_at(), new Locale(locale), timeFormat, ctx); + String repoMetaUpdatedAt = TimeHelper.formatTime(repoInfo.getUpdated_at(), locale, timeFormat, ctx); String website = (repoInfo.getWebsite().isEmpty()) ? getResources().getString(R.string.noDataWebsite) : repoInfo.getWebsite(); binding.repoMetaWebsite.setText(website); diff --git a/app/src/main/java/org/mian/gitnex/fragments/RepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/RepositoriesFragment.java index 7cf70021..25149685 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/RepositoriesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/RepositoriesFragment.java @@ -69,7 +69,6 @@ public class RepositoriesFragment extends Fragment { createNewRepo = fragmentRepositoriesBinding.addNewRepo; createNewRepo.setOnClickListener(view -> { - Intent intent = new Intent(view.getContext(), CreateRepoActivity.class); startActivity(intent); }); @@ -79,9 +78,9 @@ public class RepositoriesFragment extends Fragment { public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { if (dy > 0 && createNewRepo.isShown()) { createNewRepo.setVisibility(View.GONE); - } else if (dy < 0 ) { + } + else if (dy < 0 ) { createNewRepo.setVisibility(View.VISIBLE); - } } @@ -135,7 +134,6 @@ public class RepositoriesFragment extends Fragment { } mProgressBar.setVisibility(View.GONE); }); - } @Override @@ -147,11 +145,6 @@ public class RepositoriesFragment extends Fragment { MenuItem searchItem = menu.findItem(R.id.action_search); androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); - //searchView.setQueryHint(getContext().getString(R.string.strFilter)); - - /*if(!connToInternet) { - return; - }*/ searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { @Override @@ -167,7 +160,6 @@ public class RepositoriesFragment extends Fragment { return false; } }); - } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java index 68603d59..a28c03b7 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/SettingsFragment.java @@ -1,8 +1,11 @@ package org.mian.gitnex.fragments; +import android.app.Dialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; @@ -20,7 +23,9 @@ import org.mian.gitnex.activities.SettingsNotificationsActivity; import org.mian.gitnex.activities.SettingsReportsActivity; import org.mian.gitnex.activities.SettingsSecurityActivity; import org.mian.gitnex.activities.SettingsTranslationActivity; +import org.mian.gitnex.databinding.CustomAboutDialogBinding; import org.mian.gitnex.databinding.FragmentSettingsBinding; +import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Version; @@ -32,6 +37,7 @@ public class SettingsFragment extends Fragment { private Context ctx; private TinyDB tinyDB; + private Dialog aboutAppDialog; @Nullable @Override @@ -41,6 +47,7 @@ public class SettingsFragment extends Fragment { ctx = getContext(); tinyDB = TinyDB.getInstance(ctx); + aboutAppDialog = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert); ((MainActivity) requireActivity()).setActionBarTitle(getResources().getString(R.string.navSettings)); @@ -63,37 +70,78 @@ public class SettingsFragment extends Fragment { fragmentSettingsBinding.reportsFrame.setOnClickListener(v1 -> startActivity(new Intent(ctx, SettingsReportsActivity.class))); - fragmentSettingsBinding.rateAppFrame.setOnClickListener(aboutApp -> rateThisApp()); + fragmentSettingsBinding.rateAppFrame.setOnClickListener(rateApp -> rateThisApp()); - fragmentSettingsBinding.aboutAppFrame.setOnClickListener(aboutApp -> requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).commit()); + fragmentSettingsBinding.aboutAppFrame.setOnClickListener(aboutApp -> showAboutAppDialog()); return fragmentSettingsBinding.getRoot(); + } + public void showAboutAppDialog() { + + if (aboutAppDialog.getWindow() != null) { + aboutAppDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + } + + CustomAboutDialogBinding aboutAppDialogBinding = CustomAboutDialogBinding.inflate(LayoutInflater.from(ctx)); + View view = aboutAppDialogBinding.getRoot(); + aboutAppDialog.setContentView(view); + + aboutAppDialogBinding.appVersionBuild.setText(getString(R.string.appVersionBuild, AppUtil.getAppVersion(ctx), AppUtil.getAppBuildNo(ctx))); + aboutAppDialogBinding.userServerVersion.setText(tinyDB.getString("giteaVersion")); + + aboutAppDialogBinding.donationLinkPatreon.setOnClickListener(v12 -> { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_BROWSABLE); + intent.setData(Uri.parse(getResources().getString(R.string.supportLinkPatreon))); + startActivity(intent); + }); + + aboutAppDialogBinding.translateLink.setOnClickListener(v13 -> { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_BROWSABLE); + intent.setData(Uri.parse(getResources().getString(R.string.crowdInLink))); + startActivity(intent); + }); + + aboutAppDialogBinding.appWebsite.setOnClickListener(v14 -> { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_BROWSABLE); + intent.setData(Uri.parse(getResources().getString(R.string.appWebsiteLink))); + startActivity(intent); + }); + + if(AppUtil.isPro(requireContext())) { + aboutAppDialogBinding.supportHeader.setVisibility(View.GONE); + aboutAppDialogBinding.dividerSupport.setVisibility(View.GONE); + aboutAppDialogBinding.donationLinkPatreon.setVisibility(View.GONE); + } + + aboutAppDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + aboutAppDialog.show(); } public void rateThisApp() { try { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + requireActivity().getPackageName()))); } catch(ActivityNotFoundException e) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + requireActivity().getPackageName()))); } } @Override public void onResume() { - super.onResume(); if(tinyDB.getBoolean("refreshParent")) { - requireActivity().recreate(); requireActivity().overridePendingTransition(0, 0); tinyDB.putBoolean("refreshParent", false); } } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java new file mode 100644 index 00000000..8c389444 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java @@ -0,0 +1,160 @@ +package org.mian.gitnex.fragments.profile; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentProfileDetailBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.ClickListener; +import org.mian.gitnex.helpers.ColorInverter; +import org.mian.gitnex.helpers.RoundedTransformation; +import org.mian.gitnex.helpers.TimeHelper; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Toasty; +import java.util.Locale; +import jp.wasabeef.picasso.transformations.BlurTransformation; +import retrofit2.Call; +import retrofit2.Callback; + +/** + * Author M M Arif + */ + +public class DetailFragment extends Fragment { + + private Context context; + private FragmentProfileDetailBinding binding; + Locale locale; + TinyDB tinyDb; + + private static final String usernameBundle = ""; + private String username; + + public DetailFragment() {} + + public static DetailFragment newInstance(String username) { + DetailFragment fragment = new DetailFragment(); + Bundle args = new Bundle(); + args.putString(usernameBundle, username); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + username = getArguments().getString(usernameBundle); + } + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + binding = FragmentProfileDetailBinding.inflate(inflater, container, false); + context = getContext(); + tinyDb = TinyDB.getInstance(context); + locale = getResources().getConfiguration().locale; + + getProfileDetail(username); + + return binding.getRoot(); + } + + public void getProfileDetail(String username) { + + Call call = RetrofitClient + .getApiInterface(context) + .getUserProfile(Authorization.get(context), username); + + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if(response.isSuccessful() && response.body() != null) { + + switch(response.code()) { + case 200: + String username = !response.body().getFullname().isEmpty() ? response.body().getFullname() : response.body().getUsername(); + String email = !response.body().getEmail().isEmpty() ? response.body().getEmail() : ""; + + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + String timeFormat = tinyDb.getString("dateFormat"); + + binding.userFullName.setText(username); + binding.userLogin.setText(getString(R.string.usernameWithAt, response.body().getLogin())); + binding.userEmail.setText(email); + + String[] userLanguageCodes = response.body().getLang().split("-"); + + if(userLanguageCodes.length >= 2) { + Locale locale = new Locale(userLanguageCodes[0], userLanguageCodes[1]); + binding.userLang.setText(locale.getDisplayLanguage()); + } + else { + binding.userLang.setText(locale.getDisplayLanguage()); + } + + PicassoService.getInstance(context).get() + .load(response.body().getAvatar()) + .transform(new RoundedTransformation(imgRadius, 0)) + .placeholder(R.drawable.loader_animated) + .resize(120, 120) + .centerCrop() + .into(binding.userAvatar); + + PicassoService.getInstance(context).get() + .load(response.body().getAvatar()) + .transform(new BlurTransformation(context)) + .into(binding.userAvatarBackground, new com.squareup.picasso.Callback() { + + @Override + public void onSuccess() { + int invertedColor = new ColorInverter().getImageViewContrastColor(binding.userAvatarBackground); + + binding.userFullName.setTextColor(invertedColor); + binding.userLogin.setTextColor(invertedColor); + } + + @Override public void onError(Exception e) {} + }); + + binding.userJoinedOn.setText(TimeHelper.formatTime(response.body().getCreated(), locale, timeFormat, context)); + if(timeFormat.equals("pretty")) { + binding.userJoinedOn.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(response.body().getCreated()), context)); + } + break; + + case 401: + AlertDialogs + .authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), context.getResources().getString(R.string.alertDialogTokenRevokedMessage), context.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), context.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton)); + break; + + case 403: + Toasty.error(context, context.getString(R.string.authorizeError)); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Toasty.error(context, context.getResources().getString(R.string.genericError)); + } + }); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java new file mode 100644 index 00000000..d4ebef5a --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java @@ -0,0 +1,272 @@ +package org.mian.gitnex.fragments.profile; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.profile.FollowersAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.Version; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class FollowersFragment extends Fragment { + + private Context context; + private FragmentProfileFollowersFollowingBinding fragmentProfileFollowersFollowingBinding; + + private List usersList; + private FollowersAdapter adapter; + + private int pageSize; + private int resultLimit = Constants.resultLimitOldGiteaInstances; + + private static final String usernameBundle = ""; + private String username; + + public FollowersFragment() {} + + public static FollowersFragment newInstance(String username) { + FollowersFragment fragment = new FollowersFragment(); + Bundle args = new Bundle(); + args.putString(usernameBundle, username); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + username = getArguments().getString(usernameBundle); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + fragmentProfileFollowersFollowingBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); + setHasOptionsMenu(true); + context = getContext(); + + TinyDB tinyDb = TinyDB.getInstance(context); + + // if gitea is 1.12 or higher use the new limit + if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + usersList = new ArrayList<>(); + + fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentProfileFollowersFollowingBinding.pullToRefresh.setRefreshing(false); + loadInitial(Authorization.get(context), username, resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter = new FollowersAdapter(context, usersList); + adapter.setLoadMoreListener(() -> fragmentProfileFollowersFollowingBinding.recyclerView.post(() -> { + if(usersList.size() == resultLimit || pageSize == resultLimit) { + int page = (usersList.size() + resultLimit) / resultLimit; + loadMore(Authorization.get(context), username, page, resultLimit); + } + })); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + fragmentProfileFollowersFollowingBinding.recyclerView.setHasFixedSize(true); + fragmentProfileFollowersFollowingBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentProfileFollowersFollowingBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentProfileFollowersFollowingBinding.recyclerView.setAdapter(adapter); + + loadInitial(Authorization.get(context), username, resultLimit); + + return fragmentProfileFollowersFollowingBinding.getRoot(); + } + + private void loadInitial(String token, String username, int resultLimit) { + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserFollowers(token, username, 1, resultLimit); + + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + assert response.body() != null; + if(response.body().size() > 0) { + usersList.clear(); + usersList.addAll(response.body()); + adapter.notifyDataChanged(); + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.GONE); + } + else { + usersList.clear(); + adapter.notifyDataChanged(); + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.VISIBLE); + } + fragmentProfileFollowersFollowingBinding.progressBar.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.VISIBLE); + fragmentProfileFollowersFollowingBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + private void loadMore(String token, String username, int page, int resultLimit) { + + fragmentProfileFollowersFollowingBinding.progressLoadMore.setVisibility(View.VISIBLE); + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserFollowers(token, username, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + List result = response.body(); + assert result != null; + if(result.size() > 0) { + pageSize = result.size(); + usersList.addAll(result); + } + else { + SnackBar.info(context, fragmentProfileFollowersFollowingBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + fragmentProfileFollowersFollowingBinding.progressLoadMore.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.VISIBLE); + fragmentProfileFollowersFollowingBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + + inflater.inflate(R.menu.search_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + + MenuItem searchItem = menu.findItem(R.id.action_search); + androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); + searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + filter(newText); + return false; + } + }); + } + + private void filter(String text) { + + List arr = new ArrayList<>(); + + for(UserInfo d : usersList) { + if(d == null || d.getUsername() == null || d.getFullname() == null) { + continue; + } + if(d.getUsername().toLowerCase().contains(text) || d.getFullname().toLowerCase().contains(text)) { + arr.add(d); + } + } + adapter.updateList(arr); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java new file mode 100644 index 00000000..82390c85 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java @@ -0,0 +1,273 @@ +package org.mian.gitnex.fragments.profile; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.profile.FollowersAdapter; +import org.mian.gitnex.adapters.profile.FollowingAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.Version; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class FollowingFragment extends Fragment { + + private Context context; + private FragmentProfileFollowersFollowingBinding fragmentProfileFollowersFollowingBinding; + + private List usersList; + private FollowingAdapter adapter; + + private int pageSize; + private int resultLimit = Constants.resultLimitOldGiteaInstances; + + private static final String usernameBundle = ""; + private String username; + + public FollowingFragment() {} + + public static FollowingFragment newInstance(String username) { + FollowingFragment fragment = new FollowingFragment(); + Bundle args = new Bundle(); + args.putString(usernameBundle, username); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + username = getArguments().getString(usernameBundle); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + fragmentProfileFollowersFollowingBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); + setHasOptionsMenu(true); + context = getContext(); + + TinyDB tinyDb = TinyDB.getInstance(context); + + // if gitea is 1.12 or higher use the new limit + if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + usersList = new ArrayList<>(); + + fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentProfileFollowersFollowingBinding.pullToRefresh.setRefreshing(false); + loadInitial(Authorization.get(context), username, resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter = new FollowingAdapter(context, usersList); + adapter.setLoadMoreListener(() -> fragmentProfileFollowersFollowingBinding.recyclerView.post(() -> { + if(usersList.size() == resultLimit || pageSize == resultLimit) { + int page = (usersList.size() + resultLimit) / resultLimit; + loadMore(Authorization.get(context), username, page, resultLimit); + } + })); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + fragmentProfileFollowersFollowingBinding.recyclerView.setHasFixedSize(true); + fragmentProfileFollowersFollowingBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentProfileFollowersFollowingBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentProfileFollowersFollowingBinding.recyclerView.setAdapter(adapter); + + loadInitial(Authorization.get(context), username, resultLimit); + + return fragmentProfileFollowersFollowingBinding.getRoot(); + } + + private void loadInitial(String token, String username, int resultLimit) { + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserFollowing(token, username, 1, resultLimit); + + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + assert response.body() != null; + if(response.body().size() > 0) { + usersList.clear(); + usersList.addAll(response.body()); + adapter.notifyDataChanged(); + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.GONE); + } + else { + usersList.clear(); + adapter.notifyDataChanged(); + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.VISIBLE); + } + fragmentProfileFollowersFollowingBinding.progressBar.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.VISIBLE); + fragmentProfileFollowersFollowingBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + private void loadMore(String token, String username, int page, int resultLimit) { + + fragmentProfileFollowersFollowingBinding.progressLoadMore.setVisibility(View.VISIBLE); + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserFollowing(token, username, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + List result = response.body(); + assert result != null; + if(result.size() > 0) { + pageSize = result.size(); + usersList.addAll(result); + } + else { + SnackBar.info(context, fragmentProfileFollowersFollowingBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + fragmentProfileFollowersFollowingBinding.progressLoadMore.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentProfileFollowersFollowingBinding.noData.setVisibility(View.VISIBLE); + fragmentProfileFollowersFollowingBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + + inflater.inflate(R.menu.search_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + + MenuItem searchItem = menu.findItem(R.id.action_search); + androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); + searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + filter(newText); + return false; + } + }); + } + + private void filter(String text) { + + List arr = new ArrayList<>(); + + for(UserInfo d : usersList) { + if(d == null || d.getUsername() == null || d.getFullname() == null) { + continue; + } + if(d.getUsername().toLowerCase().contains(text) || d.getFullname().toLowerCase().contains(text)) { + arr.add(d); + } + } + adapter.updateList(arr); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java new file mode 100644 index 00000000..1f5268e6 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java @@ -0,0 +1,274 @@ +package org.mian.gitnex.fragments.profile; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.models.UserOrganizations; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.profile.OrganizationsAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentOrganizationsBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.Version; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class OrganizationsFragment extends Fragment { + + private Context context; + private FragmentOrganizationsBinding fragmentOrganizationsBinding; + + private List organizationsList; + private OrganizationsAdapter adapter; + + private int pageSize; + private int resultLimit = Constants.resultLimitOldGiteaInstances; + + private static final String usernameBundle = ""; + private String username; + + public OrganizationsFragment() {} + + public static OrganizationsFragment newInstance(String username) { + OrganizationsFragment fragment = new OrganizationsFragment(); + Bundle args = new Bundle(); + args.putString(usernameBundle, username); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + username = getArguments().getString(usernameBundle); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + fragmentOrganizationsBinding = FragmentOrganizationsBinding.inflate(inflater, container, false); + setHasOptionsMenu(true); + context = getContext(); + + TinyDB tinyDb = TinyDB.getInstance(context); + + // if gitea is 1.12 or higher use the new limit + if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + organizationsList = new ArrayList<>(); + + fragmentOrganizationsBinding.addNewOrganization.setVisibility(View.GONE); + + fragmentOrganizationsBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentOrganizationsBinding.pullToRefresh.setRefreshing(false); + loadInitial(Authorization.get(context), username, resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter = new OrganizationsAdapter(context, organizationsList); + adapter.setLoadMoreListener(() -> fragmentOrganizationsBinding.recyclerView.post(() -> { + if(organizationsList.size() == resultLimit || pageSize == resultLimit) { + int page = (organizationsList.size() + resultLimit) / resultLimit; + loadMore(Authorization.get(context), username, page, resultLimit); + } + })); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + fragmentOrganizationsBinding.recyclerView.setHasFixedSize(true); + fragmentOrganizationsBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentOrganizationsBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentOrganizationsBinding.recyclerView.setAdapter(adapter); + + loadInitial(Authorization.get(context), username, resultLimit); + + return fragmentOrganizationsBinding.getRoot(); + } + + private void loadInitial(String token, String username, int resultLimit) { + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserProfileOrganizations(token, username, 1, resultLimit); + + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + assert response.body() != null; + if(response.body().size() > 0) { + organizationsList.clear(); + organizationsList.addAll(response.body()); + adapter.notifyDataChanged(); + fragmentOrganizationsBinding.noDataOrg.setVisibility(View.GONE); + } + else { + organizationsList.clear(); + adapter.notifyDataChanged(); + fragmentOrganizationsBinding.noDataOrg.setVisibility(View.VISIBLE); + } + fragmentOrganizationsBinding.progressBar.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentOrganizationsBinding.noDataOrg.setVisibility(View.VISIBLE); + fragmentOrganizationsBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + private void loadMore(String token, String username, int page, int resultLimit) { + + fragmentOrganizationsBinding.progressLoadMore.setVisibility(View.VISIBLE); + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserProfileOrganizations(token, username, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + List result = response.body(); + assert result != null; + if(result.size() > 0) { + pageSize = result.size(); + organizationsList.addAll(result); + } + else { + SnackBar.info(context, fragmentOrganizationsBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + fragmentOrganizationsBinding.progressLoadMore.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentOrganizationsBinding.noDataOrg.setVisibility(View.VISIBLE); + fragmentOrganizationsBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + + inflater.inflate(R.menu.search_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + + MenuItem searchItem = menu.findItem(R.id.action_search); + androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); + searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + filter(newText); + return false; + } + }); + } + + private void filter(String text) { + + List arr = new ArrayList<>(); + + for(UserOrganizations d : organizationsList) { + if(d == null || d.getUsername() == null || d.getDescription() == null) { + continue; + } + if(d.getUsername().toLowerCase().contains(text) || d.getDescription().toLowerCase().contains(text)) { + arr.add(d); + } + } + adapter.updateList(arr); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java new file mode 100644 index 00000000..74d84d3a --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java @@ -0,0 +1,271 @@ +package org.mian.gitnex.fragments.profile; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.models.UserRepositories; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.profile.RepositoriesAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentRepositoriesBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.Version; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class RepositoriesFragment extends Fragment { + + private Context context; + private FragmentRepositoriesBinding fragmentRepositoriesBinding; + + private List reposList; + private RepositoriesAdapter adapter; + + private int pageSize; + private int resultLimit = Constants.resultLimitOldGiteaInstances; + + private static final String usernameBundle = ""; + private String username; + + public RepositoriesFragment() {} + + public static RepositoriesFragment newInstance(String username) { + RepositoriesFragment fragment = new RepositoriesFragment(); + Bundle args = new Bundle(); + args.putString(usernameBundle, username); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + username = getArguments().getString(usernameBundle); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + fragmentRepositoriesBinding = FragmentRepositoriesBinding.inflate(inflater, container, false); + setHasOptionsMenu(true); + context = getContext(); + + TinyDB tinyDb = TinyDB.getInstance(context); + + // if gitea is 1.12 or higher use the new limit + if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + reposList = new ArrayList<>(); + + fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); + + fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentRepositoriesBinding.pullToRefresh.setRefreshing(false); + loadInitial(Authorization.get(context), username, resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter = new RepositoriesAdapter(context, reposList); + adapter.setLoadMoreListener(() -> fragmentRepositoriesBinding.recyclerView.post(() -> { + if(reposList.size() == resultLimit || pageSize == resultLimit) { + int page = (reposList.size() + resultLimit) / resultLimit; + loadMore(Authorization.get(context), username, page, resultLimit); + } + })); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true); + fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentRepositoriesBinding.recyclerView.setAdapter(adapter); + + loadInitial(Authorization.get(context), username, resultLimit); + + return fragmentRepositoriesBinding.getRoot(); + } + + private void loadInitial(String token, String username, int resultLimit) { + + Call> call = RetrofitClient + .getApiInterface(context).getUserProfileRepositories(token, username, 1, resultLimit); + + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + assert response.body() != null; + if(response.body().size() > 0) { + reposList.clear(); + reposList.addAll(response.body()); + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.noData.setVisibility(View.GONE); + } + else { + reposList.clear(); + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + } + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + private void loadMore(String token, String username, int page, int resultLimit) { + + fragmentRepositoriesBinding.progressLoadMore.setVisibility(View.VISIBLE); + + Call> call = RetrofitClient.getApiInterface(context).getUserProfileRepositories(token, username, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + List result = response.body(); + assert result != null; + if(result.size() > 0) { + pageSize = result.size(); + reposList.addAll(result); + } + else { + SnackBar.info(context, fragmentRepositoriesBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.progressLoadMore.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + + inflater.inflate(R.menu.search_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + + MenuItem searchItem = menu.findItem(R.id.action_search); + androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); + searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + filter(newText); + return false; + } + }); + } + + private void filter(String text) { + + List arr = new ArrayList<>(); + + for(UserRepositories d : reposList) { + if(d == null || d.getFullName() == null || d.getDescription() == null) { + continue; + } + if(d.getFullName().toLowerCase().contains(text) || d.getDescription().toLowerCase().contains(text)) { + arr.add(d); + } + } + adapter.updateList(arr); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java new file mode 100644 index 00000000..38f7180d --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java @@ -0,0 +1,273 @@ +package org.mian.gitnex.fragments.profile; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.models.UserRepositories; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.profile.StarredRepositoriesAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentRepositoriesBinding; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Authorization; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Toasty; +import org.mian.gitnex.helpers.Version; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class StarredRepositoriesFragment extends Fragment { + + private Context context; + private FragmentRepositoriesBinding fragmentRepositoriesBinding; + + private List reposList; + private StarredRepositoriesAdapter adapter; + + private int pageSize; + private int resultLimit = Constants.resultLimitOldGiteaInstances; + + private static final String usernameBundle = ""; + private String username; + + public StarredRepositoriesFragment() {} + + public static StarredRepositoriesFragment newInstance(String username) { + StarredRepositoriesFragment fragment = new StarredRepositoriesFragment(); + Bundle args = new Bundle(); + args.putString(usernameBundle, username); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + username = getArguments().getString(usernameBundle); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + fragmentRepositoriesBinding = org.mian.gitnex.databinding.FragmentRepositoriesBinding.inflate(inflater, container, false); + setHasOptionsMenu(true); + context = getContext(); + TinyDB tinyDb = TinyDB.getInstance(context); + + // if gitea is 1.12 or higher use the new limit + if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + reposList = new ArrayList<>(); + + fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); + + fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentRepositoriesBinding.pullToRefresh.setRefreshing(false); + loadInitial(Authorization.get(context), username, resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter = new StarredRepositoriesAdapter(context, reposList); + adapter.setLoadMoreListener(() -> fragmentRepositoriesBinding.recyclerView.post(() -> { + if(reposList.size() == resultLimit || pageSize == resultLimit) { + int page = (reposList.size() + resultLimit) / resultLimit; + loadMore(Authorization.get(context), username, page, resultLimit); + } + })); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true); + fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentRepositoriesBinding.recyclerView.setAdapter(adapter); + + loadInitial(Authorization.get(context), username, resultLimit); + + return fragmentRepositoriesBinding.getRoot(); + } + + private void loadInitial(String token, String username, int resultLimit) { + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserProfileStarredRepositories(token, username, 1, resultLimit); + + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + assert response.body() != null; + if(response.body().size() > 0) { + reposList.clear(); + reposList.addAll(response.body()); + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.noData.setVisibility(View.GONE); + } + else { + reposList.clear(); + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + } + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + private void loadMore(String token, String username, int page, int resultLimit) { + + fragmentRepositoriesBinding.progressLoadMore.setVisibility(View.VISIBLE); + + Call> call = RetrofitClient + .getApiInterface(context) + .getUserProfileStarredRepositories(token, username, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + switch(response.code()) { + case 200: + List result = response.body(); + assert result != null; + if(result.size() > 0) { + pageSize = result.size(); + reposList.addAll(result); + } + else { + SnackBar.info(context, fragmentRepositoriesBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.progressLoadMore.setVisibility(View.GONE); + break; + + case 401: + AlertDialogs.authorizationTokenRevokedDialog(context, 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(context, context.getString(R.string.authorizeError)); + break; + + case 404: + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + break; + + default: + Toasty.error(context, getString(R.string.genericError)); + break; + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(context, getString(R.string.genericError)); + } + }); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + + inflater.inflate(R.menu.search_menu, menu); + super.onCreateOptionsMenu(menu, inflater); + + MenuItem searchItem = menu.findItem(R.id.action_search); + androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView(); + searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); + + searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + filter(newText); + return false; + } + }); + } + + private void filter(String text) { + + List arr = new ArrayList<>(); + + for(UserRepositories d : reposList) { + if(d == null || d.getFullName() == null || d.getDescription() == null) { + continue; + } + if(d.getFullName().toLowerCase().contains(text) || d.getDescription().toLowerCase().contains(text)) { + arr.add(d); + } + } + adapter.updateList(arr); + } +} diff --git a/app/src/main/java/org/mian/gitnex/helpers/Constants.java b/app/src/main/java/org/mian/gitnex/helpers/Constants.java index c9683935..65519048 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/Constants.java +++ b/app/src/main/java/org/mian/gitnex/helpers/Constants.java @@ -27,9 +27,9 @@ public class Constants { 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"; + public static final String publicOrganizations = "PublicOrganizations"; // issues variables public static final int issuesPageInit = 1; @@ -51,6 +51,9 @@ public class Constants { public static final int defaultPollingDelay = 15; public static final int maximumPollingDelay = 720; + // public organizations + public static final int publicOrganizationsPageInit = 1; + public static final int maximumFileViewerSize = 3 * 1024 * 1024; public static final String mainNotificationChannelId = "main_channel"; diff --git a/app/src/main/java/org/mian/gitnex/helpers/Markdown.java b/app/src/main/java/org/mian/gitnex/helpers/Markdown.java index 986661c7..a3c81282 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/Markdown.java +++ b/app/src/main/java/org/mian/gitnex/helpers/Markdown.java @@ -3,6 +3,7 @@ package org.mian.gitnex.helpers; import android.content.Context; import android.graphics.Typeface; import android.text.Spanned; +import android.text.method.LinkMovementMethod; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.content.res.ResourcesCompat; @@ -79,6 +80,7 @@ public class Markdown { public static void render(Context context, String markdown, TextView textView) { try { + textView.setMovementMethod(LinkMovementMethod.getInstance()); Renderer renderer = rendererPool.claim(timeout); if(renderer != null) { diff --git a/app/src/main/java/org/mian/gitnex/helpers/SnackBar.java b/app/src/main/java/org/mian/gitnex/helpers/SnackBar.java new file mode 100644 index 00000000..c2febdac --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/helpers/SnackBar.java @@ -0,0 +1,46 @@ +package org.mian.gitnex.helpers; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; +import com.google.android.material.snackbar.Snackbar; +import org.mian.gitnex.R; + +/** + * Author M M Arif + */ + +public class SnackBar { + + public static void info(Context context, View view, String message) { + Snackbar snackBar = Snackbar.make(view, message, Snackbar.LENGTH_LONG); + View sbView = snackBar.getView(); + TextView textView = sbView.findViewById(R.id.snackbar_text); + textView.setTextColor(context.getResources().getColor(R.color.colorWhite)); + snackBar.show(); + } + + public static void success(Context context, View view, String message) { + Snackbar snackBar = Snackbar.make(view, message, Snackbar.LENGTH_LONG); + View sbView = snackBar.getView(); + TextView textView = sbView.findViewById(R.id.snackbar_text); + textView.setTextColor(context.getResources().getColor(R.color.colorLightGreen)); + snackBar.show(); + } + + public static void warning(Context context, View view, String message) { + Snackbar snackBar = Snackbar.make(view, message, Snackbar.LENGTH_LONG); + View sbView = snackBar.getView(); + TextView textView = sbView.findViewById(R.id.snackbar_text); + textView.setTextColor(context.getResources().getColor(R.color.lightYellow)); + snackBar.show(); + } + + public static void error(Context context, View view, String message) { + Snackbar snackBar = Snackbar.make(view, message, Snackbar.LENGTH_LONG); + View sbView = snackBar.getView(); + TextView textView = sbView.findViewById(R.id.snackbar_text); + textView.setTextColor(context.getResources().getColor(R.color.darkRed)); + snackBar.show(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/helpers/TimeHelper.java b/app/src/main/java/org/mian/gitnex/helpers/TimeHelper.java index 84d202dd..37d08332 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/TimeHelper.java +++ b/app/src/main/java/org/mian/gitnex/helpers/TimeHelper.java @@ -43,7 +43,7 @@ public class TimeHelper { switch(timeFormat) { case "pretty": { - PrettyTime prettyTime = new PrettyTime(Locale.getDefault()); + PrettyTime prettyTime = new PrettyTime(locale); return prettyTime.format(date); } @@ -69,17 +69,17 @@ public class TimeHelper { } - public static boolean timeBetweenHours(int fromHour, int toHour) { + public static boolean timeBetweenHours(int fromHour, int toHour, int fromMinute, int toMinute) { Calendar cal = Calendar.getInstance(); Calendar from = Calendar.getInstance(); from.set(Calendar.HOUR_OF_DAY, fromHour); - from.set(Calendar.MINUTE, 0); + from.set(Calendar.MINUTE, fromMinute); Calendar to = Calendar.getInstance(); to.set(Calendar.HOUR_OF_DAY, toHour); - to.set(Calendar.MINUTE, 0); + to.set(Calendar.MINUTE, toMinute); if(to.before(from)) { if(cal.after(to)) { diff --git a/app/src/main/java/org/mian/gitnex/helpers/ssl/MemorizingTrustManager.java b/app/src/main/java/org/mian/gitnex/helpers/ssl/MemorizingTrustManager.java index cc5161c0..78db04ec 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/ssl/MemorizingTrustManager.java +++ b/app/src/main/java/org/mian/gitnex/helpers/ssl/MemorizingTrustManager.java @@ -424,16 +424,16 @@ public class MemorizingTrustManager implements X509TrustManager { } } - private static void certDetails(StringBuilder stringBuilder, X509Certificate c) { + private void certDetails(StringBuilder stringBuilder, X509Certificate c) { - SimpleDateFormat validityDateFormater = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + SimpleDateFormat validityDateFormatter = new SimpleDateFormat("yyyy-MM-dd", context.getResources().getConfiguration().locale); stringBuilder.append("\n") .append(c.getSubjectDN().toString()) .append("\n") - .append(validityDateFormater.format(c.getNotBefore())) + .append(validityDateFormatter.format(c.getNotBefore())) .append(" - ") - .append(validityDateFormater.format(c.getNotAfter())) + .append(validityDateFormatter.format(c.getNotAfter())) .append("\nSHA-256: ") .append(certHash(c, "SHA-256")) .append("\nSHA-1: ") diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/FilesViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/FilesViewModel.java index aa6eabb0..9a6cb1f3 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/FilesViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/FilesViewModel.java @@ -42,39 +42,23 @@ public class FilesViewModel extends ViewModel { .getFiles(token, owner, repo, ref); call.enqueue(new Callback>() { - @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.code() == 200) { - - assert response.body() != null; - - if(response.body().size() > 0) { - - Collections.sort(response.body(), (byType1, byType2) -> byType1.getType().compareTo(byType2.getType())); - filesList.postValue(response.body()); - } - else { - - progressBar.setVisibility(View.GONE); - noDataFiles.setVisibility(View.VISIBLE); - } + if(response.isSuccessful() && response.body() != null && !response.body().isEmpty()) { + Collections.sort(response.body(), (byType1, byType2) -> byType1.getType().compareTo(byType2.getType())); + filesList.postValue(response.body()); } else { - progressBar.setVisibility(View.GONE); noDataFiles.setVisibility(View.VISIBLE); } - } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Toasty.error(ctx, ctx.getString(R.string.errorOnLogin)); } - }); } @@ -93,27 +77,14 @@ public class FilesViewModel extends ViewModel { .getDirFiles(token, owner, repo, filesDir, ref); call.enqueue(new Callback>() { - @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.code() == 200) { - - assert response.body() != null; - - if(response.body().size() > 0) { - - Collections.sort(response.body(), (byType1, byType2) -> byType1.getType().compareTo(byType2.getType())); - filesList2.postValue(response.body()); - } - else { - - progressBar.setVisibility(View.GONE); - noDataFiles.setVisibility(View.VISIBLE); - } + if(response.isSuccessful() && response.body() != null && !response.body().isEmpty()) { + Collections.sort(response.body(), (byType1, byType2) -> byType1.getType().compareTo(byType2.getType())); + filesList2.postValue(response.body()); } else { - progressBar.setVisibility(View.GONE); noDataFiles.setVisibility(View.VISIBLE); } @@ -121,10 +92,8 @@ public class FilesViewModel extends ViewModel { @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Toasty.error(ctx, ctx.getString(R.string.errorOnLogin)); } - }); } diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/OrganizationListViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/OrganizationListViewModel.java index e973e433..e6e53ea3 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/OrganizationListViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/OrganizationListViewModel.java @@ -35,7 +35,7 @@ public class OrganizationListViewModel extends ViewModel { Call> call = RetrofitClient .getApiInterface(ctx) - .getUserOrgs(token); + .getUserOrgs(token, 1, 50); call.enqueue(new Callback>() { diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java index 380b8d59..6dc1be94 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java @@ -33,7 +33,7 @@ public class ProfileFollowersViewModel extends ViewModel { Call> call = RetrofitClient .getApiInterface(ctx) - .getFollowers(token); + .getFollowers(token, 1, 50); call.enqueue(new Callback>() { diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java index 146554e9..871d0a3a 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java @@ -33,7 +33,7 @@ public class ProfileFollowingViewModel extends ViewModel { Call> call = RetrofitClient .getApiInterface(ctx) - .getFollowing(token); + .getFollowing(token, 1, 50); call.enqueue(new Callback>() { diff --git a/app/src/main/res/drawable/shape_list_divider.xml b/app/src/main/res/drawable/shape_list_divider.xml new file mode 100644 index 00000000..ff307019 --- /dev/null +++ b/app/src/main/res/drawable/shape_list_divider.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_add_collaborator_to_repository.xml b/app/src/main/res/layout/activity_add_collaborator_to_repository.xml index 218adf7d..34114444 100644 --- a/app/src/main/res/layout/activity_add_collaborator_to_repository.xml +++ b/app/src/main/res/layout/activity_add_collaborator_to_repository.xml @@ -10,6 +10,7 @@ android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:elevation="0dp" android:theme="@style/Widget.AppCompat.SearchView"> - @@ -11,6 +11,7 @@ android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:elevation="0dp" android:theme="@style/Widget.AppCompat.SearchView"> - @@ -11,6 +11,7 @@ android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:elevation="0dp" android:theme="@style/Widget.AppCompat.SearchView"> + android:src="@drawable/ic_close" /> - - + android:orientation="horizontal"> - + android:orientation="horizontal"> -