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

Merge branch 'master' into fdroid

# Conflicts:
#	.magnum.yml
#	.travis.yml
#	README.md
#	app/build.gradle
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/commit451/gitlab/LabCoatApp.java
#	build.gradle
parents 1b90c181 16caa78a
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 107 additions and 932 deletions
Loading
Loading
@@ -44,8 +44,6 @@ public class DiffAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
mValues.clear();
if (diffs != null) {
mValues.addAll(diffs);
notifyItemRangeInserted(HEADER_COUNT, diffs.size());
return;
}
notifyDataSetChanged();
}
Loading
Loading
Loading
Loading
@@ -15,7 +15,6 @@ import java.util.Collection;
 
/**
* Shows the files
* Created by Jawnnypoo on 11/22/2015.
*/
public class FilesAdapter extends RecyclerView.Adapter<FileViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -13,7 +13,6 @@ import java.util.Collection;
 
/**
* All the groups
* Created by John on 10/8/15.
*/
public class GroupAdapter extends RecyclerView.Adapter<GroupViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -15,7 +15,6 @@ import java.util.Collection;
 
/**
* Adapter for a list of users
* Created by John on 9/28/15.
*/
public class GroupMembersAdapter extends RecyclerView.Adapter<ProjectMemberViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -16,7 +16,6 @@ import java.util.Set;
 
