Skip to content
Snippets Groups Projects
Commit 38c2d95b authored by Michi302's avatar Michi302
Browse files

Merge branch 'master' into fdroid

# Conflicts:
#	.gitlab-ci.yml
#	.magnum.yml
#	app/build.gradle
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/commit451/gitlab/GitLabApp.java
parents 0216e5f3 d79d79f5
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 1508 additions and 451 deletions
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
Loading
Loading
@@ -11,22 +11,20 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
 
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.ProjectsAdapter;
import com.commit451.gitlab.adapter.GroupPagerAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.Group;
import com.commit451.gitlab.model.Project;
import com.commit451.gitlab.tools.NavigationManager;
import com.pnikosis.materialishprogress.ProgressWheel;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.model.api.GroupDetail;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
 
Loading
Loading
@@ -34,10 +32,10 @@ import org.parceler.Parcels;
 
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import timber.log.Timber;
 
/**
* See the things about the group
Loading
Loading
@@ -46,6 +44,7 @@ import retrofit.Retrofit;
public class GroupActivity extends BaseActivity {
 
private static final String KEY_GROUP = "key_group";
private static final String KEY_GROUP_ID = "key_group_id";
 
public static Intent newInstance(Context context, Group group) {
Intent intent = new Intent(context, GroupActivity.class);
Loading
Loading
@@ -53,17 +52,18 @@ public class GroupActivity extends BaseActivity {
return intent;
}
 
public static Intent newInstance(Context context, long groupId) {
Intent intent = new Intent(context, GroupActivity.class);
intent.putExtra(KEY_GROUP_ID, groupId);
return intent;
}
@Bind(R.id.root) View mRoot;
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.collapsing_toolbar) CollapsingToolbarLayout mCollapsingToolbarLayout;
@Bind(R.id.viewpager) ViewPager mViewPager;
@Bind(R.id.tabs) TabLayout mTabLayout;
@Bind(R.id.backdrop) ImageView mBackdrop;
@Bind(R.id.list) RecyclerView mProjectsRecyclerView;
ProjectsAdapter mProjectsAdapter;
@Bind(R.id.progress) ProgressWheel mProgress;
@Bind(R.id.message) TextView mMessageView;
@OnClick(R.id.fab_add_user)
public void onClickAddUser() {
startActivity(AddUserActivity.newInstance(this, mGroup.getId()));
}
 
private final Target mImageLoadTarget = new Target() {
@Override
Loading
Loading
@@ -83,47 +83,29 @@ public class GroupActivity extends BaseActivity {
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
 
private final Callback<Group> mGroupCallback = new Callback<Group>() {
private final Callback<GroupDetail> mGroupCallback = new Callback<GroupDetail>() {
@Override
public void onResponse(Response<Group> response, Retrofit retrofit) {
mProgress.setVisibility(View.GONE);
public void onResponse(Response<GroupDetail> response, Retrofit retrofit) {
if (!response.isSuccess()) {
showMessage(R.string.connection_error);
showError();
return;
}
mGroup = response.body();
if (mGroup.getProjects().isEmpty()) {
showMessage(R.string.no_projects);
} else {
mMessageView.setVisibility(View.GONE);
mProjectsRecyclerView.setVisibility(View.VISIBLE);
mProjectsAdapter.setData(mGroup.getProjects());
}
bind(response.body());
}
 
@Override
public void onFailure(Throwable t) {
mProgress.setVisibility(View.GONE);
showMessage(R.string.connection_error);
Timber.e(t, null);
showError();
}
};
 
private final ProjectsAdapter.Listener mProjectsAdapterListener = new ProjectsAdapter.Listener() {
@Override
public void onProjectClicked(Project project) {
NavigationManager.navigateToProject(GroupActivity.this, project);
}
};
Group mGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_group);
ButterKnife.bind(this);
mGroup = Parcels.unwrap(getIntent().getParcelableExtra(KEY_GROUP));
mToolbar.setTitle(mGroup.getName());
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
Loading
Loading
@@ -131,13 +113,14 @@ public class GroupActivity extends BaseActivity {
onBackPressed();
}
});
Picasso.with(this)
.load(mGroup.getAvatarUrl())
.into(mImageLoadTarget);
mProjectsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mProjectsAdapter = new ProjectsAdapter(this, mProjectsAdapterListener);
mProjectsRecyclerView.setAdapter(mProjectsAdapter);
load();
if (getIntent().hasExtra(KEY_GROUP)) {
Group group = Parcels.unwrap(getIntent().getParcelableExtra(KEY_GROUP));
bind(group);
} else {
long groupId = getIntent().getLongExtra(KEY_GROUP_ID, -1);
GitLabClient.instance().getGroup(groupId).enqueue(mGroupCallback);
}
}
 
@Override
Loading
Loading
@@ -145,6 +128,15 @@ public class GroupActivity extends BaseActivity {
supportFinishAfterTransition();
}
 
private void bind(Group group) {
GitLabClient.getPicasso()
.load(group.getAvatarUrl())
.into(mImageLoadTarget);
mViewPager.setAdapter(new GroupPagerAdapter(this, getSupportFragmentManager(), group));
mTabLayout.setupWithViewPager(mViewPager);
}
private void bindPalette(Palette palette) {
int animationTime = 1000;
int vibrantColor = palette.getVibrantColor(Easel.getThemeAttrColor(this, R.attr.colorPrimary));
Loading
Loading
@@ -170,21 +162,10 @@ public class GroupActivity extends BaseActivity {
Color.WHITE, palette.getDarkMutedColor(Color.BLACK))
.setDuration(animationTime)
.start();
ObjectAnimator.ofObject(mProgress, "barColor", new ArgbEvaluator(),
mProgress.getBarColor(), vibrantColor)
.setDuration(animationTime)
.start();
}
private void load() {
mProgress.setVisibility(View.VISIBLE);
GitLabClient.instance().getGroupDetails(mGroup.getId()).enqueue(mGroupCallback);
}
 
private void showMessage(int stringResId) {
mMessageView.setVisibility(View.VISIBLE);
mMessageView.setText(stringResId);
mProjectsRecyclerView.setVisibility(View.GONE);
private void showError() {
Snackbar.make(mRoot, R.string.connection_error, Snackbar.LENGTH_SHORT)
.show();
}
}
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
Loading
Loading
@@ -15,9 +17,10 @@ import android.widget.TextView;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.GroupAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.Group;
import com.commit451.gitlab.tools.NavigationManager;
import com.commit451.gitlab.viewHolders.GroupViewHolder;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.util.NavigationManager;
import com.commit451.gitlab.util.PaginationUtil;
import com.commit451.gitlab.viewHolder.GroupViewHolder;
 
import java.util.List;
 
Loading
Loading
@@ -45,10 +48,28 @@ public class GroupsActivity extends BaseActivity {
@Bind(R.id.list) RecyclerView mGroupRecyclerView;
@Bind(R.id.message_text) TextView mMessageText;
GroupAdapter mGroupAdapter;
LinearLayoutManager mGroupLayoutManager;
private Uri mNextPageUrl;
private boolean mLoading = false;
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = mGroupLayoutManager.getChildCount();
int totalItemCount = mGroupLayoutManager.getItemCount();
int firstVisibleItem = mGroupLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItem + visibleItemCount >= totalItemCount && !mLoading && mNextPageUrl != null) {
loadMore();
}
}
};
 
private final Callback<List<Group>> mGroupsCallback = new Callback<List<Group>>() {
@Override
public void onResponse(Response<List<Group>> response, Retrofit retrofit) {
mLoading = false;
mSwipeRefreshLayout.setRefreshing(false);
if (!response.isSuccess()) {
return;
Loading
Loading
@@ -66,16 +87,35 @@ public class GroupsActivity extends BaseActivity {
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
Timber.e(t, null);
mLoading = false;
mMessageText.setVisibility(View.VISIBLE);
mMessageText.setText(R.string.connection_error);
}
};
 
private final Callback<List<Group>> mMoreGroupsCallback = new Callback<List<Group>>() {
@Override
public void onResponse(Response<List<Group>> response, Retrofit retrofit) {
mLoading = false;
if (!response.isSuccess()) {
return;
}
mGroupAdapter.addGroups(response.body());
mNextPageUrl = PaginationUtil.parse(response).getNext();
}
@Override
public void onFailure(Throwable t) {
Timber.e(t, null);
mLoading = false;
}
};
private final GroupAdapter.Listener mGroupAdapterListener = new GroupAdapter.Listener() {
@Override
public void onGroupClicked(Group group, GroupViewHolder groupViewHolder) {
NavigationManager.navigateToGroup(GroupsActivity.this, groupViewHolder.image, group);
NavigationManager.navigateToGroup(GroupsActivity.this, groupViewHolder.mImageView, group);
}
};
 
Loading
Loading
@@ -104,9 +144,11 @@ public class GroupsActivity extends BaseActivity {
load();
}
});
mGroupRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
mGroupLayoutManager = new GridLayoutManager(this, 2);
mGroupRecyclerView.setLayoutManager(mGroupLayoutManager);
mGroupAdapter = new GroupAdapter(mGroupAdapterListener);
mGroupRecyclerView.setAdapter(mGroupAdapter);
mGroupRecyclerView.addOnScrollListener(mOnScrollListener);
load();
}
 
Loading
Loading
@@ -119,6 +161,30 @@ public class GroupsActivity extends BaseActivity {
}
}
});
mNextPageUrl = null;
mLoading = true;
GitLabClient.instance().getGroups().enqueue(mGroupsCallback);
}
private void loadMore() {
if (mNextPageUrl == null) {
return;
}
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(true);
}
}
});
mLoading = true;
Timber.d("loadMore called for " + mNextPageUrl);
GitLabClient.instance().getGroups(mNextPageUrl.toString()).enqueue(mMoreGroupsCallback);
}
}
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
Loading
Loading
@@ -18,18 +19,19 @@ import com.commit451.gitlab.GitLabApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.IssueDetailsAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.events.IssueChangedEvent;
import com.commit451.gitlab.model.Issue;
import com.commit451.gitlab.model.Note;
import com.commit451.gitlab.model.Project;
import com.commit451.gitlab.tools.IntentUtil;
import com.commit451.gitlab.tools.KeyboardUtil;
import com.commit451.gitlab.tools.NavigationManager;
import com.commit451.gitlab.event.IssueChangedEvent;
import com.commit451.gitlab.event.IssueReloadEvent;
import com.commit451.gitlab.model.api.Issue;
import com.commit451.gitlab.model.api.Note;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.util.IntentUtil;
import com.commit451.gitlab.util.KeyboardUtil;
import com.commit451.gitlab.util.NavigationManager;
import com.commit451.gitlab.util.PaginationUtil;
import com.squareup.otto.Subscribe;
 
import org.parceler.Parcels;
 
import java.util.Collections;
import java.util.List;
 
import butterknife.Bind;
Loading
Loading
@@ -45,22 +47,22 @@ import timber.log.Timber;
*/
public class IssueActivity extends BaseActivity {
 
private static final String EXTRA_PROJECT = "extra_project";
private static final String EXTRA_SELECTED_ISSUE = "extra_selected_issue";
private static final String EXTRA_PROJECT = "extra_project";
private static final String EXTRA_SELECTED_ISSUE = "extra_selected_issue";
 
public static Intent newInstance(Context context, Project project, Issue issue) {
Intent intent = new Intent(context, IssueActivity.class);
intent.putExtra(EXTRA_PROJECT, Parcels.wrap(project));
intent.putExtra(EXTRA_SELECTED_ISSUE, Parcels.wrap(issue));
return intent;
}
public static Intent newInstance(Context context, Project project, Issue issue) {
Intent intent = new Intent(context, IssueActivity.class);
intent.putExtra(EXTRA_PROJECT, Parcels.wrap(project));
intent.putExtra(EXTRA_SELECTED_ISSUE, Parcels.wrap(issue));
return intent;
}
 
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.issue_title) TextView mIssueTitle;
@Bind(R.id.swipe_layout) SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list) RecyclerView mListView;
@Bind(R.id.new_note_edit) EditText mNewNoteEdit;
@Bind(R.id.progress) View mProgress;
@Bind(R.id.swipe_layout) SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list) RecyclerView mNotesRecyclerView;
@Bind(R.id.new_note_edit) EditText mNewNoteEdit;
@Bind(R.id.progress) View mProgress;
 
