Add Explore function #71

Merged
mmarif merged 4 commits from 6543/GitNex:repoSearch into master 2019-10-10 16:02:07 +00:00
8 changed files with 506 additions and 1 deletions

View File

@ -21,6 +21,7 @@ import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.AboutFragment;
import org.mian.gitnex.fragments.ExploreRepositoriesFragment;
import org.mian.gitnex.fragments.MyRepositoriesFragment;
import org.mian.gitnex.fragments.NavSubMenuBottomSheetFragment;
import org.mian.gitnex.fragments.OrganizationsFragment;
@ -278,6 +279,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StarredRepositoriesFragment()).commit();
break;
case R.id.nav_explore:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new ExploreRepositoriesFragment()).commit();
break;
}
drawer.closeDrawer(GravityCompat.START);

View File

@ -0,0 +1,216 @@
package org.mian.gitnex.adapters;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.squareup.picasso.Picasso;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OpenRepoInBrowserActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.TinyDB;
import java.lang.reflect.Field;
import java.util.List;
/**
* Author M M Arif
*/
public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepositoriesAdapter.ReposSearchViewHolder> {
private List<UserRepositories> searchedReposList;
private Context mCtx;
public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context mCtx) {
this.mCtx = mCtx;
this.searchedReposList = dataList;
}
static class ReposSearchViewHolder extends RecyclerView.ViewHolder {
private ImageView image;
private TextView mTextView1;
private TextView mTextView2;
private TextView fullName;
private ImageView repoPrivatePublic;
private TextView repoStars;
private TextView repoForks;
private TextView repoOpenIssuesCount;
private ReposSearchViewHolder(View itemView) {
super(itemView);
mTextView1 = itemView.findViewById(R.id.repoName);
mTextView2 = itemView.findViewById(R.id.repoDescription);
image = itemView.findViewById(R.id.imageAvatar);
fullName = itemView.findViewById(R.id.repoFullName);
repoPrivatePublic = itemView.findViewById(R.id.imageRepoType);
repoStars = itemView.findViewById(R.id.repoStars);
repoForks = itemView.findViewById(R.id.repoForks);
repoOpenIssuesCount = itemView.findViewById(R.id.repoOpenIssuesCount);
ImageView reposDropdownMenu = itemView.findViewById(R.id.reposDropdownMenu);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
TextView repoFullName = v.findViewById(R.id.repoFullName);
Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", repoFullName.getText().toString());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("repoFullName", repoFullName.getText().toString());
tinyDb.putBoolean("resumeIssues", true);
context.startActivity(intent);
}
});
reposDropdownMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = v.getContext();
Context context_ = new ContextThemeWrapper(context, R.style.popupMenuStyle);
PopupMenu popupMenu = new PopupMenu(context_, v);
popupMenu.inflate(R.menu.repo_dotted_list_menu);
Object menuHelper;
Class[] argTypes;
try {
Field fMenuHelper = PopupMenu.class.getDeclaredField("mPopup");
fMenuHelper.setAccessible(true);
menuHelper = fMenuHelper.get(popupMenu);
argTypes = new Class[] { boolean.class };
menuHelper.getClass().getDeclaredMethod("setForceShowIcon",
argTypes).invoke(menuHelper, true);
} catch (Exception e) {
popupMenu.show();
return;
}
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.repoStargazers:
Intent intent = new Intent(context, RepoStargazersActivity.class);
intent.putExtra("repoFullNameForStars", fullName.getText());
context.startActivity(intent);
break;
case R.id.repoWatchers:
Intent intentW = new Intent(context, RepoWatchersActivity.class);
intentW.putExtra("repoFullNameForWatchers", fullName.getText());
context.startActivity(intentW);
break;
case R.id.repoOpenInBrowser:
Intent intentOpenInBrowser = new Intent(context, OpenRepoInBrowserActivity.class);
intentOpenInBrowser.putExtra("repoFullNameBrowser", fullName.getText());
context.startActivity(intentOpenInBrowser);
break;
}
return false;
}
});
popupMenu.show();
}
});
}
}
@NonNull
@Override
public ExploreRepositoriesAdapter.ReposSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.repos_list, parent, false);
return new ExploreRepositoriesAdapter.ReposSearchViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull final ExploreRepositoriesAdapter.ReposSearchViewHolder holder, int position) {
final UserRepositories currentItem = searchedReposList.get(position);
holder.mTextView2.setVisibility(View.GONE);
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String firstCharacter = String.valueOf(currentItem.getName().charAt(0));
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.useFont(Typeface.DEFAULT)
.fontSize(18)
.toUpperCase()
.width(28)
.height(28)
.endConfig()
.buildRoundRect(firstCharacter, color, 3);
if (currentItem.getAvatar_url() != null) {
if (!currentItem.getAvatar_url().equals("")) {
Picasso.get().load(currentItem.getAvatar_url()).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(holder.image);
} else {
holder.image.setImageDrawable(drawable);
}
}
else {
holder.image.setImageDrawable(drawable);
}
holder.mTextView1.setText(currentItem.getName());
if (!currentItem.getDescription().equals("")) {
holder.mTextView2.setVisibility(View.VISIBLE);
holder.mTextView2.setText(currentItem.getDescription());
}
holder.fullName.setText(currentItem.getFullname());
if(currentItem.getPrivateFlag()) {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_lock_bold);
}
else {
holder.repoPrivatePublic.setImageResource(R.drawable.ic_public);
}
holder.repoStars.setText(currentItem.getStars_count());
holder.repoForks.setText(currentItem.getForks_count());
holder.repoOpenIssuesCount.setText(currentItem.getOpen_issues_count());
}
@Override
public int getItemCount() {
return searchedReposList.size();
}
}