/**
* Group pager adapter
* Created by Jawn on 9/21/2015.
*/
public class GroupPagerAdapter extends FragmentPagerAdapter {
 
Loading
Loading
Loading
Loading
@@ -18,7 +18,6 @@ import in.uncod.android.bypass.Bypass;
 
/**
* Nice notes
* Created by Jawn on 8/6/2015.
*/
public class IssueDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -14,7 +14,6 @@ import java.util.Collection;
 
/**
* Issues adapter
* Created by Jawn on 7/28/2015.
*/
public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -18,7 +18,6 @@ import java.util.Collection;
 
/**
* Shows a projects members and a groups members
* Created by Jawn on 7/28/2015.
*/
public class MemberAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -15,7 +15,6 @@ import java.util.List;
 
/**
* Merge request adapter!
* Created by Jawn on 9/20/2015.
*/
public class MergeRequestAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
 
Loading
Loading
Loading
Loading
@@ -17,7 +17,6 @@ import in.uncod.android.bypass.Bypass;
 
/**
* Shows the comments and details of a merge request
* Created by John on 11/16/15.
*/
public class MergeRequestDetailAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -11,7 +11,6 @@ import com.commit451.gitlab.fragment.UsersFragment;
 
/**
* The pager that controls the fragments when on the search activity
* Created by Jawn on 9/21/2015.
*/
public class SearchPagerAdapter extends FragmentPagerAdapter {
 
Loading
Loading
Loading
Loading
@@ -6,6 +6,7 @@ import android.support.v4.app.FragmentPagerAdapter;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.activity.ProjectActivity;
import com.commit451.gitlab.fragment.BuildsFragment;
import com.commit451.gitlab.fragment.CommitsFragment;
import com.commit451.gitlab.fragment.FeedFragment;
import com.commit451.gitlab.fragment.FilesFragment;
Loading
Loading
@@ -13,27 +14,29 @@ import com.commit451.gitlab.fragment.IssuesFragment;
import com.commit451.gitlab.fragment.MilestonesFragment;
import com.commit451.gitlab.fragment.ProjectMembersFragment;
import com.commit451.gitlab.fragment.MergeRequestsFragment;
import com.commit451.gitlab.fragment.OverviewFragment;
import com.commit451.gitlab.fragment.ProjectFragment;
import com.commit451.gitlab.model.api.Project;
 
import java.util.HashSet;
import java.util.Set;
 
import timber.log.Timber;
/**
* Controls the sections that should be shown in a {@link com.commit451.gitlab.activity.ProjectActivity}
* Created by Jawn on 9/20/2015.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
 
private static final int SECTION_COUNT = 8;
private static final int OVERVIEW_POS = 0;
private static final int SECTION_COUNT = 9;
private static final int PROJECT_POS = 0;
private static final int ACTIVITY_POS = 1;
private static final int FILES_POS = 2;
private static final int COMMITS_POS = 3;
private static final int MILESTONES_POS = 4;
private static final int ISSUES_POS = 5;
private static final int MERGE_REQUESTS_POS = 6;
private static final int PROJECT_MEMBERS_POS = 7;
private static final int BUILDS_POS = 4;
private static final int MILESTONES_POS = 5;
private static final int ISSUES_POS = 6;
private static final int MERGE_REQUESTS_POS = 7;
private static final int PROJECT_MEMBERS_POS = 8;
 
private final Project mProject;
private final String[] mTitles;
Loading
Loading
@@ -46,13 +49,20 @@ public class SectionsPagerAdapter extends FragmentPagerAdapter {
mTitles = context.getResources().getStringArray(R.array.main_tabs);
 
Project project = context.getProject();
if (!project.isBuildEnabled()) {
Timber.d("Builds are disabled");
mDisabledSections.add(BUILDS_POS);
}
if (!project.isIssuesEnabled()) {
Timber.d("Issues are disabled");
mDisabledSections.add(ISSUES_POS);
}
if (!project.isMergeRequestsEnabled()) {
Timber.d("Merge requests are disabled");
mDisabledSections.add(MERGE_REQUESTS_POS);
}
if (!project.isIssuesEnabled() && !project.isMergeRequestsEnabled()) {
Timber.d("Milestones are disabled");
mDisabledSections.add(MILESTONES_POS);
}
}
Loading
Loading
@@ -74,14 +84,16 @@ public class SectionsPagerAdapter extends FragmentPagerAdapter {
position = getCorrectPosition(position);
 
switch (position) {
case OVERVIEW_POS:
return OverviewFragment.newInstance();
case PROJECT_POS:
return ProjectFragment.newInstance();
case ACTIVITY_POS:
return FeedFragment.newInstance(mProject.getFeedUrl());
case FILES_POS:
return FilesFragment.newInstance();
case COMMITS_POS:
return CommitsFragment.newInstance();
case BUILDS_POS:
return BuildsFragment.newInstance();
case MILESTONES_POS:
return MilestonesFragment.newInstance();
case ISSUES_POS:
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
Loading
Loading
@@ -15,7 +15,6 @@ import java.util.Collection;
 
/**
* Adapter for a list of users
* Created by John on 9/28/15.
*/
public class UsersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
Loading
Loading
Loading
Loading
@@ -12,7 +12,6 @@ import timber.log.Timber;
 
/**
* Adds the private token to all requests
* Created by Jawn on 9/15/2015.
*/
public class AuthenticationRequestInterceptor implements Interceptor {
 
Loading
Loading
Loading
Loading
@@ -2,9 +2,12 @@ package com.commit451.gitlab.api;
 
import android.support.annotation.Nullable;
 
import com.commit451.gitlab.model.api.Artifact;
import com.commit451.gitlab.model.api.Branch;
import com.commit451.gitlab.model.api.Build;
import com.commit451.gitlab.model.api.Contributor;
import com.commit451.gitlab.model.api.Diff;
import com.commit451.gitlab.model.api.FileUploadResponse;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.model.api.GroupDetail;
import com.commit451.gitlab.model.api.Issue;
Loading
Loading
@@ -24,7 +27,9 @@ import com.commit451.gitlab.model.api.UserLogin;
 
import java.util.List;
 
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
Loading
Loading
@@ -123,7 +128,12 @@ public interface GitLab {
Call<List<Project>> getStarredProjects();
 
@GET(API_VERSION + "/projects/{id}")
Call<Project> getProject(@Path("id") long projectId);
Call<Project> getProject(@Path("id") String projectId);
// see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md#get-single-project
@GET(API_VERSION + "/projects/{namespace}%2F{project_name}")
Call<Project> getProject(@Path("namespace") String namespace,
@Path("project_name") String projectName);
 
@GET
Call<List<Project>> getProjects(@Url String url);
Loading
Loading
@@ -153,6 +163,20 @@ public interface GitLab {
Call<Void> removeProjectMember(@Path("id") long projectId,
@Path("user_id") long userId);
 
@POST(API_VERSION + "/projects/fork/{id}")
Call<Void> forkProject(@Path("id") long projectId);
@POST(API_VERSION + "/projects/{id}/star")
Call<Project> starProject(@Path("id") long projectId);
@DELETE(API_VERSION + "/projects/{id}/star")
Call<Project> unstarProject(@Path("id") long projectId);
//@Multipart
@POST(API_VERSION + "/projects/{id}/uploads")
Call<FileUploadResponse> uploadFile(@Path("id") long projectId,
@Body RequestBody file);
/* --- MILESTONES --- */
 
@GET(API_VERSION + "/projects/{id}/milestones")
Loading
Loading
@@ -163,29 +187,30 @@ public interface GitLab {
 
@GET(API_VERSION + "/projects/{id}/milestones/{milestone_id}/issues")
Call<List<Issue>> getMilestoneIssues(@Path("id") long projectId,
@Path("milestone_id") long milestoneId);
@Path("milestone_id") long milestoneId);
@GET
Call<List<Issue>> getMilestoneIssues(@Url String url);
 
@FormUrlEncoded
@POST(API_VERSION + "/projects/{id}/milestones")
Call<Milestone> createMilestone(@Path("id") long projectId,
@Field("title") String title,
@Field("description") String description,
@Field("due_date") String dueDate);
@Field("title") String title,
@Field("description") String description,
@Field("due_date") String dueDate);
 
@FormUrlEncoded
@PUT(API_VERSION + "/projects/{id}/milestones/{milestone_id}")
Call<Milestone> editMilestone(@Path("id") long projectId,
@Path("milestone_id") long milestoneId,
@Field("title") String title,
@Field("description") String description,
@Field("due_date") String dueDate);
@Path("milestone_id") long milestoneId,
@Field("title") String title,
@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);
@Path("milestone_id") long milestoneId,
@Query("state_event") @Milestone.StateEvent String status);
 
/* --- MERGE REQUESTS --- */
 
Loading
Loading
@@ -207,11 +232,11 @@ public interface GitLab {
 
@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);
@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);
@Path("merge_request_id") long mergeRequestId);
 