@OnClick(R.id.new_note_button)
public void onNewNoteClick() {
Loading
Loading
@@ -68,17 +70,33 @@ public class IssueActivity extends BaseActivity {
}
 
@OnClick(R.id.fab_edit_issue)
public void onEditIssueClick() {
NavigationManager.navigateToEditIssue(IssueActivity.this, mProject, mIssue);
public void onEditIssueClick(View fab) {
NavigationManager.navigateToEditIssue(IssueActivity.this, fab, mProject, mIssue);
}
 
MenuItem mOpenCloseMenuItem;
private MenuItem mOpenCloseMenuItem;
private IssueDetailsAdapter mIssueDetailsAdapter;
private LinearLayoutManager mNotesLayoutManager;
private Project mProject;
private Issue mIssue;
private boolean mLoading;
private Uri mNextPageUrl;
 
IssueDetailsAdapter mIssueDetailsAdapter;
Project mProject;
Issue mIssue;
private EventReceiver mEventReceiver;
 
EventReceiver mEventReceiver;
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = mNotesLayoutManager.getChildCount();
int totalItemCount = mNotesLayoutManager.getItemCount();
int firstVisibleItem = mNotesLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItem + visibleItemCount >= totalItemCount && !mLoading && mNextPageUrl != null) {
loadMoreNotes();
}
}
};
 
private final Toolbar.OnMenuItemClickListener mOnMenuItemClickListener = new Toolbar.OnMenuItemClickListener() {
@Override
Loading
Loading
@@ -88,7 +106,7 @@ public class IssueActivity extends BaseActivity {
IntentUtil.share(getWindow().getDecorView(), mIssue.getUrl(mProject));
return true;
case R.id.action_close:
closeIssue();
closeOrOpenIssue();
return true;
}
return false;
Loading
Loading
@@ -99,24 +117,46 @@ public class IssueActivity extends BaseActivity {
 
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
mLoading = false;
if (!response.isSuccess()) {
return;
}
mSwipeRefreshLayout.setRefreshing(false);
//Annoying that this is not API controlled...
Collections.reverse(response.body());
mIssueDetailsAdapter.addNotes(response.body());
mNextPageUrl = PaginationUtil.parse(response).getNext();
mIssueDetailsAdapter.setNotes(response.body());
}
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
mLoading = false;
Timber.e(t, null);
mSwipeRefreshLayout.setRefreshing(false);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
 
private Callback<List<Note>> mMoreNotesCallback = new Callback<List<Note>>() {
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
mLoading = false;
if (!response.isSuccess()) {
return;
}
mIssueDetailsAdapter.setLoading(false);
mNextPageUrl = PaginationUtil.parse(response).getNext();
mIssueDetailsAdapter.addNotes(response.body());
}
@Override
public void onFailure(Throwable t) {
mLoading = false;
Timber.e(t, null);
mIssueDetailsAdapter.setLoading(false);
}
};
private final Callback<Issue> mOpenCloseCallback = new Callback<Issue>() {
@Override
public void onResponse(Response<Issue> response, Retrofit retrofit) {
Loading
Loading
@@ -128,13 +168,14 @@ public class IssueActivity extends BaseActivity {
}
mIssue = response.body();
GitLabApp.bus().post(new IssueChangedEvent(mIssue));
GitLabApp.bus().post(new IssueReloadEvent());
setOpenCloseMenuStatus();
loadNotes();
}
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.error_changing_issue), Snackbar.LENGTH_SHORT)
.show();
Loading
Loading
@@ -150,28 +191,28 @@ public class IssueActivity extends BaseActivity {
}
mProgress.setVisibility(View.GONE);
mIssueDetailsAdapter.addNote(response.body());
mListView.smoothScrollToPosition(mIssueDetailsAdapter.getItemCount());
mNotesRecyclerView.smoothScrollToPosition(IssueDetailsAdapter.getHeaderCount());
}
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_issue);
ButterKnife.bind(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_issue);
ButterKnife.bind(this);
mEventReceiver = new EventReceiver();
GitLabApp.bus().register(mEventReceiver);
 
mProject = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_PROJECT));
mIssue = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_SELECTED_ISSUE));
mProject = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_PROJECT));
mIssue = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_SELECTED_ISSUE));
 
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
Loading
Loading
@@ -180,16 +221,18 @@ public class IssueActivity extends BaseActivity {
onBackPressed();
}
});
mToolbar.setSubtitle(mProject.getNameWithNamespace());
mToolbar.inflateMenu(R.menu.issue);
mToolbar.setSubtitle(mProject.getNameWithNamespace());
mToolbar.inflateMenu(R.menu.issue);
mOpenCloseMenuItem = mToolbar.getMenu().findItem(R.id.action_close);
mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
 
mIssueDetailsAdapter = new IssueDetailsAdapter(mIssue);
mListView.setLayoutManager(new LinearLayoutManager(this));
mListView.setAdapter(mIssueDetailsAdapter);
mNotesLayoutManager = new LinearLayoutManager(this);
mNotesRecyclerView.setLayoutManager(mNotesLayoutManager);
mNotesRecyclerView.setAdapter(mIssueDetailsAdapter);
mNotesRecyclerView.addOnScrollListener(mOnScrollListener);
 
mNewNoteEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() {
mNewNoteEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
postNote();
Loading
Loading
@@ -229,48 +272,54 @@ public class IssueActivity extends BaseActivity {
}
}
});
mSwipeRefreshLayout.setRefreshing(true);
mLoading = true;
GitLabClient.instance().getIssueNotes(mProject.getId(), mIssue.getId()).enqueue(mNotesCallback);
}
}
 
