Skip to content
Snippets Groups Projects
Commit f16b99cf authored by John Carlson's avatar John Carlson
Browse files

Merge branch 'develop'

parents 2995603f eb7397c0
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 1232 additions and 148 deletions
Loading
Loading
@@ -10,13 +10,15 @@ import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
 
import com.afollestad.appthemeengine.Config;
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.transition.MorphDialogToFab;
import com.commit451.gitlab.transition.MorphFabToDialog;
import com.commit451.gitlab.util.AppThemeUtil;
 
/**
* Activity that morphs from a FAB. Make sure the view you want to morph has the view id R.id.root and
* Activity that morphs from a FAB. Make sure the view you want to morph has the view id R.id.mRoot and
* call {@link #morph(View)} when the content view is set
*/
public class MorphActivity extends BaseActivity {
Loading
Loading
@@ -27,7 +29,7 @@ public class MorphActivity extends BaseActivity {
throw new IllegalStateException("Cannot pass an empty view");
}
if (Build.VERSION.SDK_INT >= 21) {
int fabColor = Easel.getThemeAttrColor(this, R.attr.colorAccent);
int fabColor = Config.accentColor(this, AppThemeUtil.resolveThemeKey(this));
int dialogColor = Easel.getThemeAttrColor(this, android.R.attr.windowBackground);
setupSharedElementTransitionsFab(this, root,
fabColor,
Loading
Loading
Loading
Loading
@@ -3,6 +3,7 @@ package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
Loading
Loading
@@ -10,14 +11,17 @@ import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
 
import com.commit451.gitlab.LabCoatApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.SectionsPagerAdapter;
import com.commit451.gitlab.adapter.ThemedArrayAdapter;
import com.commit451.gitlab.animation.HideRunnable;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.event.ProjectReloadEvent;
import com.commit451.gitlab.fragment.BaseFragment;
Loading
Loading
@@ -31,9 +35,7 @@ import java.util.List;
 
import butterknife.Bind;
import butterknife.ButterKnife;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import timber.log.Timber;
 
public class ProjectActivity extends BaseActivity {
Loading
Loading
@@ -53,11 +55,18 @@ public class ProjectActivity extends BaseActivity {
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;
@Bind(R.id.root)
ViewGroup mRoot;
@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
Loading
Loading
@@ -66,88 +75,74 @@ public class ProjectActivity extends BaseActivity {
return;
}
 
mBranchName = ((TextView)view).getText().toString();
mBranchName = ((TextView) view).getText().toString();
broadcastLoad();
}
 
@Override
public void onNothingSelected(AdapterView<?> parent) { }
public void onNothingSelected(AdapterView<?> parent) {
}
};
 
Project mProject;
String mBranchName;
 
private final Callback<Project> mProjectCallback = new Callback<Project>() {
private final Callback<Project> mProjectCallback = new EasyCallback<Project>() {
@Override
public void onResponse(Response<Project> response, Retrofit retrofit) {
if (!response.isSuccess()) {
return;
}
mProject = response.body();
public void onResponse(@NonNull Project response) {
mProject = response;
setupTabs();
loadBranches();
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mProgress.animate().alpha(0.0f).withEndAction(new Runnable() {
@Override
public void run() {
mProgress.setVisibility(View.GONE);
}
});
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
mProgress.animate()
.alpha(0.0f)
.withEndAction(new HideRunnable(mProgress));
Snackbar.make(mRoot, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
 
private final Callback<List<Branch>> mBranchesCallback = new Callback<List<Branch>>() {
private final Callback<List<Branch>> mBranchesCallback = new EasyCallback<List<Branch>>() {
 
@Override
public void onResponse(Response<List<Branch>> response, Retrofit retrofit) {
if (!response.isSuccess()) {
return;
}
mProgress.animate().alpha(0.0f).withEndAction(new Runnable() {
@Override
public void run() {
mProgress.setVisibility(View.GONE);
}
});
public void onResponse(@NonNull List<Branch> response) {
mProgress.animate()
.alpha(0.0f)
.withEndAction(new HideRunnable(mProgress));
 
if(response.body().isEmpty()) {
if (response.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()));
mBranchSpinner.setAdapter(new ThemedArrayAdapter<>(ProjectActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, response));
}
for (int i=0; i<response.body().size(); i++) {
if (response.body().get(i).getName().equals(mProject.getDefaultBranch())) {
for (int i = 0; i < response.size(); i++) {
if (response.get(i).getName().equals(mProject.getDefaultBranch())) {
mBranchSpinner.setSelection(i);
}
}
 
mBranchSpinner.setOnItemSelectedListener(mSpinnerItemSelectedListener);
 
if(response.body().isEmpty()) {
if (response.isEmpty()) {
broadcastLoad();
}
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mProgress.animate().alpha(0.0f).withEndAction(new Runnable() {
@Override
public void run() {
mProgress.setVisibility(View.GONE);
}
});
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
mProgress.animate()
.alpha(0.0f)
.withEndAction(new HideRunnable(mProgress));
Snackbar.make(mRoot, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
Loading
Loading
@@ -157,7 +152,7 @@ public class ProjectActivity extends BaseActivity {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share:
IntentUtil.share(getWindow().getDecorView(), mProject.getWebUrl());
IntentUtil.share(mRoot, mProject.getWebUrl());
return true;
}
return false;
Loading
Loading
Loading
Loading
@@ -3,6 +3,7 @@ package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.view.GravityCompat;
Loading
Loading
@@ -12,6 +13,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
 
import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer;
import com.commit451.gitlab.LabCoatApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.ProjectsPagerAdapter;
Loading
Loading
@@ -26,7 +28,13 @@ import butterknife.ButterKnife;
* Shows the projects
* Created by Jawn on 9/21/2015.
*/
public class ProjectsActivity extends BaseActivity {
public class ProjectsActivity extends BaseActivity implements ATEActivityThemeCustomizer {
@Override
public int getActivityTheme() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
R.style.Activity_Projects : R.style.ActivityLight_Projects;
}
 
public static Intent newInstance(Context context) {
Intent intent = new Intent(context, ProjectsActivity.class);
Loading
Loading
@@ -69,7 +77,7 @@ public class ProjectsActivity extends BaseActivity {
mDrawerLayout.openDrawer(GravityCompat.START);
}
});
mToolbar.inflateMenu(R.menu.search);
mToolbar.inflateMenu(R.menu.menu_search);
mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
mViewPager.setAdapter(new ProjectsPagerAdapter(this, getSupportFragmentManager()));
mTabLayout.setupWithViewPager(mViewPager);
Loading
Loading
Loading
Loading
@@ -2,27 +2,131 @@ package com.commit451.gitlab.activity;
 
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.v7.widget.Toolbar;
import android.view.View;
 
import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.prefs.ATEColorPreference;
import com.afollestad.materialdialogs.color.ColorChooserDialog;
import com.commit451.gitlab.R;
 
import butterknife.Bind;
import butterknife.ButterKnife;
 
/**
* Settings screens are fun!
* Created by John on 11/10/15.
*/
public class SettingsActivity extends BaseActivity {
public class SettingsActivity extends BaseActivity
implements ColorChooserDialog.ColorCallback {
 
public static Intent newInstance(Context context) {
Intent intent = new Intent(context, SettingsActivity.class);
return intent;
}
 
@Bind(R.id.toolbar) Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
ButterKnife.bind(this);
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
toolbar.setTitle(R.string.settings);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().replace(R.id.settings_container, new SettingsFragment()).commit();
} else {
SettingsFragment frag = (SettingsFragment) getFragmentManager().findFragmentById(R.id.settings_container);
if (frag != null) {
frag.invalidateSettings();
}
}
}
@Override
public void onColorSelection(@NonNull ColorChooserDialog dialog, @ColorInt int selectedColor) {
final Config config = ATE.config(this, getATEKey());
switch (dialog.getTitle()) {
case R.string.primary_color:
config.primaryColor(selectedColor);
break;
case R.string.accent_color:
config.accentColor(selectedColor);
break;
}
config.commit();
recreate(); // recreation needed to reach the checkboxes in the preferences layout
}
public static class SettingsFragment extends PreferenceFragment {
String mAteKey;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
invalidateSettings();
}
public void invalidateSettings() {
mAteKey = ((SettingsActivity) getActivity()).getATEKey();
ATEColorPreference primaryColorPref = (ATEColorPreference) findPreference("primary_color");
primaryColorPref.setColor(Config.primaryColor(getActivity(), mAteKey), Color.BLACK);
primaryColorPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new ColorChooserDialog.Builder((SettingsActivity) getActivity(), R.string.primary_color)
.preselect(Config.primaryColor(getActivity(), mAteKey))
.show();
return true;
}
});
ATEColorPreference accentColorPref = (ATEColorPreference) findPreference("accent_color");
accentColorPref.setColor(Config.accentColor(getActivity(), mAteKey), Color.BLACK);
accentColorPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new ColorChooserDialog.Builder((SettingsActivity) getActivity(), R.string.accent_color)
.preselect(Config.accentColor(getActivity(), mAteKey))
.show();
return true;
}
});
findPreference("dark_theme").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Marks both theme configs as changed so MainActivity restarts itself on return
Config.markChanged(getActivity(), "light_theme");
Config.markChanged(getActivity(), "dark_theme");
// The dark_theme preference value gets saved by Android in the default PreferenceManager.
// It's used in getATEKey() of both the Activities.
getActivity().recreate();
return true;
}
});
}
}
}
Loading
Loading
@@ -4,13 +4,12 @@ import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.Intent;
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.preference.PreferenceManager;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.graphics.Palette;
Loading
Loading
@@ -18,14 +17,17 @@ import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ImageView;
 
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer;
import com.afollestad.appthemeengine.util.ATEUtil;
import com.commit451.easel.Easel;
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.fragment.FeedFragment;
import com.commit451.gitlab.model.api.UserBasic;
import com.commit451.gitlab.util.AppThemeUtil;
import com.commit451.gitlab.transformation.PaletteTransformation;
import com.commit451.gitlab.util.ImageUtil;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
 
import org.parceler.Parcels;
 
Loading
Loading
@@ -36,7 +38,13 @@ import butterknife.ButterKnife;
* User activity, which shows the user!
* Created by Jawn on 9/21/2015.
*/
public class UserActivity extends BaseActivity {
public class UserActivity extends BaseActivity implements ATEActivityThemeCustomizer {
@Override
public int getActivityTheme() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
R.style.Activity_User : R.style.ActivityLight_User;
}
 
private static final String KEY_USER = "user";
 
Loading
Loading
@@ -52,30 +60,21 @@ public class UserActivity extends BaseActivity {
 
UserBasic mUser;
 
private final Target mImageLoadTarget = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
mBackdrop.setImageBitmap(bitmap);
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
public void onGenerated(Palette p) {
bindPalette(p);
}
});
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
ButterKnife.bind(this);
mUser = Parcels.unwrap(getIntent().getParcelableExtra(KEY_USER));
// Default content and scrim colors
mCollapsingToolbarLayout.setContentScrimColor(
Config.primaryColor(this, AppThemeUtil.resolveThemeKey(this)));
mCollapsingToolbarLayout.setStatusBarScrimColor(
Config.primaryColorDark(this, AppThemeUtil.resolveThemeKey(this)));
mCollapsingToolbarLayout.setCollapsedTitleTextColor(Color.WHITE);
mCollapsingToolbarLayout.setExpandedTitleColor(Color.WHITE);
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
Loading
Loading
@@ -85,9 +84,19 @@ public class UserActivity extends BaseActivity {
});
mToolbar.setTitle(mUser.getUsername());
Uri url = ImageUtil.getAvatarUrl(mUser, getResources().getDimensionPixelSize(R.dimen.user_header_image_size));
GitLabClient.getPicasso()
.load(url)
.into(mImageLoadTarget);
.transform(PaletteTransformation.instance())
.into(mBackdrop, new PaletteTransformation.PaletteCallback(mBackdrop) {
@Override
protected void onSuccess(Palette palette) {
bindPalette(palette);
}
@Override
public void onError() {}
});
 
if (savedInstanceState == null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Loading
Loading
@@ -102,8 +111,8 @@ public class UserActivity extends BaseActivity {
 
private void bindPalette(Palette palette) {
int animationTime = 1000;
int vibrantColor = palette.getVibrantColor(Easel.getThemeAttrColor(this, R.attr.colorPrimary));
int darkerColor = Easel.getDarkerColor(vibrantColor);
int vibrantColor = palette.getVibrantColor(AppThemeUtil.resolvePrimaryColor(this));
int darkerColor = ATEUtil.darkenColor(vibrantColor);
 
if (Build.VERSION.SDK_INT >= 21) {
Easel.getNavigationBarColorAnimator(getWindow(), darkerColor)
Loading
Loading
Loading
Loading
@@ -6,6 +6,8 @@ import android.view.ViewGroup;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.Diff;
import com.commit451.gitlab.model.api.RepositoryCommit;
import com.commit451.gitlab.viewHolder.DiffHeaderViewHolder;
import com.commit451.gitlab.viewHolder.DiffViewHolder;
 
import java.util.ArrayList;
Loading
Loading
@@ -13,21 +15,27 @@ import java.util.Collection;
 
/**
* Shows a bunch of diffs
* Created by Jawn on 1/1/2016.
*/
public class DiffAdapter extends RecyclerView.Adapter<DiffViewHolder> {
public class DiffAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int TYPE_HEADER = 0;
public static final int TYPE_ITEM = 1;
public static final int HEADER_COUNT = 1;
 
public interface Listener {
void onDiffClicked(Diff diff);
}
private Listener mListener;
private RepositoryCommit mRepositoryCommit;
private ArrayList<Diff> mValues;
 
public Diff getValueAt(int position) {
return mValues.get(position);
return mValues.get(position - HEADER_COUNT);
}
 
public DiffAdapter(Listener listener) {
public DiffAdapter(RepositoryCommit repositoryCommit, Listener listener) {
mRepositoryCommit = repositoryCommit;
mListener = listener;
mValues = new ArrayList<>();
}
Loading
Loading
@@ -36,7 +44,8 @@ public class DiffAdapter extends RecyclerView.Adapter<DiffViewHolder> {
mValues.clear();
if (diffs != null) {
mValues.addAll(diffs);
notifyItemRangeInserted(0, diffs.size());
notifyItemRangeInserted(HEADER_COUNT, diffs.size());
return;
}
notifyDataSetChanged();
}
Loading
Loading
@@ -50,21 +59,40 @@ public class DiffAdapter extends RecyclerView.Adapter<DiffViewHolder> {
};
 
@Override
public DiffViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
DiffViewHolder holder = DiffViewHolder.inflate(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_HEADER:
return DiffHeaderViewHolder.inflate(parent);
case TYPE_ITEM:
DiffViewHolder holder = DiffViewHolder.inflate(parent);
holder.itemView.setOnClickListener(onProjectClickListener);
return holder;
}
throw new IllegalStateException("No known view holder for " + viewType);
}
 
@Override
public void onBindViewHolder(final DiffViewHolder holder, int position) {
Diff diff = getValueAt(position);
holder.bind(diff);
holder.itemView.setTag(R.id.list_position, position);
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof DiffHeaderViewHolder) {
((DiffHeaderViewHolder) holder).bind(mRepositoryCommit);
} else if (holder instanceof DiffViewHolder) {
Diff diff = getValueAt(position);
((DiffViewHolder) holder).bind(diff);
holder.itemView.setTag(R.id.list_position, position);
}
}
 
@Override
public int getItemCount() {
return mValues.size();
return mValues.size() + HEADER_COUNT;
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
} else {
return TYPE_ITEM;
}
}
}
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.commit451.gitlab.adapter;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.commit451.gitlab.R;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
private Drawable mDivider;
private int mDividerHeight;
private boolean mShowFirstDivider = true;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
mDividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height);
}
public DividerItemDecoration(Context context, boolean first) {
this(context);
mShowFirstDivider = first;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawVertical(c, parent);
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
if (isSkipped(child, parent)) continue;
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDividerHeight;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
if (isSkipped(view, parent)) return;
outRect.set(0, 0, 0, mDividerHeight);
}
private boolean isSkipped(View child, RecyclerView parent) {
int position = parent.getChildAdapterPosition(child);
// Skip the first divider if needed
if (!mShowFirstDivider && position == 0) return true;
// Skip the last divider if needed
if (!mShowLastDivider && position == parent.getAdapter().getItemCount() - 1) return true;
// Otherwise don't skip
return false;
}
}
\ No newline at end of file
Loading
Loading
@@ -7,10 +7,11 @@ import android.view.ViewGroup;
import com.commit451.gitlab.model.api.Issue;
import com.commit451.gitlab.model.api.Note;
import com.commit451.gitlab.viewHolder.IssueHeaderViewHolder;
import com.commit451.gitlab.viewHolder.IssueLabelsViewHolder;
import com.commit451.gitlab.viewHolder.LoadingFooterViewHolder;
import com.commit451.gitlab.viewHolder.NoteViewHolder;
 
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
 
import in.uncod.android.bypass.Bypass;
Loading
Loading
@@ -22,20 +23,21 @@ import in.uncod.android.bypass.Bypass;
public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
private static final int TYPE_HEADER = 0;
private static final int TYPE_COMMENT = 1;
private static final int TYPE_FOOTER = 2;
private static final int TYPE_HEADER_LABEL = 1;
private static final int TYPE_COMMENT = 2;
private static final int TYPE_FOOTER = 3;
 
private static final int HEADER_COUNT = 1;
private static final int HEADER_COUNT = 2;
private static final int FOOTER_COUNT = 1;
 
private ArrayList<Note> mNotes;
private LinkedList<Note> mNotes;
private Issue mIssue;
private boolean mLoading = false;
private Bypass mBypass;
 
public IssueDetailsAdapter(Context context, Issue issue) {
mIssue = issue;
mNotes = new ArrayList<>();
mNotes = new LinkedList<>();
mBypass = new Bypass(context);
}
 
Loading
Loading
@@ -43,9 +45,10 @@ public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
return IssueHeaderViewHolder.inflate(parent);
} else if (viewType == TYPE_HEADER_LABEL) {
return IssueLabelsViewHolder.inflate(parent);
} else if (viewType == TYPE_COMMENT) {
RecyclerView.ViewHolder holder = NoteViewHolder.inflate(parent);
return holder;
return NoteViewHolder.inflate(parent);
} else if (viewType == TYPE_FOOTER) {
return LoadingFooterViewHolder.inflate(parent);
}
Loading
Loading
@@ -56,6 +59,8 @@ public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof IssueHeaderViewHolder) {
((IssueHeaderViewHolder) holder).bind(mIssue);
} else if (holder instanceof IssueLabelsViewHolder) {
((IssueLabelsViewHolder) holder).bind(mIssue.getLabels());
} else if (holder instanceof NoteViewHolder) {
Note note = getNoteAt(position);
((NoteViewHolder) holder).bind(note, mBypass);
Loading
Loading
@@ -71,8 +76,10 @@ public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
 
@Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
if (position == 0) {
return TYPE_HEADER;
} else if (position == 1) {
return TYPE_HEADER_LABEL;
} else if (position == HEADER_COUNT + mNotes.size()) {
return TYPE_FOOTER;
} else {
Loading
Loading
@@ -80,12 +87,8 @@ public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
}
 
private boolean isPositionHeader(int position) {
return position == 0;
}
public Note getNoteAt(int position) {
return mNotes.get(position-1);
return mNotes.get(position - HEADER_COUNT);
}
 
public void setNotes(List<Note> notes) {
Loading
Loading
@@ -101,7 +104,7 @@ public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
 
public void addNote(Note note) {
mNotes.add(note);
mNotes.addFirst(note);
notifyItemInserted(HEADER_COUNT);
}
 
Loading
Loading
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.viewHolder.LabelViewHolder;
import java.util.ArrayList;
import java.util.Collection;
/**
* So many labels
*/
public class IssueLabelsAdapter extends RecyclerView.Adapter<LabelViewHolder> {
public interface Listener {
void onLabelClicked(String label, LabelViewHolder viewHolder);
}
private Listener mListener;
private ArrayList<String> mValues;
public IssueLabelsAdapter(Listener listener) {
mListener = listener;
mValues = new ArrayList<>();
}
private final View.OnClickListener mOnItemClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = (int) v.getTag(R.id.list_position);
LabelViewHolder holder = (LabelViewHolder) v.getTag(R.id.list_view_holder);
mListener.onLabelClicked(getEntry(position), holder);
}
};
public void setLabels(Collection<String> labels) {
mValues.clear();
addLabels(labels);
}
public void addLabels(Collection<String> labels) {
if (labels != null) {
mValues.addAll(labels);
}
notifyDataSetChanged();
}
@Override
public LabelViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LabelViewHolder holder = LabelViewHolder.inflate(parent);
holder.itemView.setOnClickListener(mOnItemClickListener);
return holder;
}
@Override
public void onBindViewHolder(final LabelViewHolder holder, int position) {
holder.itemView.setTag(R.id.list_position, position);
holder.itemView.setTag(R.id.list_view_holder, holder);
holder.bind(getEntry(position));
}
@Override
public int getItemCount() {
return mValues.size();
}
private String getEntry(int position) {
return mValues.get(position);
}
}
Loading
Loading
@@ -10,7 +10,7 @@ import com.commit451.gitlab.viewHolder.LoadingFooterViewHolder;
import com.commit451.gitlab.viewHolder.MergeRequestHeaderViewHolder;
import com.commit451.gitlab.viewHolder.NoteViewHolder;
 
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
 
