diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml
index 8c59fa31..d216c01c 100644
--- a/.woodpecker/build.yml
+++ b/.woodpecker/build.yml
@@ -1,4 +1,4 @@
-pipeline:
+steps:
build:
image: alvrme/alpine-android:android-32-jdk17
commands:
diff --git a/.woodpecker/check.yml b/.woodpecker/check.yml
index 4d3da82a..a5eefc89 100644
--- a/.woodpecker/check.yml
+++ b/.woodpecker/check.yml
@@ -1,4 +1,4 @@
-pipeline:
+steps:
author-header:
image: qwerty287/woodpecker-regex-check
group: check
diff --git a/.woodpecker/finish.yml b/.woodpecker/finish.yml
index 7202f32d..035661c5 100644
--- a/.woodpecker/finish.yml
+++ b/.woodpecker/finish.yml
@@ -6,7 +6,7 @@ depends_on:
run_on: [ success, failure ]
skip_clone: true
-pipeline:
+steps:
discord:
image: appleboy/drone-discord
settings:
diff --git a/.woodpecker/locale.yml b/.woodpecker/locale.yml
index 1ded0156..31a94fc0 100644
--- a/.woodpecker/locale.yml
+++ b/.woodpecker/locale.yml
@@ -1,4 +1,4 @@
-pipeline:
+steps:
prepare:
image: alpine
commands:
diff --git a/README.md b/README.md
index cd1dce26..bc8be288 100644
--- a/README.md
+++ b/README.md
@@ -4,29 +4,27 @@
# GitNex - Android client for Forgejo and Gitea
-GitNex is a free/paid, open-source Android client for Git repository management tool Forgejo and Gitea.
+GitNex is a free/paid, open-source Android client for the Git repository management tools Forgejo and Gitea.
-GitNex is licensed under GPLv3 License. See the LICENSE file for the full license text. **No trackers are used** and source code is available here for
-anyone to audit.
+GitNex is licensed under the GPLv3 License. Please refer to the LICENSE file for the full text of the license. **No trackers are used**, and the source code is available here for anyone to audit.
## Downloads
[](https://f-droid.org/en/packages/org.mian.gitnex/)
[](https://play.google.com/store/apps/details?id=org.mian.gitnex.pro)
-[](https://cloud.swatian.com/s/DN7E5xxtaw4fRbE)
+[](https://cloud.swatian.com/s/WS4k3seXnmfQppo)
## Note about Forgejo and Gitea version
-Please make sure that you are on latest stable release or later for better app experience.
+Please make sure that you are on the latest stable release or later for a better app experience.
-Check the versions [compatibility page](https://codeberg.org/gitnex/GitNex/wiki/Compatibility) which lists all the supported versions with
-compatibility ratio.
+Check the version [compatibility page](https://codeberg.org/gitnex/GitNex/wiki/Compatibility), which lists all the supported versions along with their compatibility ratios.
## Build from source
-Option 1 - Download the source code, open it in Android Studio and build it there.
+Option 1 - Download the source code, open it in Android Studio, and build it there.
-Option 2 - Open terminal(Linux) and cd to the project dir. Run `./gradlew assembleFree`.
+Option 2 - Open the terminal (Linux) and navigate to the project directory. Then, run `./gradlew assembleFree`.
## Features
@@ -48,10 +46,9 @@ Option 2 - Open terminal(Linux) and cd to the project dir. Run `./gradlew assemb
## Translation
-Help us translate GitNex to your native language.
+Help us translate GitNex into your native language.
-We use [Crowdin](https://crowdin.com/project/gitnex) for translation. If your language is not listed, please
-request [here](https://codeberg.org/gitnex/GitNex/issues) to add it to the project.
+We use [Crowdin](https://crowdin.com/project/gitnex) for translations. If your language is not listed, please request to add it to the project [here](https://codeberg.org/gitnex/GitNex/issues).
**Link: https://crowdin.com/project/GitNex**
@@ -75,7 +72,7 @@ request [here](https://codeberg.org/gitnex/GitNex/issues) to add it to the proje
## Thanks
-Thanks to all the open source libraries, contributors and donators.
+Thanks to all the open source libraries, contributors, and donors.
#### Open source libraries
diff --git a/app/build.gradle b/app/build.gradle
index aa97c4a8..ccbdcdbc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -54,16 +54,16 @@ configurations {
}
dependencies {
- def lifecycle_version = '2.6.1'
+ def lifecycle_version = '2.6.2'
def markwon_version = '4.6.2'
def work_version = '2.8.1'
def acra = '5.9.7'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'com.google.android.material:material:1.11.0-alpha01'
- implementation 'androidx.compose.material3:material3:1.2.0-alpha03'
- implementation 'androidx.compose.material3:material3-window-size-class:1.2.0-alpha03'
+ implementation 'com.google.android.material:material:1.11.0-alpha02'
+ implementation 'androidx.compose.material3:material3:1.2.0-alpha07'
+ implementation 'androidx.compose.material3:material3-window-size-class:1.2.0-alpha07'
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
@@ -111,7 +111,7 @@ dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'com.github.chrisvest:stormpot:2.4.2'
- implementation 'androidx.browser:browser:1.5.0'
+ implementation 'androidx.browser:browser:1.6.0'
implementation 'com.google.android.flexbox:flexbox:3.0.0'
implementation('org.codeberg.gitnex:tea4j-autodeploy:65f700d036') {
exclude module: 'org.apache.oltu.oauth2.common'
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 7300363c..ce298321 100644
--- a/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/DeepLinksActivity.java
@@ -101,7 +101,7 @@ public class DeepLinksActivity extends BaseActivity {
accountFound = true;
- AppUtil.switchToAccount(ctx, userAccount, true);
+ AppUtil.switchToAccount(ctx, userAccount, false);
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 b842d9a0..2e36c300 100644
--- a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java
@@ -700,6 +700,26 @@ public class IssueDetailActivity extends BaseActivity
viewBinding.issuePrState,
ColorStateList.valueOf(
ctx.getResources().getColor(R.color.iconIssuePrClosedColor, null)));
+ } else if (issue.getIssue().getTitle().contains("[WIP]")
+ || issue.getIssue().getTitle().contains("[wip]")) { // draft
+
+ viewBinding.issuePrState.setImageResource(R.drawable.ic_draft);
+ ImageViewCompat.setImageTintList(
+ viewBinding.issuePrState,
+ ColorStateList.valueOf(
+ ctx.getResources().getColor(R.color.colorWhite, null)));
+ viewBinding.issuePrState.setBackgroundResource(R.drawable.shape_draft_release);
+ viewBinding.issuePrState.setPadding(
+ (int) ctx.getResources().getDimension(R.dimen.dimen4dp),
+ (int) ctx.getResources().getDimension(R.dimen.dimen2dp),
+ (int) ctx.getResources().getDimension(R.dimen.dimen4dp),
+ (int) ctx.getResources().getDimension(R.dimen.dimen2dp));
+
+ viewBinding.toolbarTitle.setPadding(
+ (int) ctx.getResources().getDimension(R.dimen.dimen12dp),
+ (int) ctx.getResources().getDimension(R.dimen.dimen0dp),
+ (int) ctx.getResources().getDimension(R.dimen.dimen0dp),
+ (int) ctx.getResources().getDimension(R.dimen.dimen0dp));
} else { // open
viewBinding.issuePrState.setImageResource(R.drawable.ic_pull_request);
@@ -1034,7 +1054,7 @@ public class IssueDetailActivity extends BaseActivity
RetrofitClient.getApiInterface(this)
.repoGetPullRequest(repoOwner, repoName, (long) issueIndex)
.enqueue(
- new Callback() {
+ new Callback<>() {
@Override
public void onResponse(
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 db8e04db..0930c86b 100644
--- a/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/LoginActivity.java
@@ -639,7 +639,9 @@ public class LoginActivity extends BaseActivity {
final String credential = Credentials.basic(loginUid, loginPass, StandardCharsets.UTF_8);
CreateAccessTokenOption createUserToken = new CreateAccessTokenOption().name(tokenName);
- if (giteaVersion.higherOrEqual("1.19.0")) {
+ if (giteaVersion.higherOrEqual("1.20.0")) {
+ createUserToken.addScopesItem("all");
+ } else if (giteaVersion.less("1.20.0") && (giteaVersion.higherOrEqual("1.19.0"))) {
createUserToken.addScopesItem("all");
createUserToken.addScopesItem("sudo");
}
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 51d45e6e..b5464918 100644
--- a/app/src/main/java/org/mian/gitnex/activities/MainActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/MainActivity.java
@@ -39,6 +39,7 @@ import org.mian.gitnex.databinding.ActivityMainBinding;
import org.mian.gitnex.fragments.AdministrationFragment;
import org.mian.gitnex.fragments.BottomSheetDraftsFragment;
import org.mian.gitnex.fragments.BottomSheetMyIssuesFilterFragment;
+import org.mian.gitnex.fragments.DashboardFragment;
import org.mian.gitnex.fragments.DraftsFragment;
import org.mian.gitnex.fragments.ExploreFragment;
import org.mian.gitnex.fragments.MostVisitedReposFragment;
@@ -150,6 +151,8 @@ public class MainActivity extends BaseActivity
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
} else if (fragmentById instanceof MyIssuesFragment) {
toolbarTitle.setText(getResources().getString(R.string.navMyIssues));
+ } else if (fragmentById instanceof DashboardFragment) {
+ toolbarTitle.setText(getResources().getString(R.string.dashboard));
}
getNotificationsCount();
@@ -161,6 +164,11 @@ public class MainActivity extends BaseActivity
Menu menu = navigationView.getMenu();
navNotifications = menu.findItem(R.id.nav_notifications);
+ MenuItem navDashboard = menu.findItem(R.id.nav_dashboard);
+
+ navDashboard.getActionView().findViewById(R.id.betaBadge).setVisibility(View.VISIBLE);
+ TextView dashboardBetaView = navDashboard.getActionView().findViewById(R.id.betaBadge);
+ dashboardBetaView.setText(R.string.beta);
navigationView
.getViewTreeObserver()
@@ -296,6 +304,10 @@ public class MainActivity extends BaseActivity
if (getAccount().requiresVersion("1.14.0")) {
navigationView.getMenu().findItem(R.id.nav_my_issues).setVisible(true);
}
+
+ if (getAccount().requiresVersion("1.20.0")) {
+ navigationView.getMenu().findItem(R.id.nav_dashboard).setVisible(true);
+ }
}
@Override
@@ -489,7 +501,14 @@ public class MainActivity extends BaseActivity
.commit();
navigationView.setCheckedItem(R.id.nav_notes);
break;
-
+ case 11:
+ toolbarTitle.setText(getResources().getString(R.string.dashboard));
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragment_container, new DashboardFragment())
+ .commit();
+ navigationView.setCheckedItem(R.id.nav_dashboard);
+ break;
default:
toolbarTitle.setText(getResources().getString(R.string.navMyRepos));
getSupportFragmentManager()
@@ -710,6 +729,13 @@ public class MainActivity extends BaseActivity
.beginTransaction()
.replace(R.id.fragment_container, new NotesFragment())
.commit();
+ } else if (id == R.id.nav_dashboard) {
+
+ toolbarTitle.setText(getResources().getString(R.string.dashboard));
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragment_container, new DashboardFragment())
+ .commit();
}
drawer.closeDrawer(GravityCompat.START);
diff --git a/app/src/main/java/org/mian/gitnex/activities/RepoStargazersActivity.java b/app/src/main/java/org/mian/gitnex/activities/RepoStargazersActivity.java
index 0b36c9c6..c9f8b315 100644
--- a/app/src/main/java/org/mian/gitnex/activities/RepoStargazersActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/RepoStargazersActivity.java
@@ -1,11 +1,12 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
-import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
+import android.view.inputmethod.EditorInfo;
+import androidx.appcompat.widget.SearchView;
import androidx.lifecycle.ViewModelProvider;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.UserGridAdapter;
@@ -18,37 +19,29 @@ import org.mian.gitnex.viewmodels.RepoStargazersViewModel;
*/
public class RepoStargazersActivity extends BaseActivity {
- private TextView noDataStargazers;
private View.OnClickListener onClickListener;
private UserGridAdapter adapter;
- private GridView mGridView;
- private ProgressBar mProgressBar;
-
private RepositoryContext repository;
+ private ActivityRepoStargazersBinding activityRepoStargazersBinding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActivityRepoStargazersBinding activityRepoStargazersBinding =
- ActivityRepoStargazersBinding.inflate(getLayoutInflater());
+ activityRepoStargazersBinding = ActivityRepoStargazersBinding.inflate(getLayoutInflater());
setContentView(activityRepoStargazersBinding.getRoot());
- ImageView closeActivity = activityRepoStargazersBinding.close;
- TextView toolbarTitle = activityRepoStargazersBinding.toolbarTitle;
- noDataStargazers = activityRepoStargazersBinding.noDataStargazers;
- mGridView = activityRepoStargazersBinding.gridView;
- mProgressBar = activityRepoStargazersBinding.progressBar;
+ setSupportActionBar(activityRepoStargazersBinding.toolbar);
repository = RepositoryContext.fromIntent(getIntent());
final String repoOwner = repository.getOwner();
final String repoName = repository.getName();
initCloseListener();
- closeActivity.setOnClickListener(onClickListener);
+ activityRepoStargazersBinding.close.setOnClickListener(onClickListener);
- toolbarTitle.setText(R.string.repoStargazersInMenu);
+ activityRepoStargazersBinding.toolbarTitle.setText(R.string.repoStargazersInMenu);
fetchDataAsync(repoOwner, repoName);
}
@@ -67,16 +60,18 @@ public class RepoStargazersActivity extends BaseActivity {
if (adapter.getCount() > 0) {
- mGridView.setAdapter(adapter);
- noDataStargazers.setVisibility(View.GONE);
+ activityRepoStargazersBinding.gridView.setAdapter(adapter);
+ activityRepoStargazersBinding.noDataStargazers.setVisibility(
+ View.GONE);
} else {
adapter.notifyDataSetChanged();
- mGridView.setAdapter(adapter);
- noDataStargazers.setVisibility(View.VISIBLE);
+ activityRepoStargazersBinding.gridView.setAdapter(adapter);
+ activityRepoStargazersBinding.noDataStargazers.setVisibility(
+ View.VISIBLE);
}
- mProgressBar.setVisibility(View.GONE);
+ activityRepoStargazersBinding.progressBar.setVisibility(View.GONE);
});
}
@@ -90,4 +85,36 @@ public class RepoStargazersActivity extends BaseActivity {
super.onResume();
repository.checkAccountSwitch(this);
}
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+
+ final MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.search_menu, menu);
+
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ SearchView searchView = (SearchView) searchItem.getActionView();
+ searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
+
+ searchView.setOnQueryTextListener(
+ new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
+
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+
+ if (activityRepoStargazersBinding.gridView.getAdapter() != null) {
+ adapter.getFilter().filter(newText);
+ }
+
+ return false;
+ }
+ });
+
+ return true;
+ }
}
diff --git a/app/src/main/java/org/mian/gitnex/activities/RepoWatchersActivity.java b/app/src/main/java/org/mian/gitnex/activities/RepoWatchersActivity.java
index a684b8bc..bec73fa3 100644
--- a/app/src/main/java/org/mian/gitnex/activities/RepoWatchersActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/RepoWatchersActivity.java
@@ -1,11 +1,12 @@
package org.mian.gitnex.activities;
import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
-import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
+import android.view.inputmethod.EditorInfo;
+import androidx.appcompat.widget.SearchView;
import androidx.lifecycle.ViewModelProvider;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.UserGridAdapter;
@@ -18,12 +19,9 @@ import org.mian.gitnex.viewmodels.RepoWatchersViewModel;
*/
public class RepoWatchersActivity extends BaseActivity {
- private TextView noDataWatchers;
private View.OnClickListener onClickListener;
private UserGridAdapter adapter;
- private GridView mGridView;
- private ProgressBar mProgressBar;
-
+ private ActivityRepoWatchersBinding activityRepoWatchersBinding;
private RepositoryContext repository;
@Override
@@ -31,24 +29,19 @@ public class RepoWatchersActivity extends BaseActivity {
super.onCreate(savedInstanceState);
- ActivityRepoWatchersBinding activityRepoWatchersBinding =
- ActivityRepoWatchersBinding.inflate(getLayoutInflater());
+ activityRepoWatchersBinding = ActivityRepoWatchersBinding.inflate(getLayoutInflater());
setContentView(activityRepoWatchersBinding.getRoot());
- ImageView closeActivity = activityRepoWatchersBinding.close;
- TextView toolbarTitle = activityRepoWatchersBinding.toolbarTitle;
- noDataWatchers = activityRepoWatchersBinding.noDataWatchers;
- mGridView = activityRepoWatchersBinding.gridView;
- mProgressBar = activityRepoWatchersBinding.progressBar;
+ setSupportActionBar(activityRepoWatchersBinding.toolbar);
repository = RepositoryContext.fromIntent(getIntent());
final String repoOwner = repository.getOwner();
final String repoName = repository.getName();
initCloseListener();
- closeActivity.setOnClickListener(onClickListener);
+ activityRepoWatchersBinding.close.setOnClickListener(onClickListener);
- toolbarTitle.setText(R.string.repoWatchersInMenu);
+ activityRepoWatchersBinding.toolbarTitle.setText(R.string.repoWatchersInMenu);
fetchDataAsync(repoOwner, repoName);
}
@@ -67,16 +60,17 @@ public class RepoWatchersActivity extends BaseActivity {
if (adapter.getCount() > 0) {
- mGridView.setAdapter(adapter);
- noDataWatchers.setVisibility(View.GONE);
+ activityRepoWatchersBinding.gridView.setAdapter(adapter);
+ activityRepoWatchersBinding.noDataWatchers.setVisibility(View.GONE);
} else {
adapter.notifyDataSetChanged();
- mGridView.setAdapter(adapter);
- noDataWatchers.setVisibility(View.VISIBLE);
+ activityRepoWatchersBinding.gridView.setAdapter(adapter);
+ activityRepoWatchersBinding.noDataWatchers.setVisibility(
+ View.VISIBLE);
}
- mProgressBar.setVisibility(View.GONE);
+ activityRepoWatchersBinding.progressBar.setVisibility(View.GONE);
});
}
@@ -90,4 +84,35 @@ public class RepoWatchersActivity extends BaseActivity {
super.onResume();
repository.checkAccountSwitch(this);
}
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+
+ final MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.search_menu, menu);
+
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ SearchView searchView = (SearchView) searchItem.getActionView();
+ searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
+
+ searchView.setOnQueryTextListener(
+ new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
+
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+
+ if (activityRepoWatchersBinding.gridView.getAdapter() != null) {
+ adapter.getFilter().filter(newText);
+ }
+ return false;
+ }
+ });
+
+ return true;
+ }
}
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 3a82e756..29590950 100644
--- a/app/src/main/java/org/mian/gitnex/activities/SettingsGeneralActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/SettingsGeneralActivity.java
@@ -93,6 +93,9 @@ public class SettingsGeneralActivity extends BaseActivity {
} else if (homeScreenSelectedChoice == 10) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.navNotes));
+ } else if (homeScreenSelectedChoice == 11) {
+
+ viewBinding.homeScreenSelected.setText(getResources().getString(R.string.dashboard));
}
viewBinding.homeScreenFrame.setOnClickListener(
diff --git a/app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java
new file mode 100644
index 00000000..0091b0f0
--- /dev/null
+++ b/app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java
@@ -0,0 +1,892 @@
+package org.mian.gitnex.adapters;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.core.content.res.ResourcesCompat;
+import androidx.core.text.HtmlCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import com.vdurmont.emoji.EmojiParser;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import org.apache.commons.lang3.StringUtils;
+import org.gitnex.tea4j.v2.models.Activity;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.mian.gitnex.R;
+import org.mian.gitnex.activities.IssueDetailActivity;
+import org.mian.gitnex.activities.ProfileActivity;
+import org.mian.gitnex.activities.RepoDetailActivity;
+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 org.mian.gitnex.helpers.contexts.IssueContext;
+import org.mian.gitnex.helpers.contexts.RepositoryContext;
+
+/**
+ * @author M M Arif
+ */
+public class DashboardAdapter extends RecyclerView.Adapter {
+
+ private final Context context;
+ TinyDB tinyDb;
+ private List activityList;
+ private OnLoadMoreListener loadMoreListener;
+ private boolean isLoading = false, isMoreDataAvailable = true;
+ private Intent intent;
+ public boolean isUserOrg = false;
+
+ public DashboardAdapter(List dataList, Context ctx) {
+ this.context = ctx;
+ this.activityList = dataList;
+ this.tinyDb = TinyDB.getInstance(ctx);
+ }
+
+ @NonNull @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ return new DashboardAdapter.DashboardHolder(
+ inflater.inflate(R.layout.list_dashboard_activity, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ if (position >= getItemCount() - 1
+ && isMoreDataAvailable
+ && !isLoading
+ && loadMoreListener != null) {
+ isLoading = true;
+ loadMoreListener.onLoadMore();
+ }
+
+ ((DashboardAdapter.DashboardHolder) holder).bindData(activityList.get(position));
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return activityList.size();
+ }
+
+ public void setMoreDataAvailable(boolean moreDataAvailable) {
+ isMoreDataAvailable = moreDataAvailable;
+ if (!isMoreDataAvailable) {
+ loadMoreListener.onLoadFinished();
+ }
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ public void notifyDataChanged() {
+ notifyDataSetChanged();
+ isLoading = false;
+ loadMoreListener.onLoadFinished();
+ }
+
+ public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
+ this.loadMoreListener = loadMoreListener;
+ }
+
+ public void updateList(List list) {
+ activityList = list;
+ notifyDataChanged();
+ }
+
+ public interface OnLoadMoreListener {
+
+ void onLoadMore();
+
+ void onLoadFinished();
+ }
+
+ class DashboardHolder extends RecyclerView.ViewHolder {
+
+ private final ImageView userAvatar;
+ private final TextView typeDetails;
+ private final TextView createdTime;
+ private final ImageView typeIcon;
+ private final TextView dashText;
+ private final LinearLayout dashTextFrame;
+
+ private Activity activityObject;
+
+ DashboardHolder(View itemView) {
+
+ super(itemView);
+ userAvatar = itemView.findViewById(R.id.user_avatar);
+ typeDetails = itemView.findViewById(R.id.type_details);
+ typeIcon = itemView.findViewById(R.id.type_icon);
+ createdTime = itemView.findViewById(R.id.created_time);
+ dashText = itemView.findViewById(R.id.text);
+ dashTextFrame = itemView.findViewById(R.id.dash_text_frame);
+
+ new Handler()
+ .postDelayed(
+ () -> {
+ if (!AppUtil.checkGhostUsers(
+ activityObject.getActUser().getLogin())) {
+
+ userAvatar.setOnLongClickListener(
+ loginId -> {
+ AppUtil.copyToClipboard(
+ context,
+ activityObject.getActUser().getLogin(),
+ context.getString(
+ R.string.copyLoginIdToClipBoard,
+ activityObject
+ .getActUser()
+ .getLogin()));
+ return true;
+ });
+
+ userAvatar.setOnClickListener(
+ v -> {
+ intent = new Intent(context, ProfileActivity.class);
+ intent.putExtra(
+ "username",
+ activityObject.getActUser().getLogin());
+ context.startActivity(intent);
+ });
+ }
+
+ if (activityObject.getOpType().equalsIgnoreCase("create_repo")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("rename_repo")
+ || activityObject.getOpType().equalsIgnoreCase("star_repo")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("transfer_repo")) {
+
+ itemView.setOnClickListener(
+ v -> {
+ Context context = v.getContext();
+ RepositoryContext repo =
+ new RepositoryContext(
+ activityObject.getRepo(), context);
+ repo.saveToDB(context);
+ Intent intent =
+ repo.getIntent(
+ context, RepoDetailActivity.class);
+ if (isUserOrg) {
+ intent.putExtra("openedFromUserOrg", true);
+ }
+ context.startActivity(intent);
+ });
+ }
+
+ if (activityObject.getOpType().equalsIgnoreCase("create_issue")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("comment_issue")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("close_issue")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("reopen_issue")) {
+
+ String[] parts =
+ activityObject.getRepo().getFullName().split("/");
+ final String repoOwner = parts[0];
+ final String repoName = parts[1];
+
+ RepositoryContext repo =
+ new RepositoryContext(repoOwner, repoName, context);
+
+ String[] contentParts =
+ activityObject.getContent().split("\\|");
+ String id = contentParts[0];
+
+ Intent intentIssueDetail =
+ new IssueContext(repo, Integer.parseInt(id), "open")
+ .getIntent(context, IssueDetailActivity.class);
+ intentIssueDetail.putExtra("openedFromLink", "true");
+
+ itemView.setOnClickListener(
+ v -> {
+ repo.saveToDB(context);
+ context.startActivity(intentIssueDetail);
+ });
+ }
+
+ if (activityObject
+ .getOpType()
+ .equalsIgnoreCase("create_pull_request")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("close_pull_request")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("reopen_pull_request")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("approve_pull_request")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("reject_pull_request")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("comment_pull")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("auto_merge_pull_request")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("merge_pull_request")) {
+
+ String[] parts =
+ activityObject.getRepo().getFullName().split("/");
+ final String repoOwner = parts[0];
+ final String repoName = parts[1];
+
+ RepositoryContext repo =
+ new RepositoryContext(repoOwner, repoName, context);
+
+ String[] contentParts =
+ activityObject.getContent().split("\\|");
+ String id = contentParts[0];
+
+ Intent intentIssueDetail =
+ new IssueContext(repo, Integer.parseInt(id), "open")
+ .getIntent(context, IssueDetailActivity.class);
+ intentIssueDetail.putExtra("openedFromLink", "true");
+
+ itemView.setOnClickListener(
+ v -> {
+ repo.saveToDB(context);
+ context.startActivity(intentIssueDetail);
+ });
+ }
+
+ if (activityObject.getOpType().equalsIgnoreCase("commit_repo")) {
+
+ if (activityObject.getContent().isEmpty()) {
+
+ itemView.setOnClickListener(
+ v -> {
+ RepositoryContext repo =
+ new RepositoryContext(
+ activityObject.getRepo(),
+ context);
+
+ Intent repoIntent =
+ new Intent(
+ context,
+ RepoDetailActivity.class);
+ repoIntent.putExtra("goToSection", "yes");
+ repoIntent.putExtra(
+ "goToSectionType", "commitsList");
+ repoIntent.putExtra(
+ "branchName",
+ activityObject
+ .getRefName()
+ .substring(
+ activityObject
+ .getRefName()
+ .lastIndexOf(
+ "/")
+ + 1)
+ .trim());
+
+ repo.saveToDB(context);
+ repoIntent.putExtra(
+ RepositoryContext.INTENT_EXTRA, repo);
+
+ context.startActivity(repoIntent);
+ });
+ }
+ }
+
+ if (activityObject.getOpType().equalsIgnoreCase("publish_release")
+ || activityObject
+ .getOpType()
+ .equalsIgnoreCase("push_tag")) {
+
+ itemView.setOnClickListener(
+ v -> {
+ RepositoryContext repo =
+ new RepositoryContext(
+ activityObject.getRepo(), context);
+
+ Intent repoIntent =
+ new Intent(
+ context, RepoDetailActivity.class);
+ repoIntent.putExtra("goToSection", "yes");
+ repoIntent.putExtra("goToSectionType", "releases");
+ repoIntent.putExtra(
+ "releaseTagName",
+ activityObject
+ .getRefName()
+ .substring(
+ activityObject
+ .getRefName()
+ .lastIndexOf(
+ "/")
+ + 1)
+ .trim());
+
+ repo.saveToDB(context);
+ repoIntent.putExtra(
+ RepositoryContext.INTENT_EXTRA, repo);
+
+ context.startActivity(repoIntent);
+ });
+ }
+ },
+ 200);
+ }
+
+ void bindData(Activity activity) {
+
+ this.activityObject = activity;
+ Locale locale = context.getResources().getConfiguration().locale;
+
+ int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
+
+ PicassoService.getInstance(context)
+ .get()
+ .load(activity.getActUser().getAvatarUrl())
+ .placeholder(R.drawable.loader_animated)
+ .transform(new RoundedTransformation(imgRadius, 0))
+ .resize(120, 120)
+ .centerCrop()
+ .into(userAvatar);
+
+ String username =
+ ""
+ + activity.getActUser().getLogin()
+ + "";
+
+ String headerString = "";
+ String typeString = "";
+
+ if (activity.getOpType().contains("repo")) {
+
+ if (activity.getOpType().equalsIgnoreCase("create_repo")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+ typeString = "created repository";
+ typeIcon.setImageResource(R.drawable.ic_repo);
+ } else if (activity.getOpType().equalsIgnoreCase("rename_repo")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+ typeString = "renamed repository from " + activity.getContent() + " to";
+ typeIcon.setImageResource(R.drawable.ic_repo);
+ } else if (activity.getOpType().equalsIgnoreCase("star_repo")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+ typeString = "starred";
+ typeIcon.setImageResource(R.drawable.ic_star);
+ } else if (activity.getOpType().equalsIgnoreCase("transfer_repo")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+ typeString = "transferred repository " + activity.getContent() + " to";
+ typeIcon.setImageResource(R.drawable.ic_arrow_up);
+ } else if (activity.getOpType().equalsIgnoreCase("commit_repo")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ if (activity.getContent().isEmpty()) {
+ String branch =
+ ""
+ + activity.getRefName()
+ .substring(
+ activity.getRefName().lastIndexOf("/") + 1)
+ .trim()
+ + "";
+ typeString = "created branch " + branch + " in";
+ } else {
+ String branch =
+ ""
+ + activity.getRefName()
+ .substring(
+ activity.getRefName().lastIndexOf("/") + 1)
+ .trim()
+ + "";
+ typeString = "pushed to " + branch + " at";
+
+ JSONObject commitsObj = null;
+ try {
+ commitsObj = new JSONObject(activity.getContent());
+ } catch (JSONException ignored) {
+ }
+
+ JSONArray commitsShaArray = null;
+ try {
+ commitsShaArray =
+ Objects.requireNonNull(commitsObj).getJSONArray("Commits");
+ } catch (JSONException ignored) {
+ }
+
+ dashTextFrame.setVisibility(View.VISIBLE);
+
+ dashTextFrame.setOrientation(LinearLayout.VERTICAL);
+ dashTextFrame.removeAllViews();
+
+ for (int i = 0; i < Objects.requireNonNull(commitsShaArray).length(); i++) {
+
+ try {
+
+ String timelineCommits =
+ ""
+ + StringUtils.substring(
+ String.valueOf(commitsShaArray.get(i)),
+ 9,
+ 19)
+ + "";
+
+ TextView dynamicCommitTv = new TextView(context);
+ dynamicCommitTv.setId(View.generateViewId());
+
+ dynamicCommitTv.setText(
+ HtmlCompat.fromHtml(
+ timelineCommits, HtmlCompat.FROM_HTML_MODE_LEGACY));
+
+ JSONObject sha1Obj = null;
+ try {
+ sha1Obj = (JSONObject) commitsShaArray.get(i);
+ } catch (JSONException ignored) {
+ }
+
+ JSONObject finalSha1Obj = sha1Obj;
+ dynamicCommitTv.setOnClickListener(
+ v14 -> {
+ RepositoryContext repo =
+ new RepositoryContext(
+ activity.getRepo(), context);
+
+ Intent repoIntent =
+ new Intent(context, RepoDetailActivity.class);
+ repoIntent.putExtra("goToSection", "yes");
+ repoIntent.putExtra("goToSectionType", "commit");
+ try {
+ assert finalSha1Obj != null;
+ repoIntent.putExtra(
+ "sha", (String) finalSha1Obj.get("Sha1"));
+ } catch (JSONException ignored) {
+ }
+
+ repo.saveToDB(context);
+ repoIntent.putExtra(
+ RepositoryContext.INTENT_EXTRA, repo);
+
+ context.startActivity(repoIntent);
+ });
+
+ dashTextFrame.setOrientation(LinearLayout.VERTICAL);
+ dashTextFrame.addView(dynamicCommitTv);
+ } catch (JSONException ignored) {
+ }
+ }
+ }
+ typeIcon.setImageResource(R.drawable.ic_commit);
+ }
+ } else if (activity.getOpType().contains("issue")) {
+
+ String id;
+ String content;
+ String[] contentParts = activity.getContent().split("\\|");
+ if (contentParts.length > 1) {
+ id = contentParts[0];
+ content = contentParts[1];
+ dashTextFrame.setVisibility(View.VISIBLE);
+ dashText.setText(EmojiParser.parseToUnicode(content));
+ } else {
+ id = contentParts[0];
+ }
+
+ if (activity.getOpType().equalsIgnoreCase("create_issue")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "opened issue";
+ typeIcon.setImageResource(R.drawable.ic_issue);
+ } else if (activity.getOpType().equalsIgnoreCase("comment_issue")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "commented on issue";
+ typeIcon.setImageResource(R.drawable.ic_comment);
+ } else if (activity.getOpType().equalsIgnoreCase("close_issue")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "closed issue";
+ typeIcon.setImageResource(R.drawable.ic_issue_closed);
+ } else if (activity.getOpType().equalsIgnoreCase("reopen_issue")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "reopened issue";
+ typeIcon.setImageResource(R.drawable.ic_reopen);
+ }
+ } else if (activity.getOpType().contains("pull")) {
+
+ String id;
+ String content;
+ String[] contentParts = activity.getContent().split("\\|");
+ if (contentParts.length > 1) {
+ id = contentParts[0];
+ content = contentParts[1];
+ dashTextFrame.setVisibility(View.VISIBLE);
+ dashText.setText(EmojiParser.parseToUnicode(content));
+ } else {
+ id = contentParts[0];
+ }
+
+ if (activity.getOpType().equalsIgnoreCase("create_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "created pull request";
+ typeIcon.setImageResource(R.drawable.ic_pull_request);
+ } else if (activity.getOpType().equalsIgnoreCase("close_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "closed pull request";
+ typeIcon.setImageResource(R.drawable.ic_issue_closed);
+ } else if (activity.getOpType().equalsIgnoreCase("reopen_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "reopened pull request";
+ typeIcon.setImageResource(R.drawable.ic_reopen);
+ } else if (activity.getOpType().equalsIgnoreCase("merge_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "merged pull request";
+ typeIcon.setImageResource(R.drawable.ic_pull_request);
+ } else if (activity.getOpType().equalsIgnoreCase("approve_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "approved";
+ typeIcon.setImageResource(R.drawable.ic_done);
+ } else if (activity.getOpType().equalsIgnoreCase("reject_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "suggested changes for";
+ typeIcon.setImageResource(R.drawable.ic_diff);
+ } else if (activity.getOpType().equalsIgnoreCase("comment_pull")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "commented on pull request";
+ typeIcon.setImageResource(R.drawable.ic_comment);
+ } else if (activity.getOpType().equalsIgnoreCase("auto_merge_pull_request")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + context.getResources().getString(R.string.hash)
+ + id
+ + "";
+ typeString = "automatically merged pull request";
+ typeIcon.setImageResource(R.drawable.ic_issue_closed);
+ }
+ } else if (activity.getOpType().contains("branch")) {
+
+ String content;
+ String[] contentParts = activity.getContent().split("\\|");
+ if (contentParts.length > 1) {
+ content = contentParts[1];
+ dashTextFrame.setVisibility(View.VISIBLE);
+ dashText.setText(EmojiParser.parseToUnicode(content));
+ }
+
+ if (activity.getOpType().equalsIgnoreCase("delete_branch")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ String branch =
+ ""
+ + activity.getRefName()
+ .substring(activity.getRefName().lastIndexOf("/") + 1)
+ .trim()
+ + "";
+
+ typeString = "deleted branch " + branch + " at";
+ typeIcon.setImageResource(R.drawable.ic_commit);
+ }
+ } else if (activity.getOpType().contains("tag")) {
+
+ if (activity.getOpType().equalsIgnoreCase("push_tag")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ String branch =
+ ""
+ + activity.getRefName()
+ .substring(activity.getRefName().lastIndexOf("/") + 1)
+ .trim()
+ + "";
+
+ typeString = "pushed tag " + branch + " to";
+ typeIcon.setImageResource(R.drawable.ic_commit);
+ } else if (activity.getOpType().equalsIgnoreCase("delete_tag")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ String branch =
+ ""
+ + activity.getRefName()
+ .substring(activity.getRefName().lastIndexOf("/") + 1)
+ .trim()
+ + "";
+
+ typeString = "deleted tag " + branch + " from";
+ typeIcon.setImageResource(R.drawable.ic_commit);
+ }
+ } else if (activity.getOpType().contains("release")) {
+
+ if (activity.getOpType().equalsIgnoreCase("publish_release")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ String branch =
+ ""
+ + activity.getRefName()
+ .substring(activity.getRefName().lastIndexOf("/") + 1)
+ .trim()
+ + "";
+
+ typeString = "released " + branch + " at";
+ typeIcon.setImageResource(R.drawable.ic_tag);
+ }
+ } else if (activity.getOpType().contains("mirror")) {
+
+ if (activity.getOpType().equalsIgnoreCase("mirror_sync_push")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ typeString = "synced commits to " + headerString + " at";
+ typeIcon.setImageResource(R.drawable.ic_tag);
+ } else if (activity.getOpType().equalsIgnoreCase("mirror_sync_create")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ typeString = "synced new reference " + headerString + " to";
+ typeIcon.setImageResource(R.drawable.ic_tag);
+ } else if (activity.getOpType().equalsIgnoreCase("mirror_sync_delete")) {
+
+ headerString =
+ ""
+ + activity.getRepo().getFullName()
+ + "";
+
+ typeString = "synced and deleted reference " + headerString + " at";
+ typeIcon.setImageResource(R.drawable.ic_tag);
+ }
+ } else {
+ dashTextFrame.setVisibility(View.GONE);
+ dashText.setVisibility(View.GONE);
+ }
+
+ typeDetails.setText(
+ HtmlCompat.fromHtml(
+ username + " " + typeString + " " + headerString,
+ HtmlCompat.FROM_HTML_MODE_LEGACY));
+
+ this.createdTime.setText(TimeHelper.formatTime(activity.getCreated(), locale));
+ this.createdTime.setOnClickListener(
+ new ClickListener(
+ TimeHelper.customDateFormatForToastDateFormat(activity.getCreated()),
+ context));
+ }
+ }
+}
diff --git a/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java
index df8be3bb..0b5cb5a4 100644
--- a/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java
+++ b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java
@@ -170,26 +170,31 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter {
+ 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;
+ });
+ }
},
200);
-
- issueAssigneeAvatar.setOnClickListener(
- v -> {
- 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;
- });
}
void bindData(Issue issue) {
diff --git a/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java
index 2fa28bc5..b29390de 100644
--- a/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java
+++ b/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java
@@ -3,6 +3,7 @@ package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Handler;
@@ -18,6 +19,7 @@ import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.text.HtmlCompat;
+import androidx.core.widget.ImageViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.vdurmont.emoji.EmojiParser;
@@ -106,6 +108,7 @@ public class PullRequestsAdapter extends RecyclerView.Adapter";
+ if (pullRequest.getTitle().contains("[WIP]")
+ || pullRequest.getTitle().contains("[wip]")) {
+ this.issuePrState.setVisibility(View.VISIBLE);
+ this.issuePrState.setImageResource(R.drawable.ic_draft);
+ ImageViewCompat.setImageTintList(
+ this.issuePrState,
+ ColorStateList.valueOf(
+ context.getResources().getColor(R.color.colorWhite, null)));
+ this.issuePrState.setBackgroundResource(R.drawable.shape_draft_release);
+ this.issuePrState.setPadding(
+ (int) context.getResources().getDimension(R.dimen.dimen4dp),
+ (int) context.getResources().getDimension(R.dimen.dimen0dp),
+ (int) context.getResources().getDimension(R.dimen.dimen4dp),
+ (int) context.getResources().getDimension(R.dimen.dimen0dp));
+ this.prTitle.setPadding(
+ (int) context.getResources().getDimension(R.dimen.dimen12dp),
+ (int) context.getResources().getDimension(R.dimen.dimen0dp),
+ (int) context.getResources().getDimension(R.dimen.dimen0dp),
+ (int) context.getResources().getDimension(R.dimen.dimen0dp));
+ } else {
+ this.issuePrState.setVisibility(View.GONE);
+ }
+
this.prTitle.setText(
HtmlCompat.fromHtml(
prNumber_ + " " + EmojiParser.parseToUnicode(pullRequest.getTitle()),
diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReplyFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReplyFragment.java
index a05863f1..9b0eef65 100644
--- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReplyFragment.java
+++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReplyFragment.java
@@ -314,7 +314,7 @@ public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
}
draftsHint.setVisibility(View.VISIBLE);
- valueAnimator.start();
+ // valueAnimator.start();
}
}
diff --git a/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java b/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java
new file mode 100644
index 00000000..10502f0a
--- /dev/null
+++ b/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java
@@ -0,0 +1,123 @@
+package org.mian.gitnex.fragments;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import java.util.ArrayList;
+import java.util.List;
+import org.gitnex.tea4j.v2.models.Activity;
+import org.mian.gitnex.R;
+import org.mian.gitnex.activities.BaseActivity;
+import org.mian.gitnex.activities.MainActivity;
+import org.mian.gitnex.adapters.DashboardAdapter;
+import org.mian.gitnex.databinding.FragmentDashboardBinding;
+import org.mian.gitnex.helpers.TinyDB;
+import org.mian.gitnex.viewmodels.DashboardViewModel;
+
+/**
+ * @author M M Arif
+ */
+public class DashboardFragment extends Fragment {
+
+ protected TinyDB tinyDB;
+ private DashboardViewModel dashboardViewModel;
+ private FragmentDashboardBinding binding;
+ private DashboardAdapter adapter;
+ private List activityList;
+ private int page = 1;
+ private String username;
+
+ @Override
+ public View onCreateView(
+ @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ binding = FragmentDashboardBinding.inflate(inflater, container, false);
+
+ Context ctx = getContext();
+ setHasOptionsMenu(true);
+
+ ((MainActivity) requireActivity())
+ .setActionBarTitle(getResources().getString(R.string.dashboard));
+
+ activityList = new ArrayList<>();
+
+ dashboardViewModel = new ViewModelProvider(this).get(DashboardViewModel.class);
+
+ username = ((BaseActivity) requireActivity()).getAccount().getAccount().getUserName();
+
+ binding.recyclerView.setHasFixedSize(true);
+ binding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
+
+ adapter = new DashboardAdapter(activityList, ctx);
+
+ binding.pullToRefresh.setOnRefreshListener(
+ () ->
+ new Handler(Looper.getMainLooper())
+ .postDelayed(
+ () -> {
+ activityList.clear();
+ binding.pullToRefresh.setRefreshing(false);
+ binding.progressBar.setVisibility(View.VISIBLE);
+ fetchDataAsync(username);
+ },
+ 250));
+
+ fetchDataAsync(username);
+
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // fetchDataAsync(username);
+ }
+
+ private void fetchDataAsync(String username) {
+
+ dashboardViewModel
+ .getActivitiesList(username, getContext(), binding)
+ .observe(
+ getViewLifecycleOwner(),
+ activityListMain -> {
+ adapter = new DashboardAdapter(activityListMain, getContext());
+ adapter.setLoadMoreListener(
+ new DashboardAdapter.OnLoadMoreListener() {
+
+ @Override
+ public void onLoadMore() {
+
+ page += 1;
+ dashboardViewModel.loadMoreActivities(
+ username, page, getContext(), adapter, binding);
+ binding.progressBar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onLoadFinished() {
+
+ binding.progressBar.setVisibility(View.GONE);
+ }
+ });
+
+ if (adapter.getItemCount() > 0) {
+ binding.recyclerView.setAdapter(adapter);
+ binding.noData.setVisibility(View.GONE);
+ } else {
+ adapter.notifyDataChanged();
+ binding.recyclerView.setAdapter(adapter);
+ binding.noData.setVisibility(View.VISIBLE);
+ }
+
+ binding.progressBar.setVisibility(View.GONE);
+ });
+ }
+}
diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java
new file mode 100644
index 00000000..e5efd68b
--- /dev/null
+++ b/app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java
@@ -0,0 +1,114 @@
+package org.mian.gitnex.viewmodels;
+
+import android.content.Context;
+import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+import java.util.List;
+import org.gitnex.tea4j.v2.models.Activity;
+import org.mian.gitnex.R;
+import org.mian.gitnex.adapters.DashboardAdapter;
+import org.mian.gitnex.clients.RetrofitClient;
+import org.mian.gitnex.databinding.FragmentDashboardBinding;
+import org.mian.gitnex.helpers.Constants;
+import org.mian.gitnex.helpers.Toasty;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+/**
+ * @author M M Arif
+ */
+public class DashboardViewModel extends ViewModel {
+
+ private MutableLiveData> activityList;
+ private int resultLimit;
+
+ public LiveData> getActivitiesList(
+ String username, Context ctx, FragmentDashboardBinding binding) {
+
+ activityList = new MutableLiveData<>();
+ resultLimit = Constants.getCurrentResultLimit(ctx);
+ loadActivityList(username, ctx, binding);
+ return activityList;
+ }
+
+ public void loadActivityList(String username, Context ctx, FragmentDashboardBinding binding) {
+
+ Call> call =
+ RetrofitClient.getApiInterface(ctx)
+ .userListActivityFeeds(username, false, null, 1, resultLimit);
+
+ call.enqueue(
+ new Callback<>() {
+
+ @Override
+ public void onResponse(
+ @NonNull Call> call,
+ @NonNull Response> response) {
+
+ if (response.isSuccessful()) {
+ activityList.postValue(response.body());
+ } else {
+ binding.progressBar.setVisibility(View.GONE);
+ Toasty.error(ctx, ctx.getString(R.string.genericError));
+ }
+ }
+
+ @Override
+ public void onFailure(
+ @NonNull Call> call, @NonNull Throwable t) {
+
+ Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
+ }
+ });
+ }
+
+ public void loadMoreActivities(
+ String username,
+ int page,
+ Context ctx,
+ DashboardAdapter adapter,
+ FragmentDashboardBinding binding) {
+
+ Call> call =
+ RetrofitClient.getApiInterface(ctx)
+ .userListActivityFeeds(username, false, null, page, resultLimit);
+
+ call.enqueue(
+ new Callback<>() {
+
+ @Override
+ public void onResponse(
+ @NonNull Call> call,
+ @NonNull Response> response) {
+
+ if (response.isSuccessful()) {
+
+ List list = activityList.getValue();
+ assert list != null;
+ assert response.body() != null;
+
+ if (response.body().size() != 0) {
+ list.addAll(response.body());
+ adapter.updateList(list);
+ } else {
+ adapter.setMoreDataAvailable(false);
+ }
+ } else {
+ binding.progressBar.setVisibility(View.GONE);
+ Toasty.error(ctx, ctx.getString(R.string.genericError));
+ }
+ }
+
+ @Override
+ public void onFailure(
+ @NonNull Call> call, @NonNull Throwable t) {
+
+ Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
+ }
+ });
+ }
+}
diff --git a/app/src/main/res/drawable/ic_dashboard.xml b/app/src/main/res/drawable/ic_dashboard.xml
new file mode 100644
index 00000000..8cc041b8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_dashboard.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_draft.xml b/app/src/main/res/drawable/ic_draft.xml
new file mode 100644
index 00000000..e63c7a9b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_draft.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/shape_beta_badge.xml b/app/src/main/res/drawable/shape_beta_badge.xml
new file mode 100644
index 00000000..3effc35e
--- /dev/null
+++ b/app/src/main/res/drawable/shape_beta_badge.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/shape_draft_release.xml b/app/src/main/res/drawable/shape_draft_release.xml
index 66e02aef..65c5db56 100644
--- a/app/src/main/res/drawable/shape_draft_release.xml
+++ b/app/src/main/res/drawable/shape_draft_release.xml
@@ -8,7 +8,7 @@
+ android:radius="@dimen/dimen6dp">
diff --git a/app/src/main/res/drawable/shape_pre_release.xml b/app/src/main/res/drawable/shape_pre_release.xml
index 1f250589..4a08a2a0 100644
--- a/app/src/main/res/drawable/shape_pre_release.xml
+++ b/app/src/main/res/drawable/shape_pre_release.xml
@@ -8,7 +8,7 @@
+ android:radius="@dimen/dimen6dp">
diff --git a/app/src/main/res/drawable/shape_stable_release.xml b/app/src/main/res/drawable/shape_stable_release.xml
index 9f3dedc6..c74d7fc3 100644
--- a/app/src/main/res/drawable/shape_stable_release.xml
+++ b/app/src/main/res/drawable/shape_stable_release.xml
@@ -8,7 +8,7 @@
+ android:radius="@dimen/dimen6dp">
diff --git a/app/src/main/res/layout/badge_beta.xml b/app/src/main/res/layout/badge_beta.xml
new file mode 100644
index 00000000..291f633b
--- /dev/null
+++ b/app/src/main/res/layout/badge_beta.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml
new file mode 100644
index 00000000..c14c07c8
--- /dev/null
+++ b/app/src/main/res/layout/fragment_dashboard.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_dashboard_activity.xml b/app/src/main/res/layout/list_dashboard_activity.xml
new file mode 100644
index 00000000..6949b03f
--- /dev/null
+++ b/app/src/main/res/layout/list_dashboard_activity.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_pr.xml b/app/src/main/res/layout/list_pr.xml
index 29d657bc..c9bdfdeb 100644
--- a/app/src/main/res/layout/list_pr.xml
+++ b/app/src/main/res/layout/list_pr.xml
@@ -54,15 +54,31 @@
android:layout_height="wrap_content"
android:orientation="vertical">
-
+ android:orientation="horizontal">
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/drawer_menu.xml b/app/src/main/res/menu/drawer_menu.xml
index 7bf01c41..5be95c19 100644
--- a/app/src/main/res/menu/drawer_menu.xml
+++ b/app/src/main/res/menu/drawer_menu.xml
@@ -7,6 +7,12 @@
+
+
diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml
index 42055e81..2d985ff3 100644
--- a/app/src/main/res/values/settings.xml
+++ b/app/src/main/res/values/settings.xml
@@ -74,6 +74,7 @@
- @string/navMyIssues
- @string/navMostVisited
- @string/navNotes
+ - @string/dashboard
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 321459c2..f2a757ae 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -515,6 +515,7 @@
Open in Browser
Delete %s
Reset
+ BETA
Explore users
@@ -863,4 +864,6 @@
Language Statistics
%s%%
+
+ Dashboard