private void postNote() {
String body = mNewNoteEdit.getText().toString();
private void loadMoreNotes() {
mLoading = true;
mIssueDetailsAdapter.setLoading(true);
GitLabClient.instance().getIssueNotes(mNextPageUrl.toString()).enqueue(mMoreNotesCallback);
}
 
if(body.length() < 1) {
return;
}
private void postNote() {
String body = mNewNoteEdit.getText().toString();
 
mProgress.setVisibility(View.VISIBLE);
mProgress.setAlpha(0.0f);
mProgress.animate().alpha(1.0f);
// Clear text & collapse keyboard
if(body.length() < 1) {
return;
}
mProgress.setVisibility(View.VISIBLE);
mProgress.setAlpha(0.0f);
mProgress.animate().alpha(1.0f);
// Clear text & collapse keyboard
KeyboardUtil.hideKeyboard(this);
mNewNoteEdit.setText("");
mNewNoteEdit.setText("");
 
GitLabClient.instance().postIssueNote(mProject.getId(), mIssue.getId(), body).enqueue(mPostNoteCallback);
}
GitLabClient.instance().addIssueNote(mProject.getId(), mIssue.getId(), body).enqueue(mPostNoteCallback);
}
 
private void closeIssue() {
private void closeOrOpenIssue() {
mProgress.setVisibility(View.VISIBLE);
if (mIssue.getState().equals(Issue.STATE_CLOSED)) {
GitLabClient.instance().setIssueStatus(mProject.getId(), mIssue.getId(), Issue.STATE_REOPEN)
if (mIssue.getState() == Issue.State.CLOSED) {
GitLabClient.instance().updateIssueStatus(mProject.getId(), mIssue.getId(), Issue.STATE_REOPEN)
.enqueue(mOpenCloseCallback);
} else {
GitLabClient.instance().setIssueStatus(mProject.getId(), mIssue.getId(), Issue.STATE_CLOSE)
GitLabClient.instance().updateIssueStatus(mProject.getId(), mIssue.getId(), Issue.STATE_CLOSE)
.enqueue(mOpenCloseCallback);
}
}
 
private void setOpenCloseMenuStatus() {
mOpenCloseMenuItem.setTitle(mIssue.getState().equals(Issue.STATE_CLOSED) ? R.string.reopen : R.string.close);
mOpenCloseMenuItem.setTitle(mIssue.getState() == Issue.State.CLOSED ? R.string.reopen : R.string.close);
}
 
private class EventReceiver {
 
@Subscribe
public void onIssueChanged(IssueChangedEvent event) {
if (mIssue.getId() == event.issue.getId()) {
mIssue = event.issue;
if (mIssue.getId() == event.mIssue.getId()) {
mIssue = event.mIssue;
bindIssue();
}
}
Loading
Loading
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.Manifest;
import android.annotation.TargetApi;
Loading
Loading
@@ -8,6 +8,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
Loading
Loading
@@ -19,22 +20,25 @@ import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
 
import com.commit451.gitlab.GitLabApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.Session;
import com.commit451.gitlab.model.User;
import com.commit451.gitlab.ssl.CustomTrustManager;
import com.commit451.gitlab.data.Prefs;
import com.commit451.gitlab.dialog.HttpLoginDialog;
import com.commit451.gitlab.event.LoginEvent;
import com.commit451.gitlab.event.ReloadDataEvent;
import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.model.api.UserFull;
import com.commit451.gitlab.model.api.UserLogin;
import com.commit451.gitlab.ssl.X509CertificateException;
import com.commit451.gitlab.ssl.X509Util;
import com.commit451.gitlab.tools.KeyboardUtil;
import com.commit451.gitlab.tools.NavigationManager;
import com.commit451.gitlab.data.Prefs;
import com.commit451.gitlab.views.EmailAutoCompleteTextView;
import com.commit451.gitlab.util.KeyboardUtil;
import com.commit451.gitlab.util.NavigationManager;
import com.commit451.gitlab.view.EmailAutoCompleteTextView;
import com.squareup.okhttp.Credentials;
 
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.Set;
import java.util.Date;
import java.util.regex.Pattern;
 
import javax.net.ssl.SSLHandshakeException;
Loading
Loading
@@ -49,36 +53,40 @@ import timber.log.Timber;
 
public class LoginActivity extends BaseActivity {
 
private static final int PERMISSION_REQUEST_GET_ACCOUNTS = 1337;
private static final int PERMISSION_REQUEST_GET_ACCOUNTS = 1337;
private static Pattern sUrlPattern = Patterns.WEB_URL;
private static Pattern sTokenPattern = Pattern.compile("^[A-Za-z0-9-_]*$");
 
public static Intent newInstance(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
return intent;
}
public static Intent newInstance(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
return intent;
}
 
@Bind(R.id.root) View mRoot;
@Bind(R.id.url_hint) TextInputLayout mUrlHint;
@Bind(R.id.url_input) TextView mUrlInput;
@Bind(R.id.url_input) TextView mUrlInput;
@Bind(R.id.user_input_hint) TextInputLayout mUserHint;
@Bind(R.id.user_input) EmailAutoCompleteTextView mUserInput;
@Bind(R.id.user_input) EmailAutoCompleteTextView mUserInput;
@Bind(R.id.password_hint) TextInputLayout mPasswordHint;
@Bind(R.id.password_input) TextView mPasswordInput;
@Bind(R.id.password_input) TextView mPasswordInput;
@Bind(R.id.token_hint) TextInputLayout mTokenHint;
@Bind(R.id.token_input) TextView mTokenInput;
@Bind(R.id.normal_login) View mNormalLogin;
@Bind(R.id.token_login) View mTokenLogin;
@Bind(R.id.progress) View mProgress;
private boolean mIsNormalLogin = true;
private Pattern mUrlPattern = Patterns.WEB_URL;
private final TextView.OnEditorActionListener onEditorActionListener = new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
onLoginClick();
return true;
}
};
@Bind(R.id.token_input) TextView mTokenInput;
@Bind(R.id.normal_login) View mNormalLogin;
@Bind(R.id.token_login) View mTokenLogin;
@Bind(R.id.progress) View mProgress;
private boolean mIsNormalLogin = true;
private String mTrustedCertificate;
private String mAuthorizationHeader;
private Account mAccount;
private final TextView.OnEditorActionListener onEditorActionListener = new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
onLoginClick();
return true;
}
};
 
@OnClick(R.id.show_normal_link)
public void showNormalLogin(TextView loginTypeTextView) {
Loading
Loading
@@ -98,96 +106,102 @@ public class LoginActivity extends BaseActivity {
@OnClick(R.id.login_button)
public void onLoginClick() {
KeyboardUtil.hideKeyboard(this);
if (hasEmptyFields(mUrlHint)) {
return;
}
if (!sUrlPattern.matcher(mUrlInput.getText()).matches()) {
mUrlHint.setError(getString(R.string.not_a_valid_url));
return;
} else {
mUrlHint.setError(null);
}
if (mIsNormalLogin) {
if (hasEmptyFields(mUrlHint, mUserHint, mPasswordHint)) {
return;
}
if (!mUrlPattern.matcher(mUrlInput.getText()).matches()) {
mUrlHint.setError(getString(R.string.not_a_valid_url));
} else {
if (hasEmptyFields(mTokenHint)) {
return;
}
if (!sTokenPattern.matcher(mTokenInput.getText()).matches()) {
mTokenHint.setError(getString(R.string.not_a_valid_private_token));
return;
} else {
mUrlHint.setError(null);
mTokenHint.setError(null);
}
}
if (!mIsNormalLogin && hasEmptyFields(mTokenHint)) {
return;
}
GitLabClient.reset();
 
String url = mUrlInput.getText().toString();
 
if(url.startsWith("http://") && url.endsWith(".git")) {
mUrlInput.setText(url.substring(0, nthOccurrence(url, '/', 2)));
}
else if(url.startsWith("git@") && url.endsWith(".git")) {
mUrlInput.setText("http://" + url.substring(4, url.indexOf(':')));
}
else if(!url.startsWith("http://") && !url.startsWith("https://")) {
mUrlInput.setText("http://" + mUrlInput.getText().toString());
}
mAccount = new Account();
mAccount.setServerUrl(Uri.parse(url));
mAccount.setTrustedCertificate(mTrustedCertificate);
mAccount.setAuthorizationHeader(mAuthorizationHeader);
 
if(mIsNormalLogin) {
if (mIsNormalLogin) {
connect(true);
}
else {
} else {
connect(false);
}
}
 
private Callback<Session> mSessionCallback = new Callback<Session>() {
private Callback<UserLogin> mLoginCallback = new Callback<UserLogin>() {
 
@Override
public void onResponse(Response<Session> response, Retrofit retrofit) {
mProgress.setVisibility(View.GONE);
public void onResponse(Response<UserLogin> response, Retrofit retrofit) {
mTrustedCertificate = null;
if (!response.isSuccess()) {
handleConnectionResponse(response.code());
handleConnectionResponse(response);
return;
}
Prefs.setLoggedIn(LoginActivity.this, true);
Prefs.setPrivateToken(LoginActivity.this, response.body().getPrivateToken());
Intent i = new Intent(LoginActivity.this, GitlabActivity.class);
startActivity(i);
finish();
mAccount.setPrivateToken(response.body().getPrivateToken());
loadUser();
}
 
@Override
public void onFailure(Throwable t) {
mTrustedCertificate = null;
Timber.e(t, null);
handleConnectionError(t);
}
};
 
private Callback<User> mTestUserCallback = new Callback<User>() {
private Callback<UserFull> mTestUserCallback = new Callback<UserFull>() {
@Override
public void onResponse(Response<User> response, Retrofit retrofit) {
public void onResponse(Response<UserFull> response, Retrofit retrofit) {
mProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
handleConnectionResponse(response.code());
handleConnectionResponse(response);
return;
}
Prefs.setLoggedIn(LoginActivity.this, true);
mAccount.setUser(response.body());
mAccount.setLastUsed(new Date());
Prefs.addAccount(LoginActivity.this, mAccount);
GitLabClient.setAccount(mAccount);
GitLabApp.bus().post(new LoginEvent(mAccount));
//This is mostly for if projects already exists, then we will reload the data
GitLabApp.bus().post(new ReloadDataEvent());
NavigationManager.navigateToProjects(LoginActivity.this);
finish();
}
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
Snackbar.make(mRoot, getString(R.string.login_error), Snackbar.LENGTH_LONG)
.show();
mTrustedCertificate = null;
Timber.e(t, null);
handleConnectionError(t);
}
};
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
mPasswordInput.setOnEditorActionListener(onEditorActionListener);
mTokenInput.setOnEditorActionListener(onEditorActionListener);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
mPasswordInput.setOnEditorActionListener(onEditorActionListener);
mTokenInput.setOnEditorActionListener(onEditorActionListener);
mUserInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
Loading
Loading
@@ -196,9 +210,7 @@ public class LoginActivity extends BaseActivity {
}
}
});
CustomTrustManager.setTrustedCertificates(Prefs.getTrustedCertificates(this));
}
}
 
@TargetApi(23)
private void checkAccountPermission() {
Loading
Loading
@@ -220,60 +232,46 @@ public class LoginActivity extends BaseActivity {
}
}
 
public static int nthOccurrence(String str, char c, int n) {
int pos = str.indexOf(c, 0);
while (n-- > 0 && pos != -1)
pos = str.indexOf(c, pos + 1);
return pos;
}
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
private void connect(boolean byAuth) {
private void connect(boolean byAuth) {
mProgress.setVisibility(View.VISIBLE);
mProgress.setAlpha(0.0f);
mProgress.animate().alpha(1.0f);
 
Prefs.setPrivateToken(this, "");
Prefs.setLoggedIn(this, false);
Prefs.setServerUrl(this, mUrlInput.getText().toString());
if(byAuth) {
if(byAuth) {
connectByAuth();
}
else {
else {
connectByToken();
}
}
private void connectByAuth() {
if(mUserInput.getText().toString().contains("@")) {
GitLabClient.instance().getSessionByEmail(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mSessionCallback);
}
private void connectByAuth() {
if(mUserInput.getText().toString().contains("@")) {
GitLabClient.instance(mAccount).loginWithEmail(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
}
else {
GitLabClient.instance().getSessionByUsername(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mSessionCallback);
else {
GitLabClient.instance(mAccount).loginWithUsername(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
}
}
private void connectByToken() {
Prefs.setPrivateToken(this, mTokenInput.getText().toString());
GitLabClient.instance().getUser().enqueue(mTestUserCallback);
}
}
 
private void handleConnectionError(Throwable e) {
Timber.e(e.toString());
private void connectByToken() {
mAccount.setPrivateToken(mTokenInput.getText().toString());
loadUser();
}
private void loadUser() {
GitLabClient.instance(mAccount).getThisUser().enqueue(mTestUserCallback);
}
 
private void handleConnectionError(Throwable t) {
mProgress.setVisibility(View.GONE);
 
if(e instanceof SSLHandshakeException && e.getCause() instanceof X509CertificateException) {
if(t instanceof SSLHandshakeException && t.getCause() instanceof X509CertificateException) {
String fingerprint = null;
try {
fingerprint = X509Util.getFingerPrint(((X509CertificateException) e.getCause()).getChain()[0]);
} catch (CertificateEncodingException ex) {
Timber.e(e.toString());
fingerprint = X509Util.getFingerPrint(((X509CertificateException) t.getCause()).getChain()[0]);
} catch (CertificateEncodingException e) {
Timber.e(e, null);
}
final String finalFingerprint = fingerprint;
 
Loading
Loading
@@ -284,17 +282,11 @@ public class LoginActivity extends BaseActivity {
@Override
public void onClick(DialogInterface dialog, int which) {
if (finalFingerprint != null) {
Set<String> trustedCertificates = new HashSet<>(Prefs.getTrustedCertificates(LoginActivity.this));
trustedCertificates.add(finalFingerprint);
Prefs.setTrustedCertificates(LoginActivity.this, trustedCertificates);
CustomTrustManager.setTrustedCertificates(trustedCertificates);
mTrustedCertificate = finalFingerprint;
onLoginClick();
}
 
dialog.dismiss();
if (finalFingerprint != null) {
onLoginClick();
}
}
})
.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
Loading
Loading
@@ -309,12 +301,18 @@ public class LoginActivity extends BaseActivity {
} else {
Snackbar.make(mRoot, getString(R.string.login_error), Snackbar.LENGTH_LONG)
.show();
}
}
}
 
private void handleConnectionResponse(int responseCode) {
switch (responseCode) {
private void handleConnectionResponse(Response response) {
mProgress.setVisibility(View.GONE);
switch (response.code()) {
case 401:
String header = response.headers().get("WWW-Authenticate");
if (header != null) {
handleBasicAuthentication(response);
return;
}
Snackbar.make(mRoot, getString(R.string.login_unauthorized), Snackbar.LENGTH_LONG)
.show();
return;
Loading
Loading
@@ -323,4 +321,34 @@ public class LoginActivity extends BaseActivity {
.show();
}
}
private void handleBasicAuthentication(Response response) {
String header = response.headers().get("WWW-Authenticate").trim();
if (!header.startsWith("Basic")) {
Snackbar.make(mRoot, getString(R.string.login_unsupported_authentication), Snackbar.LENGTH_LONG)
.show();
return;
}
int realmStart = header.indexOf('"') + 1;
int realmEnd = header.lastIndexOf('"');
String realm = "";
if (realmStart > 0 && realmEnd > -1) {
realm = header.substring(realmStart, realmEnd);
}
HttpLoginDialog dialog = new HttpLoginDialog(this, realm, new HttpLoginDialog.LoginListener() {
@Override
public void onLogin(String username, String password) {
mAuthorizationHeader = Credentials.basic(username, password);
onLoginClick();
}
@Override
public void onCancel() {
mAuthorizationHeader = null;
}
});
dialog.show();
}
}
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
Loading
Loading
@@ -16,10 +17,11 @@ import android.widget.TextView;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.MergeRequestDetailAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.MergeRequest;
import com.commit451.gitlab.model.MergeRequestComment;
import com.commit451.gitlab.model.Project;
import com.commit451.gitlab.tools.KeyboardUtil;
import com.commit451.gitlab.model.api.MergeRequest;
import com.commit451.gitlab.model.api.Note;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.util.KeyboardUtil;
import com.commit451.gitlab.util.PaginationUtil;
 
import org.parceler.Parcels;
 
Loading
Loading
@@ -35,7 +37,6 @@ import timber.log.Timber;
 
/**
* Shows the details of a merge request
* Created by John on 11/16/15.
*/
public class MergeRequestActivity extends BaseActivity {
 
Loading
Loading
@@ -52,44 +53,87 @@ public class MergeRequestActivity extends BaseActivity {
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.merge_request_title) TextView mMergeRequestTitle;
@Bind(R.id.swipe_layout) SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list) RecyclerView mListView;
@Bind(R.id.list) RecyclerView mNotesRecyclerView;
@Bind(R.id.new_note_edit) EditText mNewNoteEdit;
@Bind(R.id.progress) View mProgress;
@OnClick(R.id.new_note_button)
public void onNewNoteClick() {
postNote();
}
MergeRequestDetailAdapter mMergeRequestDetailAdapter;
 
Project mProject;
MergeRequest mMergeRequest;
private MergeRequestDetailAdapter mMergeRequestDetailAdapter;
private LinearLayoutManager mNotesLinearLayoutManager;
 
private Callback<List<MergeRequestComment>> mNotesCallback = new Callback<List<MergeRequestComment>>() {
private Project mProject;
private MergeRequest mMergeRequest;
private Uri mNextPageUrl;
private boolean mLoading;
 
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onResponse(Response<List<MergeRequestComment>> response, Retrofit retrofit) {
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = mNotesLinearLayoutManager.getChildCount();
int totalItemCount = mNotesLinearLayoutManager.getItemCount();
int firstVisibleItem = mNotesLinearLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItem + visibleItemCount >= totalItemCount && !mLoading && mNextPageUrl != null) {
loadMoreNotes();
}
}
};
private Callback<List<Note>> mNotesCallback = new Callback<List<Note>>() {
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
if (!response.isSuccess()) {
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
return;
}
mMergeRequestDetailAdapter.addNotes(response.body());
mNextPageUrl = PaginationUtil.parse(response).getNext();
mMergeRequestDetailAdapter.setNotes(response.body());
}
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
mLoading = false;
Timber.e(t, null);
mSwipeRefreshLayout.setRefreshing(false);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
 
private Callback<MergeRequestComment> mPostNoteCallback = new Callback<MergeRequestComment>() {
private Callback<List<Note>> mMoreNotesCallback = new Callback<List<Note>>() {
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
mMergeRequestDetailAdapter.setLoading(false);
mLoading = false;
if (!response.isSuccess()) {
return;
}
mNextPageUrl = PaginationUtil.parse(response).getNext();
mMergeRequestDetailAdapter.addNotes(response.body());
}
@Override
public void onFailure(Throwable t) {
mLoading = false;
Timber.e(t, null);
mMergeRequestDetailAdapter.setLoading(false);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
private Callback<Note> mPostNoteCallback = new Callback<Note>() {
 
@Override
public void onResponse(Response<MergeRequestComment> response, Retrofit retrofit) {
public void onResponse(Response<Note> response, Retrofit retrofit) {
mProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
Loading
Loading
@@ -97,12 +141,12 @@ public class MergeRequestActivity extends BaseActivity {
return;
}
mMergeRequestDetailAdapter.addNote(response.body());
mListView.smoothScrollToPosition(mMergeRequestDetailAdapter.getItemCount());
mNotesRecyclerView.smoothScrollToPosition(mMergeRequestDetailAdapter.getItemCount());
}
 
@Override
public void onFailure(Throwable t) {
Timber.e(t.toString());
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
Loading
Loading
@@ -130,8 +174,10 @@ public class MergeRequestActivity extends BaseActivity {
mMergeRequestTitle.setText(mMergeRequest.getTitle());
 
mMergeRequestDetailAdapter = new MergeRequestDetailAdapter(mMergeRequest);
mListView.setLayoutManager(new LinearLayoutManager(this));
mListView.setAdapter(mMergeRequestDetailAdapter);
mNotesLinearLayoutManager = new LinearLayoutManager(this);
mNotesRecyclerView.setLayoutManager(mNotesLinearLayoutManager);
mNotesRecyclerView.setAdapter(mMergeRequestDetailAdapter);
mNotesRecyclerView.addOnScrollListener(mOnScrollListener);
 
mNewNoteEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
Loading
Loading
@@ -159,10 +205,14 @@ public class MergeRequestActivity extends BaseActivity {
}
}
});
mSwipeRefreshLayout.setRefreshing(true);
GitLabClient.instance().getMergeRequestNotes(mProject.getId(), mMergeRequest.getId()).enqueue(mNotesCallback);
}
 
private void loadMoreNotes() {
mMergeRequestDetailAdapter.setLoading(true);
GitLabClient.instance().getMergeRequestNotes(mNextPageUrl.toString()).enqueue(mMoreNotesCallback);
}
private void postNote() {
String body = mNewNoteEdit.getText().toString();
 
Loading
Loading
@@ -177,6 +227,6 @@ public class MergeRequestActivity extends BaseActivity {
KeyboardUtil.hideKeyboard(this);
mNewNoteEdit.setText("");
 
GitLabClient.instance().postMergeRequestComment(mProject.getId(), mMergeRequest.getId(), body).enqueue(mPostNoteCallback);
GitLabClient.instance().addMergeRequestNote(mProject.getId(), mMergeRequest.getId(), body).enqueue(mPostNoteCallback);
}
}
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;
import com.commit451.gitlab.GitLabApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.MilestoneIssuesAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.event.MilestoneChangedEvent;
import com.commit451.gitlab.model.api.Issue;
import com.commit451.gitlab.model.api.Milestone;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.util.NavigationManager;
import com.commit451.gitlab.util.PaginationUtil;
import com.squareup.otto.Subscribe;
import org.parceler.Parcels;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import timber.log.Timber;
public class MilestoneActivity extends BaseActivity {
private static final String EXTRA_PROJECT = "extra_project";
private static final String EXTRA_MILESTONE = "extra_milestone";
public static Intent newInstance(Context context, Project project, Milestone milestone) {
Intent intent = new Intent(context, MilestoneActivity.class);
intent.putExtra(EXTRA_PROJECT, Parcels.wrap(project));
intent.putExtra(EXTRA_MILESTONE, Parcels.wrap(milestone));
return intent;
}
@Bind(R.id.root)
View mRoot;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.swipe_layout)
SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list)
RecyclerView mIssuesRecyclerView;
MilestoneIssuesAdapter mMilestoneIssuesAdapter;
LinearLayoutManager mIssuesLayoutManager;
@Bind(R.id.message_text)
TextView mMessageText;
private Project mProject;
private Milestone mMilestone;
private Uri mNextPageUrl;
private boolean mLoading = false;
EventReceiver mEventReceiver;
@OnClick(R.id.add)
void onAddClick() {
NavigationManager.navigateToAddIssue(MilestoneActivity.this, null, mProject);
}
@OnClick(R.id.edit)
void onEditClicked(View fab) {
NavigationManager.navigateToEditMilestone(MilestoneActivity.this, fab, mProject, mMilestone);
}
private final Callback<List<Issue>> mIssuesCallback = new Callback<List<Issue>>() {
@Override
public void onResponse(Response<List<Issue>> response, Retrofit retrofit) {
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
if (!response.isSuccess()) {
Timber.e("Issues response was not a success: %d", response.code());
mMessageText.setVisibility(View.VISIBLE);
mMessageText.setText(R.string.connection_error_issues);
mMilestoneIssuesAdapter.setIssues(null);
return;
}
if (!response.body().isEmpty()) {
mMessageText.setVisibility(View.GONE);
} else {
Timber.d("No issues found");
mMessageText.setVisibility(View.VISIBLE);
mMessageText.setText(R.string.no_issues);
}
mNextPageUrl = PaginationUtil.parse(response).getNext();
mMilestoneIssuesAdapter.setIssues(response.body());
}
@Override
public void onFailure(Throwable t) {
Timber.e(t, null);
mLoading = false;
mSwipeRefreshLayout.setRefreshing(false);
mMessageText.setVisibility(View.VISIBLE);
mMessageText.setText(R.string.connection_error);
mMilestoneIssuesAdapter.setIssues(null);
}
};
private final Callback<List<Issue>> mMoreIssuesCallback = new Callback<List<Issue>>() {
@Override
public void onResponse(Response<List<Issue>> response, Retrofit retrofit) {
if (!response.isSuccess()) {
return;
}
mLoading = false;
mNextPageUrl = PaginationUtil.parse(response).getNext();
mMilestoneIssuesAdapter.addIssues(response.body());
}
@Override
public void onFailure(Throwable t) {
Timber.e(t, null);
mLoading = false;
}
};
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = mIssuesLayoutManager.getChildCount();
int totalItemCount = mIssuesLayoutManager.getItemCount();
int firstVisibleItem = mIssuesLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItem + visibleItemCount >= totalItemCount && !mLoading && mNextPageUrl != null) {
loadMore();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_milestone);
ButterKnife.bind(this);
mEventReceiver = new EventReceiver();
GitLabApp.bus().register(mEventReceiver);
mProject = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_PROJECT));
mMilestone = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_MILESTONE));
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
mMilestoneIssuesAdapter = new MilestoneIssuesAdapter(new MilestoneIssuesAdapter.Listener() {
@Override
public void onIssueClicked(Issue issue) {
NavigationManager.navigateToIssue(MilestoneActivity.this, mProject, issue);
}
});
bind(mMilestone);
mIssuesRecyclerView.setAdapter(mMilestoneIssuesAdapter);
mIssuesLayoutManager = new LinearLayoutManager(this);
mIssuesRecyclerView.setLayoutManager(mIssuesLayoutManager);
mIssuesRecyclerView.addOnScrollListener(mOnScrollListener);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
loadData();
}
});
loadData();
}
@Override
protected void onDestroy() {
super.onDestroy();
GitLabApp.bus().unregister(mEventReceiver);
}
private void bind(Milestone milestone) {
mToolbar.setTitle(milestone.getTitle());
mMilestoneIssuesAdapter.setMilestone(milestone);
}
private void loadData() {
mMessageText.setVisibility(View.GONE);
mLoading = true;
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(true);
}
}
});
GitLabClient.instance().getMilestoneIssues(mProject.getId(), mMilestone.getId()).enqueue(mIssuesCallback);
}
private void loadMore() {
if (mNextPageUrl == null) {
return;
}
mLoading = true;
Timber.d("loadMore called for " + mNextPageUrl);
GitLabClient.instance().getMilestoneIssues(mNextPageUrl.toString()).enqueue(mMoreIssuesCallback);
}
private class EventReceiver {
@Subscribe
public void onMilestoneChanged(MilestoneChangedEvent event) {
if (mMilestone.getId() == event.mMilestone.getId()) {
mMilestone = event.mMilestone;
bind(mMilestone);
}
}
}
}
package com.commit451.gitlab.activity;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.transition.ArcMotion;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.transition.MorphDialogToFab;
import com.commit451.gitlab.transition.MorphFabToDialog;
/**
* Activity that morphs from a FAB. Make sure the view you want to morph has the view id R.id.root and
* call {@link #morph(View)} when the content view is set
*/
public class MorphActivity extends BaseActivity {
protected void morph(View root) {
if (root == null) {
throw new IllegalStateException("Cannot pass an empty view");
}
if (Build.VERSION.SDK_INT >= 21) {
int fabColor = Easel.getThemeAttrColor(this, R.attr.colorAccent);
int dialogColor = Easel.getThemeAttrColor(this, android.R.attr.windowBackground);
setupSharedElementTransitionsFab(this, root,
fabColor,
dialogColor,
getResources().getDimensionPixelSize(R.dimen.dialog_corners));
}
}
@TargetApi(21)
public void setupSharedElementTransitionsFab(@NonNull Activity activity,
@Nullable View target,
int fabColor,
int dialogColor,
int dialogCornerRadius) {
ArcMotion arcMotion = new ArcMotion();
arcMotion.setMinimumHorizontalAngle(50f);
arcMotion.setMinimumVerticalAngle(50f);
Interpolator easeInOut = AnimationUtils.loadInterpolator(activity, android.R.interpolator.fast_out_slow_in);
MorphFabToDialog sharedEnter = new MorphFabToDialog(fabColor, dialogColor, dialogCornerRadius);
sharedEnter.setPathMotion(arcMotion);
sharedEnter.setInterpolator(easeInOut);
MorphDialogToFab sharedReturn = new MorphDialogToFab(dialogColor, fabColor);
sharedReturn.setPathMotion(arcMotion);
sharedReturn.setInterpolator(easeInOut);
if (target != null) {
sharedEnter.addTarget(target);
sharedReturn.addTarget(target);
}
activity.getWindow().setSharedElementEnterTransition(sharedEnter);
activity.getWindow().setSharedElementReturnTransition(sharedReturn);
}
@Override
public void onBackPressed() {
dismiss();
}
@TargetApi(21)
public void dismiss() {
if (Build.VERSION.SDK_INT >= 21) {
finishAfterTransition();
} else {
finish();
}
}
}
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import com.commit451.gitlab.GitLabApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.SectionsPagerAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.event.ProjectReloadEvent;
import com.commit451.gitlab.fragment.BaseFragment;
import com.commit451.gitlab.model.api.Branch;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.util.IntentUtil;
import org.parceler.Parcels;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import timber.log.Timber;
public class ProjectActivity extends BaseActivity {
private static final String EXTRA_PROJECT = "extra_project";
public static Intent newInstance(Context context, Project project) {
Intent intent = new Intent(context, ProjectActivity.class);
intent.putExtra(EXTRA_PROJECT, Parcels.wrap(project));
return intent;
}
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.tabs) TabLayout mTabLayout;
@Bind(R.id.branch_spinner) Spinner mBranchSpinner;
@Bind(R.id.progress) View mProgress;
@Bind(R.id.pager) ViewPager mViewPager;
private final AdapterView.OnItemSelectedListener mSpinnerItemSelectedListener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (!(view instanceof TextView)) {
return;
}
mBranchName = ((TextView)view).getText().toString();
broadcastLoad();
}
@Override
public void onNothingSelected(AdapterView<?> parent) { }
};
Project mProject;
String mBranchName;
private Callback<List<Branch>> mBranchesCallback = new Callback<List<Branch>>() {
@Override
public void onResponse(Response<List<Branch>> response, Retrofit retrofit) {
if (!response.isSuccess()) {
return;
}
mProgress.setVisibility(View.GONE);
if(response.body().isEmpty()) {
mBranchSpinner.setVisibility(View.GONE);
} else {
mBranchSpinner.setVisibility(View.VISIBLE);
mBranchSpinner.setAlpha(0.0f);
mBranchSpinner.animate().alpha(1.0f);
// Set up the dropdown list navigation in the action bar.
mBranchSpinner.setAdapter(new ArrayAdapter<>(ProjectActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, response.body()));
}
for (int i=0; i<response.body().size(); i++) {
if (response.body().get(i).getName().equals(mProject.getDefaultBranch())) {
mBranchSpinner.setSelection(i);
}
}
mBranchSpinner.setOnItemSelectedListener(mSpinnerItemSelectedListener);
if(response.body().isEmpty()) {
broadcastLoad();
}
}
@Override
public void onFailure(Throwable t) {
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
private final Toolbar.OnMenuItemClickListener mOnMenuItemClickListener = new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share:
IntentUtil.share(getWindow().getDecorView(), mProject.getWebUrl());
return true;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_project);
ButterKnife.bind(this);
mProject = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_PROJECT));
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mToolbar.inflateMenu(R.menu.menu_repository);
mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
mViewPager.setAdapter(sectionsPagerAdapter);
mTabLayout.setupWithViewPager(mViewPager);
loadBranches();
}
private void loadBranches() {
GitLabClient.instance().getBranches(mProject.getId()).enqueue(mBranchesCallback);
}
private void broadcastLoad() {
GitLabApp.bus().post(new ProjectReloadEvent(mProject, mBranchName));
}
@Override
public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + mViewPager.getCurrentItem());
if (fragment instanceof BaseFragment) {
if (((BaseFragment) fragment).onBackPressed()) {
return;
}
}
super.onBackPressed();
}
public String getBranchName() {
return mBranchName;
}
public Project getProject() {
return mProject;
}
}
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
Loading
Loading
@@ -15,8 +15,8 @@ import android.view.View;
import com.commit451.gitlab.GitLabApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.ProjectsPagerAdapter;
import com.commit451.gitlab.events.CloseDrawerEvent;
import com.commit451.gitlab.tools.NavigationManager;
import com.commit451.gitlab.event.CloseDrawerEvent;
import com.commit451.gitlab.util.NavigationManager;
import com.squareup.otto.Subscribe;
 