import in.uncod.android.bypass.Bypass;
Loading
Loading
@@ -28,14 +28,14 @@ public class MergeRequestDetailAdapter extends RecyclerView.Adapter<RecyclerView
private static final int HEADER_COUNT = 1;
private static final int FOOTER_COUNT = 1;
 
private ArrayList<Note> mNotes;
private LinkedList<Note> mNotes;
private MergeRequest mMergeRequest;
private boolean mLoading = false;
private Bypass mBypass;
 
public MergeRequestDetailAdapter(Context context, MergeRequest mergeRequest) {
mMergeRequest = mergeRequest;
mNotes = new ArrayList<>();
mNotes = new LinkedList<>();
mBypass = new Bypass(context);
}
 
Loading
Loading
@@ -44,8 +44,7 @@ public class MergeRequestDetailAdapter extends RecyclerView.Adapter<RecyclerView
if (viewType == TYPE_HEADER) {
return MergeRequestHeaderViewHolder.inflate(parent);
} else if (viewType == TYPE_COMMENT) {
RecyclerView.ViewHolder holder = NoteViewHolder.inflate(parent);
return holder;
return NoteViewHolder.inflate(parent);
} else if (viewType == TYPE_FOOTER) {
return LoadingFooterViewHolder.inflate(parent);
}
Loading
Loading
@@ -85,12 +84,12 @@ public class MergeRequestDetailAdapter extends RecyclerView.Adapter<RecyclerView
}
 
