added GitHub's profile pinned repo

This commit is contained in:
Kosh Sergani 2017-08-09 18:16:26 +08:00
parent 08b844409f
commit 255ec2e8c0
12 changed files with 324 additions and 13 deletions

View File

@ -32,7 +32,7 @@ We have configured snapshots of FastHub, which can be downloaded from [AppVeyor
- Markdown and code highlighting support
- Notifications overview and "Mark all as read"
- Search users/orgs, repos, issues/prs & code.
- Pinned Repos
- FastHub & GitHub Pinned Repos
- Trending
- Wiki
- **Repositories**
@ -73,6 +73,7 @@ We have configured snapshots of FastHub, which can be downloaded from [AppVeyor
- Teams & Teams repos
- Repos
- **Users**
- GitHub Pinned Repos
- Follow/Unfollow users
- View user feeds
- Contribution graph.

View File

@ -0,0 +1,28 @@
query getPinnedRepos($login: String!) {
user(login: $login) {
pinnedRepositories(first: 100) {
edges {
node {
name
url
issues(states: OPEN) {
totalCount
}
pullRequests(states: OPEN) {
totalCount
}
stargazers {
totalCount
}
forks {
totalCount
}
primaryLanguage {
name
color
}
}
}
}
}
}

View File

@ -0,0 +1,24 @@
package com.fastaccess.ui.adapter
import android.view.ViewGroup
import com.fastaccess.ui.adapter.viewholder.ProfilePinnedReposViewHolder
import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
import pr.GetPinnedReposQuery
/**
* Created by kosh on 09/08/2017.
*/
class ProfilePinnedReposAdapter(data: List<GetPinnedReposQuery.Node>) : BaseRecyclerAdapter<GetPinnedReposQuery.Node,
ProfilePinnedReposViewHolder, BaseViewHolder.OnItemClickListener<GetPinnedReposQuery.Node>>(data) {
override fun viewHolder(parent: ViewGroup, viewType: Int): ProfilePinnedReposViewHolder {
return ProfilePinnedReposViewHolder.newInstance(parent, this)
}
override fun onBindView(holder: ProfilePinnedReposViewHolder, position: Int) {
holder.bind(data[position])
}
}

View File

@ -0,0 +1,50 @@
package com.fastaccess.ui.adapter.viewholder
import android.graphics.Color
import android.view.View
import android.view.ViewGroup
import butterknife.BindView
import com.fastaccess.R
import com.fastaccess.ui.widgets.FontTextView
import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
import pr.GetPinnedReposQuery
/**
* Created by kosh on 09/08/2017.
*/
class ProfilePinnedReposViewHolder private constructor(view: View, adapter: BaseRecyclerAdapter<*, *, *>) :
BaseViewHolder<GetPinnedReposQuery.Node>(view, adapter) {
@BindView(R.id.title) lateinit var title: FontTextView
@BindView(R.id.issues) lateinit var issues: FontTextView
@BindView(R.id.pullRequests) lateinit var pullRequest: FontTextView
@BindView(R.id.language) lateinit var language: FontTextView
@BindView(R.id.stars) lateinit var stars: FontTextView
@BindView(R.id.forks) lateinit var forks: FontTextView
override fun bind(t: GetPinnedReposQuery.Node) {
title.text = t.name()
issues.text = "${t.issues().totalCount()}"
pullRequest.text = "${t.pullRequests().totalCount()}"
forks.text = "${t.forks().totalCount()}"
stars.text = "${t.stargazers().totalCount()}"
t.primaryLanguage()?.let {
language.text = it.name()
it.color()?.let {
if (it.startsWith("#")) {
language.tintDrawables(Color.parseColor(it))
} else {
val color = "#$it"
language.tintDrawables(Color.parseColor(color))
}
}
}
}
companion object {
fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>): ProfilePinnedReposViewHolder {
return ProfilePinnedReposViewHolder(getView(parent, R.layout.profile_pinned_repo_row_item), adapter)
}
}
}

View File

@ -26,7 +26,7 @@ import pr.PullRequestTimelineQuery
* Created by kosh on 03/08/2017.
*/
class PullRequestEventViewHolder private constructor(private val view: View, adapter: BaseRecyclerAdapter<*, *, *>) :
class PullRequestEventViewHolder private constructor(view: View, adapter: BaseRecyclerAdapter<*, *, *>) :
BaseViewHolder<PullRequestTimelineModel>(view, adapter) {
@BindView(R.id.stateImage) lateinit var stateImage: ForegroundImageView
@ -316,7 +316,7 @@ class PullRequestEventViewHolder private constructor(private val view: View, ada
private fun commitEvent(event: PullRequestTimelineQuery.AsCommit) {
event.author()?.let {
stateText.text = SpannableBuilder.builder()//Review[k0shk0sh] We may want to suppress more then 3 or 4 commits. since it will clog the it
.bold(if(it.user() == null) it.name() else it.user()?.login())
.bold(if (it.user() == null) it.name() else it.user()?.login())
.append(" ")
.append("committed")
.append(" ")

View File

@ -34,13 +34,16 @@ import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.ParseDateFormat;
import com.fastaccess.provider.emoji.EmojiParser;
import com.fastaccess.provider.scheme.SchemeParser;
import com.fastaccess.ui.adapter.ProfileOrgsAdapter;
import com.fastaccess.ui.adapter.ProfilePinnedReposAdapter;
import com.fastaccess.ui.base.BaseFragment;
import com.fastaccess.ui.modules.profile.ProfilePagerMvp;
import com.fastaccess.ui.widgets.AvatarLayout;
import com.fastaccess.ui.widgets.FontTextView;
import com.fastaccess.ui.widgets.SpannableBuilder;
import com.fastaccess.ui.widgets.contributions.GitHubContributionsView;
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder;
import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView;
import com.fastaccess.ui.widgets.recyclerview.layout_manager.GridManager;
@ -48,6 +51,7 @@ import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import pr.GetPinnedReposQuery;
import static android.view.Gravity.TOP;
import static android.view.View.GONE;
@ -78,12 +82,15 @@ public class ProfileOverviewFragment extends BaseFragment<ProfileOverviewMvp.Vie
@BindView(R.id.followers) FontTextView followers;
@BindView(R.id.progress) View progress;
@BindView(R.id.followBtn) Button followBtn;
@State User userModel;
@BindView(R.id.orgsList) DynamicRecyclerView orgsList;
@BindView(R.id.orgsCard) CardView orgsCard;
@BindView(R.id.parentView) NestedScrollView parentView;
@BindView(R.id.contributionView) GitHubContributionsView contributionView;
@BindView(R.id.contributionCard) CardView contributionCard;
@BindView(R.id.pinnedReposTextView) FontTextView pinnedReposTextView;
@BindView(R.id.pinnedList) DynamicRecyclerView pinnedList;
@BindView(R.id.pinnedReposCard) CardView pinnedReposCard;
@State User userModel;
private ProfilePagerMvp.View profileCallback;
public static ProfileOverviewFragment newInstance(@NonNull String login) {
@ -127,6 +134,7 @@ public class ProfileOverviewFragment extends BaseFragment<ProfileOverviewMvp.Vie
@Override protected void onFragmentCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
onInitOrgs(getPresenter().getOrgs());
onInitPinnedRepos(getPresenter().getNodes());
if (savedInstanceState == null) {
getPresenter().onFragmentCreated(getArguments());
} else {
@ -269,6 +277,26 @@ public class ProfileOverviewFragment extends BaseFragment<ProfileOverviewMvp.Vie
hideProgress();
}
@Override public void onInitPinnedRepos(@NonNull List<GetPinnedReposQuery.Node> nodes) {
if (!nodes.isEmpty()) {
pinnedReposTextView.setVisibility(VISIBLE);
pinnedReposCard.setVisibility(VISIBLE);
ProfilePinnedReposAdapter adapter = new ProfilePinnedReposAdapter(nodes);
adapter.setListener(new BaseViewHolder.OnItemClickListener<GetPinnedReposQuery.Node>() {
@Override public void onItemClick(int position, View v, GetPinnedReposQuery.Node item) {
SchemeParser.launchUri(getContext(), item.url().toString());
}
@Override public void onItemLongClick(int position, View v, GetPinnedReposQuery.Node item) {}
});
pinnedList.addDivider();
pinnedList.setAdapter(adapter);
} else {
pinnedReposTextView.setVisibility(GONE);
pinnedReposCard.setVisibility(GONE);
}
}
@Override public void showProgress(@StringRes int resId) {
progress.setVisibility(VISIBLE);
}
@ -331,5 +359,4 @@ public class ProfileOverviewFragment extends BaseFragment<ProfileOverviewMvp.Vie
return Login.getUser() != null && Login.getUser().getLogin().equalsIgnoreCase(getPresenter().getLogin()) ||
(userModel != null && userModel.getType() != null && !userModel.getType().equalsIgnoreCase("user"));
}
}

View File

@ -13,6 +13,8 @@ import com.fastaccess.ui.widgets.contributions.GitHubContributionsView;
import java.util.ArrayList;
import java.util.List;
import pr.GetPinnedReposQuery;
/**
* Created by Kosh on 03 Dec 2016, 9:15 AM
*/
@ -33,6 +35,8 @@ public interface ProfileOverviewMvp {
void onUserNotFound();
void onImagePosted(@Nullable String link);
void onInitPinnedRepos(@NonNull List<GetPinnedReposQuery.Node> nodes);
}
interface Presenter extends BaseMvp.FAPresenter {
@ -57,6 +61,8 @@ public interface ProfileOverviewMvp {
@NonNull ArrayList<ContributionsDay> getContributions();
@NonNull ArrayList<GetPinnedReposQuery.Node> getNodes();
@NonNull String getLogin();
}
}

View File

@ -6,6 +6,9 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.apollographql.apollo.ApolloCall;
import com.apollographql.apollo.rx2.Rx2Apollo;
import com.fastaccess.App;
import com.fastaccess.data.dao.model.Login;
import com.fastaccess.data.dao.model.User;
import com.fastaccess.helper.BundleConstant;
@ -21,6 +24,7 @@ import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import pr.GetPinnedReposQuery;
/**
* Created by Kosh on 03 Dec 2016, 9:16 AM
@ -30,7 +34,8 @@ class ProfileOverviewPresenter extends BasePresenter<ProfileOverviewMvp.View> im
@com.evernote.android.state.State boolean isSuccessResponse;
@com.evernote.android.state.State boolean isFollowing;
@com.evernote.android.state.State String login;
@com.evernote.android.state.State ArrayList<User> userOrgs = new ArrayList<>();
private ArrayList<User> userOrgs = new ArrayList<>();
private ArrayList<GetPinnedReposQuery.Node> nodes = new ArrayList<>();
private ArrayList<ContributionsDay> contributions = new ArrayList<>();
private static final String URL = "https://github.com/users/%s/contributions";
@ -83,9 +88,12 @@ class ProfileOverviewPresenter extends BasePresenter<ProfileOverviewMvp.View> im
}
login = bundle.getString(BundleConstant.EXTRA);
if (login != null) {
loadOrgs();
// loadUrlBackgroundImage();
makeRestCall(RestProvider.getUserService(isEnterprise()).getUser(login), userModel -> {
makeRestCall(RestProvider.getUserService(isEnterprise())
.getUser(login)
.doOnComplete(() -> {
loadPinnedRepos(login);
loadOrgs();
}), userModel -> {
onSendUserToView(userModel);
if (userModel != null) {
userModel.save(userModel);
@ -97,6 +105,29 @@ class ProfileOverviewPresenter extends BasePresenter<ProfileOverviewMvp.View> im
}
}
@SuppressWarnings("ConstantConditions") private void loadPinnedRepos(@NonNull String login) {
ApolloCall<GetPinnedReposQuery.Data> apolloCall = App.getInstance().getApolloClient()
.query(GetPinnedReposQuery.builder()
.login(login)
.build());
manageObservable(Rx2Apollo.from(apolloCall)
.filter(dataResponse -> !dataResponse.hasErrors())
.flatMap(dataResponse -> {
if (dataResponse.data() != null && dataResponse.data().user() != null) {
return Observable.fromIterable(dataResponse.data().user().pinnedRepositories().edges());
}
return Observable.empty();
})
.map(GetPinnedReposQuery.Edge::node)
.toList()
.toObservable()
.doOnNext(nodes1 -> {
nodes.clear();
nodes.addAll(nodes1);
sendToView(view -> view.onInitPinnedRepos(nodes));
}));
}
@Override public void onWorkOffline(@NonNull String login) {
User userModel = User.getUser(login);
if (userModel == null) {
@ -134,6 +165,10 @@ class ProfileOverviewPresenter extends BasePresenter<ProfileOverviewMvp.View> im
return contributions;
}
@NonNull @Override public ArrayList<GetPinnedReposQuery.Node> getNodes() {
return nodes;
}
@NonNull @Override public String getLogin() {
return login;
}

View File

@ -314,10 +314,6 @@ public class PullRequestTimelinePresenter extends BasePresenter<PullRequestTimel
private void loadEverything(@NonNull String login, @NonNull String repoId, int number,
@NonNull String sha, boolean isMergeable, int page) {
PullRequestTimelineQuery query = getTimelineBuilder(login, repoId, number, page);
if (query == null) {
sendToView(PullRequestTimelineMvp.View::hideProgress);
return;
}
ApolloCall<PullRequestTimelineQuery.Data> apolloCall = App.getInstance().getApolloClient().query(query);
Observable<PullRequestTimelineModel> observable = Rx2Apollo.from(apolloCall)
.flatMap(response -> {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/material_green_700"
android:pathData="M6,3A3,3 0 0,1 9,6C9,7.31 8.17,8.42 7,8.83V15.17C8.17,15.58 9,16.69 9,18A3,3 0 0,1 6,21A3,3 0 0,1 3,18C3,16.69 3.83,15.58 5,15.17V8.83C3.83,8.42 3,7.31 3,6A3,3 0 0,1 6,3M6,5A1,1 0 0,0 5,6A1,1 0 0,0 6,7A1,1 0 0,0 7,6A1,1 0 0,0 6,5M6,17A1,1 0 0,0 5,18A1,1 0 0,0 6,19A1,1 0 0,0 7,18A1,1 0 0,0 6,17M21,18A3,3 0 0,1 18,21A3,3 0 0,1 15,18C15,16.69 15.83,15.58 17,15.17V7H15V10.25L10.75,6L15,1.75V5H17A2,2 0 0,1 19,7V15.17C20.17,15.58 21,16.69 21,18M18,17A1,1 0 0,0 17,18A1,1 0 0,0 18,19A1,1 0 0,0 19,18A1,1 0 0,0 18,17Z"/>
</vector>

View File

@ -277,12 +277,50 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:nestedScrollingEnabled="false"
app:layoutManager="@string/grid_layout_manager"
app:spanCount="3"
tools:listitem="@layout/profile_org_row_item"/>
</android.support.v7.widget.CardView>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/pinnedReposTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_normal"
android:layout_marginTop="@dimen/spacing_normal"
android:paddingLeft="@dimen/spacing_xs_large"
android:paddingRight="@dimen/spacing_xs_large"
android:text="@string/pinned"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:visibility="gone"
tools:visibility="visible"/>
<android.support.v7.widget.CardView
android:id="@+id/pinnedReposCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:cardBackgroundColor="?card_background"
app:cardCornerRadius="0dp"
app:contentPaddingBottom="@dimen/spacing_normal"
app:contentPaddingLeft="@dimen/spacing_xs_large"
app:contentPaddingRight="@dimen/spacing_xs_large"
app:contentPaddingTop="@dimen/spacing_normal"
tools:visibility="visible">
<com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView
android:id="@+id/pinnedList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
android:orientation="vertical"
app:layoutManager="@string/grid_layout_manager"
app:spanCount="@integer/small_spans"/>
</android.support.v7.widget.CardView>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/contributionsCaption"
android:layout_width="wrap_content"

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:orientation="vertical"
android:paddingBottom="@dimen/spacing_normal"
android:paddingEnd="@dimen/spacing_normal"
android:paddingStart="@dimen/spacing_normal">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/title"
style="@style/Base.TextAppearance.AppCompat.Subhead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/spacing_normal"
android:paddingTop="@dimen/spacing_normal"
tools:text="Repo Name"/>
<com.fastaccess.ui.widgets.AutoLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:auto_gravity="start"
app:auto_orientation="horizontal">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/stars"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/spacing_micro"
android:drawablePadding="@dimen/spacing_micro"
android:drawableStart="@drawable/ic_star_small"
android:gravity="start|center"
android:textColor="?android:attr/textColorSecondary"
app:drawableColor="?android:attr/textColorSecondary"
tools:text="1000"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/forks"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/spacing_micro"
android:drawablePadding="@dimen/spacing_micro"
android:drawableStart="@drawable/ic_fork_small"
android:gravity="start|center"
android:textColor="?android:attr/textColorSecondary"
app:drawableColor="?android:attr/textColorSecondary"
tools:text="5000"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/issues"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/spacing_micro"
android:drawablePadding="@dimen/spacing_micro"
android:drawableStart="@drawable/ic_issue_opened_small"
android:gravity="start|center"
android:textColor="?android:attr/textColorSecondary"
tools:text="100 MB"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/pullRequests"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/spacing_micro"
android:drawablePadding="@dimen/spacing_micro"
android:drawableStart="@drawable/ic_pull_requests_small"
android:gravity="start|center"
android:textColor="?android:attr/textColorSecondary"
tools:text="100 MB"/>
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/language"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableStart="@drawable/ic_language_small"
android:gravity="start|center"
android:textColor="?android:attr/textColorSecondary"
app:drawableColor="?android:attr/textColorSecondary"
tools:text="TypeScript"/>
</com.fastaccess.ui.widgets.AutoLinearLayout>
</LinearLayout>