import butterknife.Bind;
Loading
Loading
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
Loading
Loading
@@ -16,7 +16,7 @@ import android.widget.TextView;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.SearchPagerAdapter;
import com.commit451.gitlab.tools.KeyboardUtil;
import com.commit451.gitlab.util.KeyboardUtil;
 
import butterknife.Bind;
import butterknife.ButterKnife;
Loading
Loading
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
Loading
Loading
package com.commit451.gitlab.activities;
package com.commit451.gitlab.activity;
 
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
Loading
Loading
@@ -8,28 +8,22 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
 
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.FeedAdapter;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.data.Prefs;
import com.commit451.gitlab.model.User;
import com.commit451.gitlab.model.rss.Entry;
import com.commit451.gitlab.model.rss.UserFeed;
import com.commit451.gitlab.tools.ImageUtil;
import com.commit451.gitlab.tools.IntentUtil;
import com.pnikosis.materialishprogress.ProgressWheel;
import com.commit451.gitlab.fragment.FeedFragment;
import com.commit451.gitlab.model.api.UserBasic;
import com.commit451.gitlab.util.ImageUtil;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
 
Loading
Loading
@@ -37,10 +31,6 @@ import org.parceler.Parcels;
 
import butterknife.Bind;
import butterknife.ButterKnife;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import timber.log.Timber;
 
