From 1693acaa70c12ae051952bd1a906bd4245dfce67 Mon Sep 17 00:00:00 2001 From: M M Arif Date: Mon, 2 Aug 2021 20:04:33 +0200 Subject: [PATCH] User profile view (#931) Closes #881 Please suggest on current data shown as some may be related to personal(email etc), but at this moment we have not much to show either. So sticking to it is my view on this. I will extend the taps on profile images once we agree what to show. @gitnex/Code-Managers - [x] Detail - [x] Repositories - [x] Starred Repos - [x] Followers - [x] Following - [x] Tap on all profile images - [x] Organizations Co-authored-by: M M Arif Co-authored-by: opyale Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/931 Reviewed-by: 6543 <6543@noreply.codeberg.org> Co-authored-by: M M Arif Co-committed-by: M M Arif --- app/build.gradle | 9 +- app/src/main/AndroidManifest.xml | 4 +- .../gitnex/activities/CreateRepoActivity.java | 2 +- .../activities/IssueDetailActivity.java | 33 ++- .../mian/gitnex/activities/MainActivity.java | 12 +- ...ivity.java => MyProfileEmailActivity.java} | 2 +- .../gitnex/activities/ProfileActivity.java | 143 +++++++++ .../gitnex/adapters/AdminGetUsersAdapter.java | 12 +- .../gitnex/adapters/CollaboratorsAdapter.java | 12 +- .../gitnex/adapters/ExploreIssuesAdapter.java | 13 +- .../gitnex/adapters/IssueCommentsAdapter.java | 29 +- .../mian/gitnex/adapters/IssuesAdapter.java | 15 +- .../gitnex/adapters/MembersByOrgAdapter.java | 12 +- ...apter.java => MyProfileEmailsAdapter.java} | 10 +- ...er.java => MyProfileFollowersAdapter.java} | 24 +- ...er.java => MyProfileFollowingAdapter.java} | 24 +- .../gitnex/adapters/PullRequestsAdapter.java | 25 +- .../mian/gitnex/adapters/ReleasesAdapter.java | 13 + .../adapters/RepoStargazersAdapter.java | 18 +- .../gitnex/adapters/RepoWatchersAdapter.java | 18 +- .../adapters/TeamMembersByOrgAdapter.java | 12 +- .../gitnex/adapters/UserSearchAdapter.java | 20 +- .../UserSearchForTeamMemberAdapter.java | 21 +- .../adapters/profile/FollowersAdapter.java | 166 +++++++++++ .../adapters/profile/FollowingAdapter.java | 166 +++++++++++ .../profile/OrganizationsAdapter.java | 137 +++++++++ .../adapters/profile/RepositoriesAdapter.java | 196 +++++++++++++ .../profile/StarredRepositoriesAdapter.java | 197 +++++++++++++ ...java => BottomSheetMyProfileFragment.java} | 6 +- ...ment.java => MyProfileEmailsFragment.java} | 14 +- ...t.java => MyProfileFollowersFragment.java} | 28 +- ...t.java => MyProfileFollowingFragment.java} | 32 +- ...leFragment.java => MyProfileFragment.java} | 47 ++- .../fragments/RepositoriesFragment.java | 12 +- .../fragments/profile/DetailFragment.java | 160 ++++++++++ .../fragments/profile/FollowersFragment.java | 272 +++++++++++++++++ .../fragments/profile/FollowingFragment.java | 273 +++++++++++++++++ .../profile/OrganizationsFragment.java | 274 ++++++++++++++++++ .../profile/RepositoriesFragment.java | 271 +++++++++++++++++ .../profile/StarredRepositoriesFragment.java | 273 +++++++++++++++++ .../org/mian/gitnex/helpers/Constants.java | 1 - .../viewmodels/OrganizationListViewModel.java | 2 +- .../viewmodels/ProfileFollowersViewModel.java | 2 +- .../viewmodels/ProfileFollowingViewModel.java | 2 +- app/src/main/res/layout/activity_profile.xml | 54 ++++ app/src/main/res/layout/fragment_profile.xml | 2 +- .../res/layout/fragment_profile_detail.xml | 195 +++++++++++++ ... fragment_profile_followers_following.xml} | 13 +- .../res/layout/fragment_profile_following.xml | 40 --- .../main/res/layout/fragment_repositories.xml | 9 + ...l => list_profile_followers_following.xml} | 0 .../res/layout/list_profile_following.xml | 41 --- app/src/main/res/values/strings.xml | 1 + 53 files changed, 3092 insertions(+), 277 deletions(-) rename app/src/main/java/org/mian/gitnex/activities/{ProfileEmailActivity.java => MyProfileEmailActivity.java} (98%) create mode 100644 app/src/main/java/org/mian/gitnex/activities/ProfileActivity.java rename app/src/main/java/org/mian/gitnex/adapters/{ProfileEmailsAdapter.java => MyProfileEmailsAdapter.java} (82%) rename app/src/main/java/org/mian/gitnex/adapters/{ProfileFollowersAdapter.java => MyProfileFollowersAdapter.java} (72%) rename app/src/main/java/org/mian/gitnex/adapters/{ProfileFollowingAdapter.java => MyProfileFollowingAdapter.java} (72%) create mode 100644 app/src/main/java/org/mian/gitnex/adapters/profile/FollowersAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/adapters/profile/FollowingAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/adapters/profile/OrganizationsAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/adapters/profile/RepositoriesAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/adapters/profile/StarredRepositoriesAdapter.java rename app/src/main/java/org/mian/gitnex/fragments/{BottomSheetProfileFragment.java => BottomSheetMyProfileFragment.java} (80%) rename app/src/main/java/org/mian/gitnex/fragments/{ProfileEmailsFragment.java => MyProfileEmailsFragment.java} (90%) rename app/src/main/java/org/mian/gitnex/fragments/{ProfileFollowersFragment.java => MyProfileFollowersFragment.java} (77%) rename app/src/main/java/org/mian/gitnex/fragments/{ProfileFollowingFragment.java => MyProfileFollowingFragment.java} (75%) rename app/src/main/java/org/mian/gitnex/fragments/{ProfileFragment.java => MyProfileFragment.java} (86%) create mode 100644 app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java create mode 100644 app/src/main/res/layout/activity_profile.xml create mode 100644 app/src/main/res/layout/fragment_profile_detail.xml rename app/src/main/res/layout/{fragment_profile_followers.xml => fragment_profile_followers_following.xml} (75%) delete mode 100644 app/src/main/res/layout/fragment_profile_following.xml rename app/src/main/res/layout/{list_profile_followers.xml => list_profile_followers_following.xml} (100%) delete mode 100644 app/src/main/res/layout/list_profile_following.xml diff --git a/app/build.gradle b/app/build.gradle index 86c3f050..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.7.0-alpha03" + 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" @@ -108,9 +109,9 @@ dependencies { 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.10" + 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(ctx) - .getOrgOwners(instanceToken); + .getOrgOwners(instanceToken, 1, 50); call.enqueue(new Callback>() { 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 53f79b2d..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; @@ -591,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(); @@ -612,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)); @@ -621,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 { @@ -759,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)); @@ -768,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/MainActivity.java b/app/src/main/java/org/mian/gitnex/activities/MainActivity.java index 2168ecc4..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(); @@ -389,7 +389,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig return; case "profile": - 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); return; @@ -431,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; @@ -569,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/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/adapters/AdminGetUsersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java index a01a1d3d..686883a5 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.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; @@ -15,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.amulyakhare.textdrawable.TextDrawable; 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; @@ -31,7 +33,7 @@ public class AdminGetUsersAdapter 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/ExploreIssuesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java index e24250c0..5067a22c 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.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; @@ -64,8 +65,6 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter { - - Context context = v.getContext(); Intent intent = new Intent(context, IssueDetailActivity.class); intent.putExtra("issueNumber", issue.getNumber()); @@ -99,10 +98,14 @@ public class ExploreIssuesAdapter 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; }); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java index 0ead649f..218984ac 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java @@ -20,6 +20,7 @@ import com.google.gson.JsonElement; import com.vdurmont.emoji.EmojiParser; import org.gitnex.tea4j.models.IssueComments; 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.fragments.BottomSheetReplyFragment; @@ -87,10 +88,9 @@ 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); @@ -108,7 +108,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { tinyDB.putBoolean("commentEdited", true); @@ -148,10 +148,10 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { @@ -195,27 +195,32 @@ 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 -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); - Context context = loginId.getContext(); + avatar.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/IssuesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/IssuesAdapter.java index 70d948b1..252fa561 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/IssuesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/IssuesAdapter.java @@ -16,6 +16,7 @@ import com.vdurmont.emoji.EmojiParser; 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.helpers.AppUtil; import org.mian.gitnex.helpers.ClickListener; @@ -110,9 +111,6 @@ public class IssuesAdapter 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,12 +121,15 @@ 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") 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/ProfileEmailsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/MyProfileEmailsAdapter.java similarity index 82% rename from app/src/main/java/org/mian/gitnex/adapters/ProfileEmailsAdapter.java rename to app/src/main/java/org/mian/gitnex/adapters/MyProfileEmailsAdapter.java index 3757bcfc..dd867c5c 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ProfileEmailsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/MyProfileEmailsAdapter.java @@ -18,7 +18,7 @@ import java.util.List; * Author M M Arif */ -public class ProfileEmailsAdapter 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,12 +131,15 @@ 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") @@ -176,38 +175,30 @@ 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 a0bb8962..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); + }); } } @@ -94,6 +106,7 @@ 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/TeamMembersByOrgAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/TeamMembersByOrgAdapter.java index b818f515..392e17c1 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/TeamMembersByOrgAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/TeamMembersByOrgAdapter.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.text.Html; import android.view.LayoutInflater; @@ -12,6 +13,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; @@ -27,7 +29,7 @@ public class TeamMembersByOrgAdapter extends BaseAdapter { private final List 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/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/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/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/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 3c06b35d..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,7 +27,6 @@ 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"; 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/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml new file mode 100644 index 00000000..7431dba1 --- /dev/null +++ b/app/src/main/res/layout/activity_profile.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 0a98053c..ea65f0b3 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -9,7 +9,7 @@ android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_profile_followers.xml b/app/src/main/res/layout/fragment_profile_followers_following.xml similarity index 75% rename from app/src/main/res/layout/fragment_profile_followers.xml rename to app/src/main/res/layout/fragment_profile_followers_following.xml index 26dac2bc..e027c6b9 100644 --- a/app/src/main/res/layout/fragment_profile_followers.xml +++ b/app/src/main/res/layout/fragment_profile_followers_following.xml @@ -19,15 +19,24 @@ + + - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_repositories.xml b/app/src/main/res/layout/fragment_repositories.xml index 91ca3bc7..d792ec3c 100644 --- a/app/src/main/res/layout/fragment_repositories.xml +++ b/app/src/main/res/layout/fragment_repositories.xml @@ -29,6 +29,15 @@ style="@style/Widget.MaterialComponents.LinearProgressIndicator" app:indicatorColor="?attr/progressIndicatorColor" /> + + - - - - - - - - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 26c1ff99..0779def5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -753,4 +753,5 @@ Indicates the progress of ongoing downloads Updated %s + Joined