View File

@ -0,0 +1,194 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.adapters.ExploreRepositoriesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.ExploreRepositories;
import org.mian.gitnex.models.UserRepositories;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
+ * Template Author M M Arif
+ * Author 6543
+ */
public class ExploreRepositoriesFragment extends Fragment {
private static String repoNameF = "param2";
private static String repoOwnerF = "param1";
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
private TextView noData;
private TextView searchKeyword;
private Boolean repoTypeInclude = true;
private String sort = "updated";
private String order = "asc";
private ExploreRepositoriesAdapter adapter;
private OnFragmentInteractionListener mListener;
public ExploreRepositoriesFragment() {
}
public static ExploreRepositoriesFragment newInstance(String param1, String param2) {
ExploreRepositoriesFragment fragment = new ExploreRepositoriesFragment();
Bundle args = new Bundle();
args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
String repoName = getArguments().getString(repoNameF);
String repoOwner = getArguments().getString(repoOwnerF);
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext()));
final View v = inflater.inflate(R.layout.fragment_explore_repo, container, false);
//setHasOptionsMenu(true);
((MainActivity) Objects.requireNonNull(getActivity())).setActionBarTitle(getResources().getString(R.string.pageTitleExplore));
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
searchKeyword = v.findViewById(R.id.searchKeyword);
noData = v.findViewById(R.id.noData);
mProgressBar = v.findViewById(R.id.progress_bar);
mRecyclerView = v.findViewById(R.id.recyclerViewReposSearch);
if(connToInternet) {
searchKeyword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
if(!searchKeyword.getText().toString().equals("")) {
mProgressBar.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
loadSearchReposList(instanceUrl, instanceToken, loginUid, searchKeyword.getText().toString(), repoTypeInclude, sort, order, getContext());
}
}
return false;
}
});
}
else {
mProgressBar.setVisibility(View.GONE);
}
return v;
}
private void loadSearchReposList(String instanceUrl, String instanceToken, String loginUid, String searchKeyword, Boolean repoTypeInclude, String sort, String order, final Context context) {
Call<ExploreRepositories> call = RetrofitClient
.getInstance(instanceUrl)
.getApiInterface()
.queryRepos(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), searchKeyword, repoTypeInclude, sort, order);
call.enqueue(new Callback<ExploreRepositories>() {
@Override
public void onResponse(@NonNull Call<ExploreRepositories> call, @NonNull Response<ExploreRepositories> response) {
if (response.isSuccessful()) {
assert response.body() != null;
getReposList(response.body().getSearchedData(), context);
} else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) {
Log.i("onFailure", t.getMessage());
}
});
}
private void getReposList(List<UserRepositories> dataList, Context context) {
adapter = new ExploreRepositoriesAdapter(dataList, context);
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
noData.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
}
else {
noData.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}