/**
* User activity, which shows the user!
Loading
Loading
@@ -50,7 +40,7 @@ public class UserActivity extends BaseActivity {
 
private static final String KEY_USER = "user";
 
public static Intent newInstance(Context context, User user) {
public static Intent newInstance(Context context, UserBasic user) {
Intent intent = new Intent(context, UserActivity.class);
intent.putExtra(KEY_USER, Parcels.wrap(user));
return intent;
Loading
Loading
@@ -59,12 +49,8 @@ public class UserActivity extends BaseActivity {
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.collapsing_toolbar) CollapsingToolbarLayout mCollapsingToolbarLayout;
@Bind(R.id.backdrop) ImageView mBackdrop;
@Bind(R.id.list) RecyclerView mActivityRecyclerView;
FeedAdapter mFeedAdapter;
@Bind(R.id.progress) ProgressWheel mProgress;
@Bind(R.id.message) TextView mMessageView;
 
User mUser;
UserBasic mUser;
 
private final Target mImageLoadTarget = new Target() {
@Override
Loading
Loading
@@ -84,38 +70,6 @@ public class UserActivity extends BaseActivity {
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
 
private final Callback<UserFeed> mUserFeedCallback = new Callback<UserFeed>() {
@Override
public void onResponse(Response<UserFeed> response, Retrofit retrofit) {
mProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
Timber.e("Feed response was not a success: %d", response.code());
return;
}
if (response.body().getEntries() == null || response.body().getEntries().isEmpty()) {
mMessageView.setVisibility(View.VISIBLE);
mMessageView.setText(R.string.no_activity);
} else {
mFeedAdapter.setEntries(response.body().getEntries());
}
}
@Override
public void onFailure(Throwable t) {
mProgress.setVisibility(View.GONE);
mMessageView.setVisibility(View.VISIBLE);
mMessageView.setText(R.string.connection_error);
Timber.e(t.toString());
}
};
private final FeedAdapter.Listener mFeedAdapterListener = new FeedAdapter.Listener() {
@Override
public void onFeedEntryClicked(Entry entry) {
IntentUtil.openPage(getWindow().getDecorView(), entry.getLink().getHref());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Loading
Loading
@@ -130,14 +84,15 @@ public class UserActivity extends BaseActivity {
}
});
mToolbar.setTitle(mUser.getUsername());
String url = ImageUtil.getGravatarUrl(mUser, getResources().getDimensionPixelSize(R.dimen.user_header_image_size));
Picasso.with(this)
Uri url = ImageUtil.getAvatarUrl(mUser, getResources().getDimensionPixelSize(R.dimen.user_header_image_size));
GitLabClient.getPicasso()
.load(url)
.into(mImageLoadTarget);
mActivityRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mFeedAdapter = new FeedAdapter(mFeedAdapterListener);
mActivityRecyclerView.setAdapter(mFeedAdapter);
load();
if (savedInstanceState == null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.user_feed, FeedFragment.newInstance(mUser.getFeedUrl().toString())).commit();
}
}
 
@Override
Loading
Loading
@@ -171,16 +126,5 @@ public class UserActivity extends BaseActivity {
Color.WHITE, palette.getDarkMutedColor(Color.BLACK))
.setDuration(animationTime)
.start();
ObjectAnimator.ofObject(mProgress, "barColor", new ArgbEvaluator(),
mProgress.getBarColor(), vibrantColor)
.setDuration(animationTime)
.start();
}
private void load() {
mMessageView.setVisibility(View.GONE);
mProgress.setVisibility(View.VISIBLE);
GitLabClient.rssInstance().getUserFeed(mUser.getFeedUrl(Prefs.getServerUrl(this))).enqueue(mUserFeedCallback);
}
}
package com.commit451.gitlab.adapter;
 
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
 
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.viewHolders.ProjectAccessViewHolder;
import com.commit451.gitlab.viewHolder.AccessViewHolder;
 
/**
* Adapter to show the access levels
* Created by Jawn on 9/16/2015.
*/
public class ProjectAccessAdapter extends RecyclerView.Adapter<ProjectAccessViewHolder> {
public interface Listener {
void onAccessLevelClicked(String accessLevel);
}
private Listener mListener;
public class AccessAdapter extends RecyclerView.Adapter<AccessViewHolder> {
 
private String[] mValues;
private String mSelectedValue;
private int mColorControlHighlight;
 
public ProjectAccessAdapter(Context context, Listener listener) {
mListener = listener;
mValues = context.getResources().getStringArray(R.array.role_names);
public AccessAdapter(Context context, String[] roles) {
mColorControlHighlight = Easel.getThemeAttrColor(context, R.attr.colorControlHighlight);
mValues = roles;
}
public void setSelectedAccess(String access) {
mSelectedValue = access;
}
 
public String getValueAt(int position) {
Loading
Loading
@@ -34,21 +37,22 @@ public class ProjectAccessAdapter extends RecyclerView.Adapter<ProjectAccessView
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
mListener.onAccessLevelClicked(getValueAt(position));
mSelectedValue = getValueAt(position);
notifyDataSetChanged();
}
};
 
@Override
public ProjectAccessViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ProjectAccessViewHolder holder = ProjectAccessViewHolder.create(parent);
public AccessViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
AccessViewHolder holder = AccessViewHolder.inflate(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
}
 
@Override
public void onBindViewHolder(final ProjectAccessViewHolder holder, int position) {
public void onBindViewHolder(final AccessViewHolder holder, int position) {
String accessLevel = getValueAt(position);
holder.bind(accessLevel);
holder.bind(accessLevel, mColorControlHighlight, accessLevel.equalsIgnoreCase(mSelectedValue));
holder.itemView.setTag(R.id.list_position, position);
}
 
Loading
Loading
@@ -56,4 +60,9 @@ public class ProjectAccessAdapter extends RecyclerView.Adapter<ProjectAccessView
public int getItemCount() {
return mValues.length;
}
@Nullable
public String getSelectedValue() {
return mSelectedValue;
}
}
package com.commit451.gitlab.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.viewHolder.AccountFooterViewHolder;
import com.commit451.gitlab.viewHolder.AccountViewHolder;
import java.util.ArrayList;
import java.util.Collection;
/**
* Adapter to show all the accounts
* Created by Jawn on 12/6/2015.
*/
public class AccountsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_ACCOUNT = 0;
private static final int TYPE_FOOTER = 1;
private static final int FOOTER_COUNT = 1;
public interface Listener {
void onAccountClicked(Account account);
void onAddAccountClicked();
void onAccountLogoutClicked(Account account);
}
private Listener mListener;
private ArrayList<Account> mAccounts;
private int mColorControlHighlight;
private View.OnClickListener mOnItemClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
mListener.onAccountClicked(getItemAtPosition(position));
}
};
private View.OnClickListener mOnFooterClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onAddAccountClicked();
}
};
public AccountsAdapter(Context context, Listener listener) {
mListener = listener;
mAccounts = new ArrayList<>();
mColorControlHighlight = Easel.getThemeAttrColor(context, R.attr.colorControlHighlight);
}
public void setAccounts(Collection<Account> accounts) {
mAccounts.clear();
if (accounts != null) {
mAccounts.addAll(accounts);
}
notifyDataSetChanged();
}
public void addAccount(Account account) {
if (!mAccounts.contains(account)) {
mAccounts.add(0, account);
notifyItemInserted(0);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_ACCOUNT:
AccountViewHolder holder = AccountViewHolder.inflate(parent);
holder.itemView.setOnClickListener(mOnItemClickListener);
return holder;
case TYPE_FOOTER:
AccountFooterViewHolder footerViewHolder = AccountFooterViewHolder.inflate(parent);
footerViewHolder.itemView.setOnClickListener(mOnFooterClickListener);
return footerViewHolder;
}
throw new IllegalStateException("No known view holder for that type " + viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof AccountViewHolder) {
final Account account = getItemAtPosition(position);
((AccountViewHolder) holder).bind(account, account.equals(GitLabClient.getAccount()), mColorControlHighlight);
holder.itemView.setTag(R.id.list_position, position);
((AccountViewHolder) holder).mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_sign_out:
int itemPosition = mAccounts.indexOf(account);
mAccounts.remove(account);
notifyItemRemoved(itemPosition);
mListener.onAccountLogoutClicked(account);
return true;
}
return false;
}
});
} else if (holder instanceof AccountFooterViewHolder) {
//Nah
} else {
throw new IllegalStateException("No known bind for this viewHolder");
}
}
@Override
public int getItemCount() {
return mAccounts.size() + FOOTER_COUNT;
}
@Override
public int getItemViewType(int position) {
return position == mAccounts.size() ? TYPE_FOOTER : TYPE_ACCOUNT;
}
private Account getItemAtPosition(int position) {
return mAccounts.get(position);
}
public int getAccountsCount() {
return mAccounts.size();
}
}
package com.commit451.gitlab.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.Member;
import com.commit451.gitlab.model.api.UserBasic;
import com.commit451.gitlab.viewHolder.AssigneeViewHolder;
import java.util.ArrayList;
import java.util.Collection;
/**
* Shows the possible assignees
* Created by Jawn on 12/18/2015.
*/
public class AssigneeAdapter extends RecyclerView.Adapter<AssigneeViewHolder> {
private static final int HEADER_COUNT = 1;
private int mColorControlHighlight;
private ArrayList<Member> mUsers;
private UserBasic mSelectedAssignee;
private View.OnClickListener mOnItemClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
if (position > 0) {
mSelectedAssignee = getUser(position);
} else {
mSelectedAssignee = null;
}
notifyDataSetChanged();
}
};
public AssigneeAdapter(Context context, UserBasic currentAssignee) {
mUsers = new ArrayList<>();
mSelectedAssignee = currentAssignee;
mColorControlHighlight = Easel.getThemeAttrColor(context, R.attr.colorControlHighlight);
}
public void setUsers(Collection<Member> users) {
mUsers.clear();
if (users != null) {
mUsers.addAll(users);
}
notifyDataSetChanged();
}
@Override
public AssigneeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
AssigneeViewHolder holder = AssigneeViewHolder.inflate(parent);
holder.itemView.setOnClickListener(mOnItemClickListener);
return holder;
}
@Override
public void onBindViewHolder(AssigneeViewHolder holder, int position) {
if (position == 0) {
holder.bind(null, mColorControlHighlight, mSelectedAssignee == null);
} else {
UserBasic user = getUser(position);
holder.bind(user, mColorControlHighlight, mSelectedAssignee == null ? false : mSelectedAssignee.equals(user));
}
holder.itemView.setTag(R.id.list_position, position);
}
@Override
public int getItemCount() {
return mUsers.size() + HEADER_COUNT;
}
private Member getUser(int position) {
return mUsers.get(position - HEADER_COUNT);
}
}
package com.commit451.gitlab.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.Member;
import com.commit451.gitlab.model.api.UserBasic;
import com.commit451.gitlab.viewHolder.AssigneeSpinnerViewHolder;
import java.util.List;
/**
* Adapter to show assignees in a spinner
*/
public class AssigneeSpinnerAdapter extends ArrayAdapter<Member> {
public AssigneeSpinnerAdapter(Context context, List<Member> members) {
super(context, 0, members);
members.add(0, null);
notifyDataSetChanged();
}
public int getSelectedItemPosition(UserBasic userBasic) {
if (userBasic == null) {
return 0;
}
for (int i=0; i<getCount(); i++) {
Member member = getItem(i);
if (member != null && userBasic.getId() == member.getId()) {
return i;
}
}
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getTheView(position, convertView, parent);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getTheView(position, convertView, parent);
}
private View getTheView(int position, View convertView, ViewGroup parent) {
Member member = getItem(position);
AssigneeSpinnerViewHolder assigneeSpinnerViewHolder;
if (convertView == null) {
assigneeSpinnerViewHolder = AssigneeSpinnerViewHolder.inflate(parent);
assigneeSpinnerViewHolder.itemView.setTag(R.id.list_view_holder, assigneeSpinnerViewHolder);
} else {
assigneeSpinnerViewHolder = (AssigneeSpinnerViewHolder) convertView.getTag(R.id.list_view_holder);
}
assigneeSpinnerViewHolder.bind(member);
return assigneeSpinnerViewHolder.itemView;
}
}
\ No newline at end of file
Loading
Loading
@@ -5,63 +5,53 @@ import android.view.View;
import android.view.ViewGroup;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.viewHolders.BreadcrumbViewHolder;
import com.commit451.gitlab.viewHolder.BreadcrumbViewHolder;
 