public Note getNoteAt(int position) {
return mNotes.get(position-1);
return mNotes.get(position - HEADER_COUNT);
}
 
public void addNote(Note note) {
mNotes.add(note);
notifyItemInserted(mNotes.size() + HEADER_COUNT);
mNotes.addFirst(note);
notifyItemInserted(HEADER_COUNT);
}
 
public void setNotes(List<Note> notes) {
Loading
Loading
@@ -109,4 +108,8 @@ public class MergeRequestDetailAdapter extends RecyclerView.Adapter<RecyclerView
mLoading = loading;
notifyItemChanged(mNotes.size() + HEADER_COUNT);
}
public static int getHeaderCount() {
return HEADER_COUNT;
}
}
package com.commit451.gitlab.adapter;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.commit451.gitlab.R;
import com.commit451.gitlab.fragment.MergeRequestCommitsFragment;
import com.commit451.gitlab.fragment.MergeRequestDiscussionFragment;
import com.commit451.gitlab.model.api.MergeRequest;
import com.commit451.gitlab.model.api.Project;
/**
* Projects Pager Adapter
*/
public class MergeRequestSectionsPagerAdapter extends FragmentPagerAdapter {
private static final int SECTION_COUNT = 2;
private Project mProject;
private MergeRequest mMergeRequest;
private String[] mTitles;
public MergeRequestSectionsPagerAdapter(Context context, FragmentManager fm, Project project, MergeRequest mergeRequest) {
super(fm);
mProject = project;
mMergeRequest = mergeRequest;
mTitles = context.getResources().getStringArray(R.array.merge_request_tabs);
}
@Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return MergeRequestDiscussionFragment.newInstance(mProject, mMergeRequest);
case 1:
return MergeRequestCommitsFragment.newInstance(mProject, mMergeRequest);
}
throw new IllegalStateException("Position exceeded on view pager");
}
@Override
public int getCount() {
return SECTION_COUNT;
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
Loading
Loading
@@ -10,7 +10,6 @@ import com.commit451.gitlab.fragment.ProjectsFragment;
 
/**
* Projects Pager Adapter
* Created by Jawn on 9/21/2015.
*/
public class ProjectsPagerAdapter extends FragmentPagerAdapter {
private static final int SECTION_COUNT = 3;
Loading
Loading
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.commit451.gitlab.adapter;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.support.annotation.ArrayRes;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.view.ContextThemeWrapper;
import android.support.v7.widget.ThemedSpinnerAdapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.util.ATEUtil;
import com.commit451.gitlab.util.AppThemeUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* An Adapter derived from ArrayAdapter that also allows theming with AppThemeEngine
*/
public class ThemedArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
/**
* Lock used to modify the content of {@link #mObjects}. Any write operation
* performed on the array should be synchronized on this lock. This lock is also
* used by the filter (see {@link #getFilter()} to make a synchronized copy of
* the original array of data.
*/
private final Object mLock = new Object();
private final LayoutInflater mInflater;
/**
* Contains the list of objects that represent the data of this ThemedArrayAdapter.
* The content of this list is referred to as "the array" in the documentation.
*/
private List<T> mObjects;
/**
* The resource indicating what views to inflate to display the content of this
* array adapter.
*/
private int mResource;
/**
* The resource indicating what views to inflate to display the content of this
* array adapter in a drop down widget.
*/
private int mDropDownResource;
/**
* If the inflated resource is not a TextView, {@link #mFieldId} is used to find
* a TextView inside the inflated views hierarchy. This field must contain the
* identifier that matches the one defined in the resource file.
*/
private int mFieldId = 0;
/**
* Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
* {@link #mObjects} is modified.
*/
private boolean mNotifyOnChange = true;
private Context mContext;
// A copy of the original mObjects array, initialized from and then used instead as soon as
// the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
private ArrayList<T> mOriginalValues;
private ArrayFilter mFilter;
/** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */
private LayoutInflater mDropDownInflater;
/**
* Constructor
*
* @param context The current context.
* @param resource The resource ID for a layout file containing a TextView to use when
* instantiating views.
*/
public ThemedArrayAdapter(Context context, @LayoutRes int resource) {
this(context, resource, 0, new ArrayList<T>());
}
/**
* Constructor
*
* @param context The current context.
* @param resource The resource ID for a layout file containing a layout to use when
* instantiating views.
* @param textViewResourceId The id of the TextView within the layout resource to be populated
*/
public ThemedArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
this(context, resource, textViewResourceId, new ArrayList<T>());
}
/**
* Constructor
*
* @param context The current context.
* @param resource The resource ID for a layout file containing a TextView to use when
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
public ThemedArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) {
this(context, resource, 0, Arrays.asList(objects));
}
/**
* Constructor
*
* @param context The current context.
* @param resource The resource ID for a layout file containing a layout to use when
* instantiating views.
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
public ThemedArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
@NonNull T[] objects) {
this(context, resource, textViewResourceId, Arrays.asList(objects));
}
/**
* Constructor
*
* @param context The current context.
* @param resource The resource ID for a layout file containing a TextView to use when
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
public ThemedArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
this(context, resource, 0, objects);
}
/**
* Constructor
*
* @param context The current context.
* @param resource The resource ID for a layout file containing a layout to use when
* instantiating views.
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
public ThemedArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
@NonNull List<T> objects) {
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = mDropDownResource = resource;
mObjects = objects;
mFieldId = textViewResourceId;
}
/**
* Adds the specified object at the end of the array.
*
* @param object The object to add at the end of the array.
*/
public void add(T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
} else {
mObjects.add(object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Adds the specified Collection at the end of the array.
*
* @param collection The Collection to add at the end of the array.
*/
public void addAll(Collection<? extends T> collection) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.addAll(collection);
} else {
mObjects.addAll(collection);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Adds the specified items at the end of the array.
*
* @param items The items to add at the end of the array.
*/
public void addAll(T ... items) {
synchronized (mLock) {
if (mOriginalValues != null) {
Collections.addAll(mOriginalValues, items);
} else {
Collections.addAll(mObjects, items);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Inserts the specified object at the specified index in the array.
*
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
public void insert(T object, int index) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(index, object);
} else {
mObjects.add(index, object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Removes the specified object from the array.
*
* @param object The object to remove.
*/
public void remove(T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.remove(object);
} else {
mObjects.remove(object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Remove all elements from the list.
*/
public void clear() {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.clear();
} else {
mObjects.clear();
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Sorts the content of this adapter using the specified comparator.
*
* @param comparator The comparator used to sort the objects contained
* in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
synchronized (mLock) {
if (mOriginalValues != null) {
Collections.sort(mOriginalValues, comparator);
} else {
Collections.sort(mObjects, comparator);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* {@inheritDoc}
*/
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
mNotifyOnChange = true;
}
/**
* Control whether methods that change the list ({@link #add},
* {@link #insert}, {@link #remove}, {@link #clear}) automatically call
* {@link #notifyDataSetChanged}. If set to false, caller must
* manually call notifyDataSetChanged() to have the changes
* reflected in the attached view.
*
* The default is true, and calling notifyDataSetChanged()
* resets the flag to true.
*
* @param notifyOnChange if true, modifications to the list will
* automatically call {@link
* #notifyDataSetChanged}
*/
public void setNotifyOnChange(boolean notifyOnChange) {
mNotifyOnChange = notifyOnChange;
}
/**
* Returns the context associated with this array adapter. The context is used
* to create views from the resource passed to the constructor.
*
* @return The Context associated with this adapter.
*/
public Context getContext() {
return mContext;
}
/**
* {@inheritDoc}
*/
public int getCount() {
return mObjects.size();
}
/**
* {@inheritDoc}
*/
public T getItem(int position) {
return mObjects.get(position);
}
/**
* Returns the position of the specified item in the array.
*
* @param item The item to retrieve the position of.
*
* @return The position of the specified item.
*/
public int getPosition(T item) {
return mObjects.indexOf(item);
}
/**
* {@inheritDoc}
*/
public long getItemId(int position) {
return position;
}
/**
* {@inheritDoc}
*/
public View getView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource, false);
}
private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
ViewGroup parent, int resource, boolean dropdown) {
View view;
TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}
try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = (TextView) view.findViewById(mFieldId);
}
} catch (ClassCastException e) {
Log.e("ThemedArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ThemedArrayAdapter requires the resource ID to be a TextView", e);
}
// Theme the TextView with AppThemeEngine values
if (dropdown) {
text.setTextColor(Config.textColorPrimary(view.getContext(),
AppThemeUtil.resolveThemeKey(view.getContext())));
} else {
text.setTextColor(ATEUtil.isColorLight(Config.primaryColor(view.getContext(),
AppThemeUtil.resolveThemeKey(view.getContext()))) ? Color.BLACK : Color.WHITE);
}
T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence)item);
} else {
text.setText(item.toString());
}
return view;
}
/**
* <p>Sets the layout resource to create the drop down views.</p>
*
* @param resource the layout resource defining the drop down views
* @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
*/
public void setDropDownViewResource(@LayoutRes int resource) {
this.mDropDownResource = resource;
}
/**
* Sets the {@link Resources.Theme} against which drop-down views are
* inflated.
* <p>
* By default, drop-down views are inflated against the theme of the
* {@link Context} passed to the adapter's constructor.
*
* @param theme the theme against which to inflate drop-down views or
* {@code null} to use the theme from the adapter's context
* @see #getDropDownView(int, View, ViewGroup)
*/
@Override
public void setDropDownViewTheme(Resources.Theme theme) {
if (theme == null) {
mDropDownInflater = null;
} else if (theme == mInflater.getContext().getTheme()) {
mDropDownInflater = mInflater;
} else {
final Context context = new ContextThemeWrapper(mContext, theme);
mDropDownInflater = LayoutInflater.from(context);
}
}
@Override
public Resources.Theme getDropDownViewTheme() {
return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
return createViewFromResource(inflater, position, convertView, parent, mDropDownResource, true);
}
/**
* Creates a new ThemedArrayAdapter from external resources. The content of the array is
* obtained through {@link android.content.res.Resources#getTextArray(int)}.
*
* @param context The application's environment.
* @param textArrayResId The identifier of the array to use as the data source.
* @param textViewResId The identifier of the layout used to create views.
*
* @return An ThemedArrayAdapter<CharSequence>.
*/
public static ThemedArrayAdapter<CharSequence> createFromResource(Context context,
@ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
return new ThemedArrayAdapter<CharSequence>(context, textViewResId, strings);
}
/**
* {@inheritDoc}
*/
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
/**
* <p>An array filter constrains the content of the array adapter with
* a prefix. Each item that does not start with the supplied prefix
* is removed from the list.</p>
*/
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (mLock) {
mOriginalValues = new ArrayList<T>(mObjects);
}
}
if (prefix == null || prefix.length() == 0) {
ArrayList<T> list;
synchronized (mLock) {
list = new ArrayList<T>(mOriginalValues);
}
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase();
ArrayList<T> values;
synchronized (mLock) {
values = new ArrayList<T>(mOriginalValues);
}
final int count = values.size();
final ArrayList<T> newValues = new ArrayList<T>();
for (int i = 0; i < count; i++) {
final T value = values.get(i);
final String valueText = value.toString().toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
final String[] words = valueText.split(" ");
final int wordCount = words.length;
// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(value);
break;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
//noinspection unchecked
mObjects = (List<T>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}
\ No newline at end of file
package com.commit451.gitlab.animation;
import android.view.View;
import java.lang.ref.WeakReference;
/**
* Hides the view when run. Usually used with {@link android.view.ViewPropertyAnimator#withEndAction(Runnable)}
*/
public class HideRunnable implements Runnable {
private WeakReference<View> mViewWeakReference;
public HideRunnable(View view) {
mViewWeakReference = new WeakReference<>(view);
}
@Override
public void run() {
if (mViewWeakReference != null) {
View view = mViewWeakReference.get();
if (view != null) {
view.setVisibility(View.GONE);
}
}
}
}
package com.commit451.gitlab.animation;
import android.view.View;
import java.lang.ref.WeakReference;
/**
* Shows the view. Usually used with {@link android.view.ViewPropertyAnimator#withStartAction(Runnable)}
*/
public class ShowRunnable implements Runnable {
private WeakReference<View> mViewWeakReference;
public ShowRunnable(View view) {
mViewWeakReference = new WeakReference<>(view);
}
@Override
public void run() {
if (mViewWeakReference != null) {
View view = mViewWeakReference.get();
if (view != null) {
view.setVisibility(View.VISIBLE);
}
}
}
}
package com.commit451.gitlab.api;
 
import com.commit451.gitlab.model.Account;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
 
import java.io.IOException;
 
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import timber.log.Timber;
 
/**
Loading
Loading
@@ -30,7 +30,7 @@ public class AuthenticationRequestInterceptor implements Interceptor {
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
 
HttpUrl url = request.httpUrl();
HttpUrl url = request.url();
 
String cleanUrl = url.toString();
cleanUrl = cleanUrl.substring(cleanUrl.indexOf(':'));
Loading
Loading
package com.commit451.gitlab.api;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.commit451.gitlab.api.exception.HttpException;
import com.commit451.gitlab.api.exception.NullBodyException;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* An easier version of a Retrofit callback that simplifies
* the response block so that you do not have to check
* {@link Response#isSuccessful()}. You can still call {@link #getResponse()}
* if you need it. If there is a HTTP error, {@link #onAllFailure(Throwable)}
* will be called with a {@link HttpException}
*/
public abstract class EasyCallback<T> implements Callback<T> {
@Nullable
private Response<T> mResponse;
private Call<T> mCall;
public abstract void onResponse(@NonNull T response);
public abstract void onAllFailure(Throwable t);
@Override
public void onResponse(Call<T> call, Response<T> response) {
mCall = call;
mResponse = response;
if (!response.isSuccessful()) {
onAllFailure(new HttpException(response.code(), response.errorBody()));
return;
}
if (response.body() == null) {
onAllFailure(new NullBodyException());
return;
}
onResponse(response.body());
}
@Override
public void onFailure(Call<T> call, Throwable t) {
mCall = call;
onAllFailure(t);
}
@Nullable
public Response<T> getResponse() {
return mResponse;
}
@Nullable
public Call<T> getCall() {
return mCall;
}
}
Loading
Loading
@@ -8,6 +8,7 @@ import com.commit451.gitlab.model.api.Diff;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.model.api.GroupDetail;
import com.commit451.gitlab.model.api.Issue;
import com.commit451.gitlab.model.api.Label;
import com.commit451.gitlab.model.api.Member;
import com.commit451.gitlab.model.api.MergeRequest;
import com.commit451.gitlab.model.api.Milestone;
Loading
Loading
@@ -23,16 +24,17 @@ import com.commit451.gitlab.model.api.UserLogin;
 
import java.util.List;
 
import retrofit.Call;
import retrofit.http.DELETE;
import retrofit.http.Field;
import retrofit.http.FormUrlEncoded;
import retrofit.http.GET;
import retrofit.http.POST;
import retrofit.http.PUT;
import retrofit.http.Path;
import retrofit.http.Query;
import retrofit.http.Url;
import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;
import retrofit2.http.Url;
 
/**
* Defines the interface for Retrofit for the GitLab API
Loading
Loading
@@ -111,10 +113,10 @@ public interface GitLab {
 
/* --- PROJECTS --- */
 
@GET(API_VERSION + "/projects?order_by=last_activity_at")
@GET(API_VERSION + "/projects?order_by=last_activity_at&archived=false")
Call<List<Project>> getAllProjects();
 
@GET(API_VERSION + "/projects/owned?order_by=last_activity_at")
@GET(API_VERSION + "/projects/owned?order_by=last_activity_at&archived=false")
Call<List<Project>> getMyProjects();
 
@GET(API_VERSION + "/projects/starred")
Loading
Loading
@@ -180,6 +182,11 @@ public interface GitLab {
@Field("description") String description,
@Field("due_date") String dueDate);
 
@PUT(API_VERSION + "/projects/{id}/milestones/{milestone_id}")
Call<Milestone> updateMilestoneStatus(@Path("id") long projectId,
@Path("milestone_id") long milestoneId,
@Query("state_event") @Milestone.StateEvent String status);
/* --- MERGE REQUESTS --- */
 
@GET(API_VERSION + "/projects/{id}/merge_requests")
Loading
Loading
@@ -198,6 +205,14 @@ public interface GitLab {
Call<List<Note>> getMergeRequestNotes(@Path("id") long projectId,
@Path("merge_request_id") long mergeRequestId);
 
@GET(API_VERSION + "/projects/{id}/merge_requests/{merge_request_id}/commits")
Call<List<RepositoryCommit>> getMergeRequestCommits(@Path("id") long projectId,
@Path("merge_request_id") long mergeRequestId);
@GET(API_VERSION + "/projects/{id}/merge_requests/{merge_request_id}/changes")
Call<MergeRequest> getMergeRequestChanges(@Path("id") long projectId,
@Path("merge_request_id") long mergeRequestId);
@GET
Call<List<Note>> getMergeRequestNotes(@Url String url);
 
Loading
Loading
@@ -285,4 +300,33 @@ public interface GitLab {
@GET(API_VERSION + "/projects/{id}/repository/commits/{sha}/diff")
Call<List<Diff>> getCommitDiff(@Path("id") long projectId,
@Path("sha") String commitSHA);
/**
* Get the current labels for a project
* @param projectId id
* @return all the labels within a project
*/
@GET(API_VERSION + "/projects/{id}/labels")
Call<List<Label>> getLabels(@Path("id") long projectId);
/**
* Create a new label
* @param projectId id
* @param name the name of the label
* @param color the color, ex. #ff0000
* @return call onSuccess the newly created label
*/
@POST(API_VERSION + "/projects/{id}/labels")
Call<Label> createLabel(@Path("id") long projectId,
@Query("name") String name,
@Query("color") String color);
/**
* Delete the label by its name
* @param projectId id
* @return all the labels within a project
*/
@DELETE(API_VERSION + "/projects/{id}/labels")
Call<Label> deleteLabel(@Path("id") long projectId,
@Query("name") String name);
}
\ No newline at end of file
Loading
Loading
@@ -5,18 +5,18 @@ import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.provider.GsonProvider;
import com.commit451.gitlab.provider.OkHttpClientProvider;
import com.commit451.gitlab.provider.SimpleXmlProvider;
import com.squareup.picasso.OkHttpDownloader;
import com.jakewharton.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;
 
import java.util.List;
 
import retrofit.GsonConverterFactory;
import retrofit.Retrofit;
import retrofit.SimpleXmlConverterFactory;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
 
/**
* Pulls all the GitLab stuff from the API
* Created by Jawn on 7/28/2015.
*/
public final class GitLabClient {
 
Loading
Loading
@@ -63,7 +63,6 @@ public final class GitLabClient {
}
 
public static GitLabRss rssInstance(Account account) {
checkAccountSet();
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(account.getServerUrl().toString())
.client(OkHttpClientProvider.getInstance(account))
Loading
Loading
@@ -74,6 +73,7 @@ public final class GitLabClient {
 
public static GitLabRss rssInstance() {
if (sGitLabRss == null) {
checkAccountSet();
sGitLabRss = rssInstance(sAccount);
}
 
Loading
Loading
@@ -81,14 +81,15 @@ public final class GitLabClient {
}
 
public static Picasso getPicasso(Account account) {
checkAccountSet();
OkHttpClient client = OkHttpClientProvider.getInstance(account);
return new Picasso.Builder(LabCoatApp.instance())
.downloader(new OkHttpDownloader(OkHttpClientProvider.getInstance(account)))
.downloader(new OkHttp3Downloader(client))
.build();
}
 
public static Picasso getPicasso() {
if (sPicasso == null) {
checkAccountSet();
sPicasso = getPicasso(sAccount);
}
 
Loading
Loading
@@ -98,6 +99,10 @@ public final class GitLabClient {
private static void checkAccountSet() {
if (sAccount == null) {
List<Account> accounts = Account.getAccounts(LabCoatApp.instance());
if (accounts.isEmpty()) {
throw new IllegalStateException("No accounts found");
}
GitLabClient.setAccount(accounts.get(0));
}
}
Loading
Loading
Loading
Loading
@@ -2,9 +2,9 @@ package com.commit451.gitlab.api;
 
import com.commit451.gitlab.model.rss.Feed;
 
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Url;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Url;
 
public interface GitLabRss {
 
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