View File

@ -3,6 +3,7 @@ package org.mian.gitnex.interfaces;
import com.google.gson.JsonElement;
import org.mian.gitnex.models.AddEmail;
import org.mian.gitnex.models.Branches;
import org.mian.gitnex.models.ExploreRepositories;
import org.mian.gitnex.models.Files;
import org.mian.gitnex.models.NewFile;
import org.mian.gitnex.models.UpdateIssueAssignee;
@ -213,6 +214,9 @@ public interface ApiInterface {
@GET("repos/{owner}/{repo}/subscribers") // get all repo watchers
Call<List<UserInfo>> getRepoWatchers(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/search") // get all the repos which match the query string
Call<ExploreRepositories> queryRepos(@Header("Authorization") String token, @Query("q") String searchKeyword, @Query("private") Boolean repoTypeInclude, @Query("sort") String sort, @Query("order") String order);
@POST("repos/{owner}/{repo}/contents/{file}") // create new file
Call<JsonElement> createNewFile(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("file") String fileName, @Body NewFile jsonStr);
@ -224,4 +228,4 @@ public interface ApiInterface {
@GET("repos/{owner}/{repo}/contents/{fileDir}") // get all the sub files and dirs of a repository
Call<List<Files>> getDirFiles(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("fileDir") String fileDir);
}
}

View File

@ -0,0 +1,22 @@
package org.mian.gitnex.models;
import java.util.ArrayList;
/**
* Author M M Arif
*/
public class ExploreRepositories {
private ArrayList<UserRepositories> data;
private Boolean ok;
public ArrayList<UserRepositories> getSearchedData() {
return data;
}
public Boolean getOk() {
return ok;
}
}

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:orientation="vertical">
<EditText
android:id="@+id/searchKeyword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="14sp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:inputType="text"
android:background="@drawable/shape_inputs"
android:textColor="@color/white"
android:textColorHint="@color/colorAccent"
android:hint="@string/exploreTextBoxHint"
android:textColorHighlight="@color/white"
android:imeOptions="actionSend" />
<TextView
android:id="@+id/noData"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:gravity="center"
android:text="@string/noDataFound"
android:textColor="@color/white"
android:textSize="20sp"
android:visibility="gone" />
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewReposSearch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="0dp"
android:scrollbars="vertical" />
</LinearLayout>

View File

@ -17,6 +17,9 @@
<item android:id="@+id/nav_repositories"
android:icon="@drawable/ic_repos"
android:title="@string/navRepos" />
<item android:id="@+id/nav_explore"
android:icon="@drawable/ic_search"
android:title="@string/navExplore" />
<item android:id="@+id/nav_profile"
android:icon="@drawable/ic_person_24dp"
android:title="@string/navProfile" />

View File

@ -30,6 +30,7 @@
<string name="navAbout">About</string>
<string name="navRate">Rate GitNex</string>
<string name="navLogout">Logout</string>
<string name="navExplore">Explore</string>
<!-- menu items -->
<!-- page titles -->
@ -53,6 +54,7 @@
<string name="pageTitleCreateTeam">New Team</string>
<string name="pageTitleAddEmail">Add Email Address</string>
<string name="pageTitleNewFile">New File</string>
<string name="pageTitleExplore">Explore</string>
<!-- page titles -->
<string name="appVersion">Version\u0020:\u0020</string>
@ -501,5 +503,6 @@
<!-- generic copy -->
<string name="translateText">Translate GitNex with Crowdin</string>
<string name="exploreTextBoxHint">Explore repositories</string>
</resources>