import java.util.ArrayList;
import java.util.Collection;
import timber.log.Timber;
import java.util.List;
 
/**
* Shows the current file path
* Created by Jawnnypoo on 11/22/2015.
*/
public class BreadcrumbAdapter extends RecyclerView.Adapter<BreadcrumbViewHolder> {
private List<Breadcrumb> mValues;
 
public interface Listener {
void onBreadcrumbClicked();
}
private Listener mListener;
private ArrayList<String> mValues;
public BreadcrumbAdapter(Listener listener) {
mListener = listener;
public BreadcrumbAdapter() {
mValues = new ArrayList<>();
clear();
notifyDataSetChanged();
}
 
private final View.OnClickListener onProjectClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
if (position != mValues.size() && mValues.size() > 1) {
ArrayList<String> itemsToRemove = new ArrayList<>();
for (int i = mValues.size()-1; i > position; i--) {
itemsToRemove.add(mValues.get(i));
}
for (String item : itemsToRemove) {
Timber.d("Removing item " + item);
}
mValues.removeAll(itemsToRemove);
notifyDataSetChanged();
mListener.onBreadcrumbClicked();
Breadcrumb breadcrumb = getValueAt(position);
if (breadcrumb != null && breadcrumb.getListener() != null) {
breadcrumb.getListener().onClick();
}
}
};
 
@Override
public BreadcrumbViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
BreadcrumbViewHolder holder = BreadcrumbViewHolder.newInstance(parent);
BreadcrumbViewHolder holder = BreadcrumbViewHolder.inflate(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
}
 
@Override
public void onBindViewHolder(final BreadcrumbViewHolder holder, int position) {
String breadcrumb = getValueAt(position);
String title = "";
boolean showArrow = position != mValues.size() - 1;
holder.bind(breadcrumb, showArrow);
Breadcrumb breadcrumb = getValueAt(position);
if (breadcrumb != null) {
title = breadcrumb.getTitle();
}
holder.bind(title, showArrow);
holder.itemView.setTag(R.id.list_position, position);
}
 
Loading
Loading
@@ -70,13 +60,8 @@ public class BreadcrumbAdapter extends RecyclerView.Adapter<BreadcrumbViewHolder
return mValues.size();
}
 