@GET
Call<List<Note>> getMergeRequestNotes(@Url String url);
Loading
Loading
@@ -222,6 +247,10 @@ public interface GitLab {
@Path("merge_request_id") long mergeRequestId,
@Field("body") String body);
 
@PUT(API_VERSION + "/projects/{id}/merge_requests/{merge_request_id}")
Call<MergeRequest> acceptMergeRequest(@Path("id") long projectId,
@Path("merge_request_id") long mergeRequestId);
/* --- ISSUES --- */
 
@GET(API_VERSION + "/projects/{id}/issues")
Loading
Loading
@@ -234,14 +263,18 @@ public interface GitLab {
 
@GET(API_VERSION + "/projects/{id}/issues/{issue_id}")
Call<Issue> getIssue(@Path("id") long projectId,
@Path("issue_id") long issueId);
@Path("issue_id") String issueId);
@GET(API_VERSION + "/projects/{id}/issues")
Call<List<Issue>> getIssuesByIid(@Path("id") long projectId,
@Query("iid") String internalIssueId);
 
@FormUrlEncoded
@POST(API_VERSION + "/projects/{id}/issues")
Call<Issue> createIssue(@Path("id") long projectId,
@Field("title") String title,
@Field("description") String description,
@Field("assignee_id") @Nullable Long assigneeId,
@Field("assignee_id") @Nullable Long assigneeId,
@Field("milestone_id") @Nullable Long milestoneId);
 
@PUT(API_VERSION + "/projects/{id}/issues/{issue_id}")
Loading
Loading
@@ -276,7 +309,7 @@ public interface GitLab {
Call<List<Branch>> getBranches(@Path("id") long projectId);
 
@GET(API_VERSION + "/projects/{id}/repository/contributors")
Call<List<Contributor>> getContributors(@Path("id") long projectId);
Call<List<Contributor>> getContributors(@Path("id") String projectId);
 
@GET(API_VERSION + "/projects/{id}/repository/tree")
Call<List<RepositoryTreeObject>> getTree(@Path("id") long projectId,
Loading
Loading
@@ -300,8 +333,10 @@ 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
*/
Loading
Loading
@@ -310,9 +345,10 @@ public interface GitLab {
 
/**
* Create a new label
*
* @param projectId id
* @param name the name of the label
* @param color the color, ex. #ff0000
* @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")
Loading
Loading
@@ -322,11 +358,41 @@ public interface GitLab {
 
/**
* 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);
@Query("name") String name);
/* --- BUILDS --- */
@GET(API_VERSION + "/projects/{id}/builds")
Call<List<Build>> getBuilds(@Path("id") long projectId,
@Query("scope") String scope);
@GET
Call<List<Build>> getBuilds(@Url String url,
@Query("scope") String state);
@GET(API_VERSION + "/projects/{id}/builds/{build_id}")
Call<Build> getBuild(@Path("id") long projectId,
@Path("build_id") long buildId);
@POST(API_VERSION + "/projects/{id}/builds/{build_id}/retry")
Call<Build> retryBuild(@Path("id") long projectId,
@Path("build_id") long buildId);
@POST(API_VERSION + "/projects/{id}/builds/{build_id}/erase")
Call<Build> eraseBuild(@Path("id") long projectId,
@Path("build_id") long buildId);
@POST(API_VERSION + "/projects/{id}/builds/{build_id}/cancel")
Call<Build> cancelBuild(@Path("id") long projectId,
@Path("build_id") long buildId);
 
@GET(API_VERSION + "/projects/{id}/builds/{build_id}/artifacts")
Call<List<Artifact>> getBuildArtifacts(@Path("id") long projectId,
@Path("build_id") long buildId);
}
\ No newline at end of file
package com.commit451.gitlab.api;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import timber.log.Timber;
/**
* Intercepts requests and logs them using Timber
* Created by John on 9/11/15.
*/
public class TimberRequestInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Timber.i("Sending request %s%n%s",
request.url(), request.headers());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Timber.i("Received response for %s in %.1fms%n%s%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers(), response.body());
return response;
}
}
\ No newline at end of file
package com.commit451.gitlab.customtabs;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.support.design.widget.Snackbar;
import com.commit451.gitlab.R;
/**
* A fallback to open the url in the browser
*/
public class BrowserFallback implements CustomTabsActivityHelper.CustomTabFallback {
@Override
public void openUri(Activity activity, Uri uri) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(uri);
try {
activity.startActivity(i);
} catch (ActivityNotFoundException e) {
Snackbar.make(activity.getWindow().getDecorView(), R.string.error_no_browser, Snackbar.LENGTH_SHORT)
.show();
}
}
}
package com.commit451.gitlab.customtabs;
import android.app.Activity;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Bundle;
import android.support.customtabs.CustomTabsClient;
import android.support.customtabs.CustomTabsIntent;
import android.support.customtabs.CustomTabsServiceConnection;
import android.support.customtabs.CustomTabsSession;
import java.util.List;
public class CustomTabsActivityHelper {
private CustomTabsSession mCustomTabsSession;
private CustomTabsClient mClient;
private CustomTabsServiceConnection mConnection;
private ConnectionCallback mConnectionCallback;
/**
* Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView
*
* @param activity The host activity
* @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available
* @param uri the Uri to be opened
* @param fallback a CustomTabFallback to be used if Custom Tabs is not available
*/
public static void openCustomTab(Activity activity,
CustomTabsIntent customTabsIntent,
Uri uri,
CustomTabFallback fallback) {
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
//If we cant find a package name, it means theres no browser that supports
//Chrome Custom Tabs installed. So, we fallback to the webview
if (packageName == null) {
if (fallback != null) {
fallback.openUri(activity, uri);
}
} else {
customTabsIntent.intent.setPackage(packageName);
customTabsIntent.launchUrl(activity, uri);
}
}
/**
* Unbinds the Activity from the Custom Tabs Service
* @param activity the activity that is connected to the service
*/
public void unbindCustomTabsService(Activity activity) {
if (mConnection == null) return;
activity.unbindService(mConnection);
mClient = null;
mCustomTabsSession = null;
}
/**
* Creates or retrieves an exiting CustomTabsSession
*
* @return a CustomTabsSession
*/
public CustomTabsSession getSession() {
if (mClient == null) {
mCustomTabsSession = null;
} else if (mCustomTabsSession == null) {
mCustomTabsSession = mClient.newSession(null);
}
return mCustomTabsSession;
}
/**
* Register a Callback to be called when connected or disconnected from the Custom Tabs Service
* @param connectionCallback
*/
public void setConnectionCallback(ConnectionCallback connectionCallback) {
this.mConnectionCallback = connectionCallback;
}
/**
* Binds the Activity to the Custom Tabs Service
* @param activity the activity to be binded to the service
*/
public void bindCustomTabsService(Activity activity) {
if (mClient != null) return;
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
if (packageName == null) return;
mConnection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
mClient = client;
mClient.warmup(0L);
if (mConnectionCallback != null) mConnectionCallback.onCustomTabsConnected();
//Initialize a session as soon as possible.
getSession();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mClient = null;
if (mConnectionCallback != null) mConnectionCallback.onCustomTabsDisconnected();
}
};
CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
}
public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) {
if (mClient == null) return false;
CustomTabsSession session = getSession();
if (session == null) return false;
return session.mayLaunchUrl(uri, extras, otherLikelyBundles);
}
/**
* A Callback for when the service is connected or disconnected. Use those callbacks to
* handle UI changes when the service is connected or disconnected
*/
public interface ConnectionCallback {
/**
* Called when the service is connected
*/
void onCustomTabsConnected();
/**
* Called when the service is disconnected
*/
void onCustomTabsDisconnected();
}
/**
* To be used as a fallback to open the Uri when Custom Tabs is not available
*/
public interface CustomTabFallback {
/**
*
* @param activity The Activity that wants to open the Uri
* @param uri The uri to be opened by the fallback
*/
void openUri(Activity activity, Uri uri);
}
}
\ No newline at end of file
package com.commit451.gitlab.customtabs;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.support.customtabs.CustomTabsService;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class for Custom Tabs.
*/
public class CustomTabsHelper {
private static final String TAG = "CustomTabsHelper";
static final String STABLE_PACKAGE = "com.android.chrome";
static final String BETA_PACKAGE = "com.chrome.beta";
static final String DEV_PACKAGE = "com.chrome.dev";
static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
"android.support.customtabs.extra.KEEP_ALIVE";
private static String sPackageNameToUse;
private CustomTabsHelper() {}
public static void addKeepAliveExtra(Context context, Intent intent) {
Intent keepAliveIntent = new Intent().setClassName(
context.getPackageName(), KeepAliveService.class.getCanonicalName());
intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent);
}
/**
* Goes through all apps that handle VIEW intents and have a warmup service. Picks
* the one chosen by the user if there is one, otherwise makes a best effort to return a
* valid package name.
*
* This is <strong>not</strong> threadsafe.
*
* @param context {@link Context} to use for accessing {@link PackageManager}.
* @return The package name recommended to use for connecting to custom tabs related components.
*/
public static String getPackageNameToUse(Context context) {
if (sPackageNameToUse != null) return sPackageNameToUse;
PackageManager pm = context.getPackageManager();
// Get default VIEW intent handler.
Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
String defaultViewHandlerPackageName = null;
if (defaultViewHandlerInfo != null) {
defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
}
// Get all apps that can handle VIEW intents.
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
List<String> packagesSupportingCustomTabs = new ArrayList<>();
for (ResolveInfo info : resolvedActivityList) {
Intent serviceIntent = new Intent();
serviceIntent.setAction(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
serviceIntent.setPackage(info.activityInfo.packageName);
if (pm.resolveService(serviceIntent, 0) != null) {
packagesSupportingCustomTabs.add(info.activityInfo.packageName);
}
}
// Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
// and service calls.
if (packagesSupportingCustomTabs.isEmpty()) {
sPackageNameToUse = null;
} else if (packagesSupportingCustomTabs.size() == 1) {
sPackageNameToUse = packagesSupportingCustomTabs.get(0);
} else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
&& !hasSpecializedHandlerIntents(context, activityIntent)
&& packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
sPackageNameToUse = defaultViewHandlerPackageName;
} else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
sPackageNameToUse = STABLE_PACKAGE;
} else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
sPackageNameToUse = BETA_PACKAGE;
} else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
sPackageNameToUse = DEV_PACKAGE;
} else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
sPackageNameToUse = LOCAL_PACKAGE;
}
return sPackageNameToUse;
}
/**
* Used to check whether there is a specialized handler for a given intent.
* @param intent The intent to check with.
* @return Whether there is a specialized handler for the given intent.
*/
private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) {
try {
PackageManager pm = context.getPackageManager();
List<ResolveInfo> handlers = pm.queryIntentActivities(
intent,
PackageManager.GET_RESOLVED_FILTER);
if (handlers == null || handlers.size() == 0) {
return false;
}
for (ResolveInfo resolveInfo : handlers) {
IntentFilter filter = resolveInfo.filter;
if (filter == null) continue;
if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue;
if (resolveInfo.activityInfo == null) continue;
return true;
}
} catch (RuntimeException e) {
Log.e(TAG, "Runtime exception while getting specialized handlers");
}
return false;
}
/**
* @return All possible chrome package names that provide custom tabs feature.
*/
public static String[] getPackages() {
return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE};
}
}
\ No newline at end of file
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