public void addBreadcrumb(String breadcrumb) {
mValues.add(breadcrumb);
notifyDataSetChanged();
}
public void setData(Collection<String> breadcrumbs) {
clear();
public void setData(Collection<Breadcrumb> breadcrumbs) {
mValues.clear();
if (breadcrumbs != null) {
mValues.addAll(breadcrumbs);
notifyItemRangeInserted(0, breadcrumbs.size());
Loading
Loading
@@ -84,23 +69,33 @@ public class BreadcrumbAdapter extends RecyclerView.Adapter<BreadcrumbViewHolder
notifyDataSetChanged();
}
 
public void clear() {
mValues.clear();
mValues.add("ROOT");
notifyDataSetChanged();
}
public Breadcrumb getValueAt(int position) {
if (position < 0 || position >= mValues.size()) {
return null;
}
 
private String getValueAt(int position) {
return mValues.get(position);
}
 
public String getCurrentPath() {
String currentPath = "";
if (mValues.size() > 1) {
for (int i = 1; i < mValues.size(); i++) {
currentPath += mValues.get(i) + "/";
}
public static class Breadcrumb {
private final String mTitle;
private final Listener mListener;
public Breadcrumb(String title, Listener listener) {
mTitle = title;
mListener = listener;
}
return currentPath;
public String getTitle() {
return mTitle;
}
public Listener getListener() {
return mListener;
}
}
public interface Listener {
void onClick();
}
}
Loading
Loading
@@ -5,65 +5,102 @@ import android.view.View;
import android.view.ViewGroup;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.DiffLine;
import com.commit451.gitlab.viewHolders.CommitViewHolder;
import com.commit451.gitlab.model.api.RepositoryCommit;
import com.commit451.gitlab.viewHolder.CommitViewHolder;
import com.commit451.gitlab.viewHolder.LoadingFooterViewHolder;
 
import java.util.ArrayList;
import java.util.Collection;
 
/**
* Shows a list of commits to a project, seen in a project overview
* Created by Jawn on 7/28/2015.
*/
public class CommitsAdapter extends RecyclerView.Adapter<CommitViewHolder> {
public class CommitsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int FOOTER_COUNT = 1;
private static final int TYPE_ITEM = 0;
private static final int TYPE_FOOTER = 1;
 
public interface Listener {
void onCommitClicked(DiffLine diffLine);
void onCommitClicked(RepositoryCommit commit);
}
private Listener mListener;
private ArrayList<DiffLine> mValues;
private ArrayList<RepositoryCommit> mValues;
private boolean mLoading = false;
 
public DiffLine getValueAt(int position) {
return mValues.get(position);
}
private final View.OnClickListener onProjectClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
mListener.onCommitClicked(getValueAt(position));
}
};
 
public CommitsAdapter(Listener listener) {
mListener = listener;
mValues = new ArrayList<>();
}
 
public void setData(Collection<DiffLine> commits) {
mValues.clear();
if (commits != null) {
mValues.addAll(commits);
notifyItemRangeInserted(0, commits.size());
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_ITEM:
CommitViewHolder holder = CommitViewHolder.inflate(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
case TYPE_FOOTER:
return LoadingFooterViewHolder.inflate(parent);
}
notifyDataSetChanged();
throw new IllegalStateException("No known ViewHolder for type " + viewType);
}
 
private final View.OnClickListener onProjectClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
mListener.onCommitClicked(getValueAt(position));
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof CommitViewHolder) {
RepositoryCommit commit = getValueAt(position);
((CommitViewHolder) holder).bind(commit);
holder.itemView.setTag(R.id.list_position, position);
} else if (holder instanceof LoadingFooterViewHolder) {
((LoadingFooterViewHolder) holder).bind(mLoading);
}
};
}
 
@Override
public CommitViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CommitViewHolder holder = CommitViewHolder.create(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
public int getItemCount() {
return mValues.size() + FOOTER_COUNT;
}
 
@Override
public void onBindViewHolder(final CommitViewHolder holder, int position) {
DiffLine commit = getValueAt(position);
holder.bind(commit);
holder.itemView.setTag(R.id.list_position, position);
public int getItemViewType(int position) {
if (position == mValues.size()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
 
@Override
public int getItemCount() {
return mValues.size();
public RepositoryCommit getValueAt(int position) {
return mValues.get(position);
}
public void addData(Collection<RepositoryCommit> commits) {
if (commits != null) {
mValues.addAll(commits);
notifyItemRangeInserted(0, commits.size());
}
notifyDataSetChanged();
}
public void setData(Collection<RepositoryCommit> commits) {
mValues.clear();
addData(commits);
}
public void setLoading(boolean loading) {
mLoading = loading;
notifyItemChanged(mValues.size());
}
}
package com.commit451.gitlab.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.Diff;
import com.commit451.gitlab.viewHolder.DiffViewHolder;
import java.util.ArrayList;
import java.util.Collection;
/**
* Shows a bunch of diffs
* Created by Jawn on 1/1/2016.
*/
public class DiffAdapter extends RecyclerView.Adapter<DiffViewHolder> {
public interface Listener {
void onDiffClicked(Diff diff);
}
private Listener mListener;
private ArrayList<Diff> mValues;
public Diff getValueAt(int position) {
return mValues.get(position);
}
public DiffAdapter(Listener listener) {
mListener = listener;
mValues = new ArrayList<>();
}
public void setData(Collection<Diff> diffs) {
mValues.clear();
if (diffs != null) {
mValues.addAll(diffs);
notifyItemRangeInserted(0, diffs.size());
}
notifyDataSetChanged();
}
private final View.OnClickListener onProjectClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
mListener.onDiffClicked(getValueAt(position));
}
};
@Override
public DiffViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
DiffViewHolder holder = DiffViewHolder.inflate(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
}
@Override
public void onBindViewHolder(final DiffViewHolder holder, int position) {
Diff diff = getValueAt(position);
holder.bind(diff);
holder.itemView.setTag(R.id.list_position, position);
}
@Override
public int getItemCount() {
return mValues.size();
}
}
Loading
Loading
@@ -6,7 +6,7 @@ import android.view.ViewGroup;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.rss.Entry;
import com.commit451.gitlab.viewHolders.FeedEntryViewHolder;
import com.commit451.gitlab.viewHolder.FeedEntryViewHolder;
 
import java.util.ArrayList;
import java.util.Collection;
Loading
Loading
@@ -47,7 +47,7 @@ public class FeedAdapter extends RecyclerView.Adapter<FeedEntryViewHolder> {
 
@Override
public FeedEntryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
FeedEntryViewHolder holder = FeedEntryViewHolder.newInstance(parent);
FeedEntryViewHolder holder = FeedEntryViewHolder.inflate(parent);
holder.itemView.setOnClickListener(mOnItemClickListener);
return holder;
}
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment