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

Merge branch 'master' into fdroid

parents cc5fea52 1dd2e31b
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 766 additions and 500 deletions
Loading
Loading
@@ -3,10 +3,12 @@ before_script:
- export TERM=dumb
- export _JAVA_OPTIONS="-Djava.awt.headless=true"
- apt-get -q -y update
- apt-get -q -y install wget tar openjdk-7-jdk lib32stdc++6 lib32z1
- apt-get -q -y install wget tar expect openjdk-7-jdk lib32stdc++6 lib32z1
- wget -q http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz
- tar xzf android-sdk_r24.4.1-linux.tgz
- echo y | android-sdk-linux/tools/android -s update sdk --no-ui --all --filter tools,platform-tools,build-tools-23.0.2,android-23,extra-android-m2repository
- wget -q https://raw.githubusercontent.com/journeyapps/android-sdk-installer/master/accept-licenses
- chmod +x accept-licenses
- ./accept-licenses "android-sdk-linux/tools/android -s update sdk --no-ui --all --filter tools,platform-tools,build-tools-23.0.2,android-23,extra-android-m2repository" "android-sdk-license-5be876d5|android-sdk-license-ed0d0a5b"
- export ANDROID_HOME=$PWD/android-sdk-linux
- chmod +x gradlew
 
Loading
Loading
Loading
Loading
@@ -6,7 +6,9 @@ before_script:
- sudo apt-get -q -y install wget tar openjdk-7-jdk lib32stdc++6 lib32z1
- wget -q http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz
- tar xzf android-sdk_r24.4.1-linux.tgz
- echo y | android-sdk-linux/tools/android -s update sdk --no-ui --all --filter tools,platform-tools,build-tools-23.0.2,android-23,extra-android-m2repository
- wget -q https://raw.githubusercontent.com/journeyapps/android-sdk-installer/master/accept-licenses
- chmod +x accept-licenses
- ./accept-licenses "android-sdk-linux/tools/android -s update sdk --no-ui --all --filter tools,platform-tools,build-tools-23.0.2,android-23,extra-android-m2repository" "android-sdk-license-5be876d5|android-sdk-license-ed0d0a5b"
- export ANDROID_HOME=$PWD/android-sdk-linux
- chmod +x gradlew
 
Loading
Loading
Loading
Loading
@@ -36,6 +36,7 @@ The following 3rd party libraries and resources are the reason this app works. R
- RobotoTextView (https://github.com/johnkil/Android-RobotoTextView)
- GitDiffTextView (https://github.com/alorma/GitDiffTextView)
- MaterialDateTimePicker (https://github.com/wdullaer/MaterialDateTimePicker)
- highlight.js (https://highlightjs.org/)
 
## Contributing
Please fork this repository and contribute back! All Merge Requests should be made against the `develop` branch, as it is the active branch for development. Please make your best effort to break up commits as much as possible to improve the reviewing process.
Loading
Loading
Loading
Loading
@@ -10,12 +10,12 @@ android {
minSdkVersion 16
targetSdkVersion 23
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode 224
versionName "2.2.4"
versionCode 225
versionName "2.2.5"
}
buildTypes {
release {
minifyEnabled true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
Loading
Loading
@@ -32,37 +32,53 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:palette-v7:23.1.1'
compile 'com.android.support:customtabs:23.1.1'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile ('com.squareup.retrofit:converter-simplexml:2.0.0-beta2') {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
compile 'com.android.support:appcompat-v7:23.2.1'
compile 'com.android.support:design:23.2.1'
compile 'com.android.support:recyclerview-v7:23.2.1'
compile 'com.android.support:cardview-v7:23.2.1'
compile 'com.android.support:palette-v7:23.2.1'
compile 'com.android.support:customtabs:23.2.1'
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile('com.squareup.retrofit2:converter-simplexml:2.0.0') {
exclude group: 'xpp3', module: 'xpp3'
exclude group: 'stax', module: 'stax-api'
exclude group: 'stax', module: 'stax'
}
compile 'com.squareup.okhttp:okhttp:2.7.2'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.0.2'
compile 'com.squareup:otto:1.3.8'
compile 'io.reactivex:rxjava:1.1.2'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.jakewharton.timber:timber:4.1.0'
compile 'com.google.code.gson:gson:2.5'
compile 'net.danlew:android.joda:2.9.1'
compile "org.parceler:parceler-api:1.0.3"
apt "org.parceler:parceler:1.0.3"
compile 'com.jakewharton.timber:timber:4.1.1'
compile 'com.google.code.gson:gson:2.6.2'
compile 'net.danlew:android.joda:2.9.2'
compile "org.parceler:parceler-api:1.0.4"
apt "org.parceler:parceler:1.0.4"
compile 'com.commit451:bypasses:1.0.1'
compile 'com.commit451:easel:0.0.4'
compile 'com.commit451:easel:0.0.5'
compile 'com.commit451:foregroundviews:1.0.0'
compile 'com.commit451:elasticdragdismisslayout:1.0.2'
compile 'com.commit451:adapterlayout:1.0.1'
compile 'com.pnikosis:materialish-progress:1.7'
compile 'com.jawnnypoo:physicslayout:1.0.1'
compile 'com.github.ivbaranov:MaterialLetterIcon:0.2.1'
compile 'com.github.johnkil.android-robototextview:robototextview:2.4.3'
compile 'com.github.alorma:diff-textview:1.1.0'
compile 'com.wdullaer:materialdatetimepicker:2.1.1'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
compile 'com.github.ivbaranov:materiallettericon:0.2.1'
compile 'com.github.johnkil.android-robototextview:robototextview:2.5.0'
compile 'com.github.alorma:diff-textview:1.3.0'
compile 'com.wdullaer:materialdatetimepicker:2.3.0'
compile "com.wefika:flowlayout:0.4.1"
compile('com.github.afollestad:app-theme-engine:1.0.1@aar') {
transitive = true
}
compile('com.github.afollestad.material-dialogs:core:0.8.5.7@aar') {
transitive = true
}
compile('com.github.afollestad.material-dialogs:commons:0.8.5.7@aar') {
transitive = true
}
}
Loading
Loading
@@ -23,22 +23,25 @@
 
# So that Fabric can still have line numbers
-keepattributes SourceFile,LineNumberTable
-keep class com.commit451.gitlab.ssl.CustomSSLSocketFactory
 
# Picasso rules
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
 
# Retrofit rules
-keep class com.squareup.okhttp.** { *; }
-keep class retrofit.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-keep class okhttp3.** { *; }
-keep class retrofit2.** { *; }
-keep interface okhttp3.** { *; }
 
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn retrofit.**
-dontwarn retrofit2.**
-dontwarn rx.**
 
-keepclasseswithmembers class * {
@retrofit.http.* <methods>;
@retrofit2.http.* <methods>;
}
 
# If in your rest service interface you use methods with Callback argument.
Loading
Loading
Loading
Loading
@@ -30,11 +30,9 @@
<activity android:name=".activity.LoginActivity" />
 
<activity android:name=".activity.ProjectsActivity"
android:theme="@style/Activity.Projects"
android:launchMode="singleTask"/>
 
<activity android:name=".activity.GroupsActivity"
android:theme="@style/Activity.Groups"
android:launchMode="singleTask"/>
 
<activity
Loading
Loading
@@ -49,15 +47,14 @@
 
<activity android:name=".activity.AboutActivity"/>
<activity android:name=".activity.AddUserActivity"/>
<activity android:name=".activity.UserActivity"
android:theme="@style/Activity.User"/>
<activity android:name=".activity.UserActivity"/>
<activity android:name=".activity.SearchActivity"/>
<activity android:name=".activity.GroupActivity"
android:theme="@style/Activity.Group"/>
<activity android:name=".activity.GroupActivity"/>
<activity android:name=".activity.MergeRequestActivity"/>
<activity android:name=".activity.AddIssueActivity"/>
<activity android:name=".activity.MilestoneActivity"/>
<activity android:name=".activity.AddMilestoneActivity"/>
<activity android:name=".activity.SettingsActivity"/>
</application>
 
</manifest>
\ No newline at end of file
Loading
Loading
@@ -4,124 +4,96 @@ github.com style (c) Vasily Polovnyov <vast@whiteants.net>
 
*/
 
pre code {
display: block; padding: 0.5em;
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #FFFFFF
background: #f8f8f8;
}
 
pre .comment,
pre .template_comment,
pre .diff .header,
pre .javadoc {
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic
font-style: italic;
}
 
pre .keyword,
pre .css .rule .keyword,
pre .winutils,
pre .javascript .title,
pre .nginx .title,
pre .subst,
pre .request,
pre .status {
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold
font-weight: bold;
}
 
pre .number,
pre .hexcolor,
pre .ruby .constant {
color: #099;
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
 
pre .string,
pre .tag .value,
pre .phpdoc,
pre .tex .formula {
color: #d14
.hljs-string,
.hljs-doctag {
color: #d14;
}
 
pre .title,
pre .id {
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold
font-weight: bold;
}
 
pre .javascript .title,
pre .lisp .title,
pre .clojure .title,
pre .subst {
font-weight: normal
.hljs-subst {
font-weight: normal;
}
 
pre .class .title,
pre .haskell .type,
pre .vhdl .literal,
pre .tex .command {
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold
font-weight: bold;
}
 
pre .tag,
pre .tag .title,
pre .rules .property,
pre .django .tag .keyword {
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal
font-weight: normal;
}
 
pre .attribute,
pre .variable,
pre .lisp .body {
color: #008080
.hljs-regexp,
.hljs-link {
color: #009926;
}
 
pre .regexp {
color: #009926
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
 
pre .class {
color: #458;
font-weight: bold
}
pre .symbol,
pre .ruby .symbol .string,
pre .lisp .keyword,
pre .tex .special,
pre .prompt {
color: #990073
}
pre .built_in,
pre .lisp .title,
pre .clojure .built_in {
color: #0086b3
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
 
pre .preprocessor,
pre .pi,
pre .doctype,
pre .shebang,
pre .cdata {
.hljs-meta {
color: #999;
font-weight: bold
font-weight: bold;
}
 
pre .deletion {
background: #fdd
.hljs-deletion {
background: #fdd;
}
 
pre .addition {
background: #dfd
.hljs-addition {
background: #dfd;
}
 
pre .diff .change {
background: #0086b3
.hljs-emphasis {
font-style: italic;
}
 
pre .chunk {
color: #aaa
.hljs-strong {
font-weight: bold;
}
Source diff could not be displayed: it is too large. Options to address this: view the blob.
Loading
Loading
@@ -8,14 +8,17 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.api.Contributor;
import com.commit451.gitlab.transformation.CircleTransformation;
Loading
Loading
@@ -34,9 +37,7 @@ import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import timber.log.Timber;
 
/**
Loading
Loading
@@ -51,11 +52,15 @@ public class AboutActivity extends BaseActivity {
return intent;
}
 
@Bind(R.id.root) View root;
@Bind(R.id.toolbar) Toolbar toolbar;
@Bind(R.id.toolbar_title) TextView toolbarTitle;
@Bind(R.id.contributors) TextView contributors;
@Bind(R.id.physics_layout) PhysicsFrameLayout physicsLayout;
@Bind(R.id.root)
ViewGroup mRoot;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.contributors)
TextView mContributors;
@Bind(R.id.physics_layout)
PhysicsFrameLayout mPhysicsLayout;
@OnClick(R.id.sauce)
void onSauceClick() {
if ("https://gitlab.com".equals(GitLabClient.getAccount().getServerUrl().toString())) {
Loading
Loading
@@ -72,30 +77,28 @@ public class AboutActivity extends BaseActivity {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {
if (physicsLayout.getPhysics().getWorld() != null) {
if (mPhysicsLayout.getPhysics().getWorld() != null) {
WindowUtil.normalizeForOrientation(getWindow(), event);
physicsLayout.getPhysics().getWorld().setGravity(new Vec2(-event.values[0], event.values[1]));
mPhysicsLayout.getPhysics().getWorld().setGravity(new Vec2(-event.values[0], event.values[1]));
}
}
}
 
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
 
private Callback<List<Contributor>> mContributorResponseCallback = new Callback<List<Contributor>>() {
private Callback<List<Contributor>> mContributorResponseCallback = new EasyCallback<List<Contributor>>() {
@Override
public void onResponse(Response<List<Contributor>> response, Retrofit retrofit) {
if (!response.isSuccess()) {
return;
}
addContributors(Contributor.groupContributors(response.body()));
public void onResponse(@NonNull List<Contributor> response) {
addContributors(Contributor.groupContributors(response));
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
Snackbar.make(getWindow().getDecorView(), R.string.failed_to_load_contributors, Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, R.string.failed_to_load_contributors, Snackbar.LENGTH_SHORT)
.show();
}
};
Loading
Loading
@@ -106,15 +109,15 @@ public class AboutActivity extends BaseActivity {
WindowUtil.lockToCurrentOrientation(this);
setContentView(R.layout.activity_about);
ButterKnife.bind(this);
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
toolbarTitle.setText(R.string.about);
physicsLayout.getPhysics().enableFling();
mToolbar.setTitle(R.string.about);
mPhysicsLayout.getPhysics().enableFling();
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
GitLabClient.instance().getContributors(REPO_ID).enqueue(mContributorResponseCallback);
Loading
Loading
@@ -139,11 +142,10 @@ public class AboutActivity extends BaseActivity {
.setFriction(0.0f)
.setRestitution(0.0f)
.build();
int borderSize = getResources().getDimensionPixelSize(R.dimen.border_size);
int x = 0;
int y = 0;
int imageSize = getResources().getDimensionPixelSize(R.dimen.circle_size);
for (int i=0; i<contributors.size(); i++) {
for (int i = 0; i < contributors.size(); i++) {
Contributor contributor = contributors.get(i);
ImageView imageView = new ImageView(this);
FrameLayout.LayoutParams llp = new FrameLayout.LayoutParams(
Loading
Loading
@@ -151,14 +153,14 @@ public class AboutActivity extends BaseActivity {
imageSize);
imageView.setLayoutParams(llp);
Physics.setPhysicsConfig(imageView, config);
physicsLayout.addView(imageView);
mPhysicsLayout.addView(imageView);
imageView.setX(x);
imageView.setY(y);
 
x = (x + imageSize);
if (x > physicsLayout.getWidth()) {
if (x > mPhysicsLayout.getWidth()) {
x = 0;
y = (y + imageSize) % physicsLayout.getHeight();
y = (y + imageSize) % mPhysicsLayout.getHeight();
}
 
Uri url = ImageUtil.getAvatarUrl(contributor.getEmail(), imageSize);
Loading
Loading
@@ -167,6 +169,6 @@ public class AboutActivity extends BaseActivity {
.transform(new CircleTransformation())
.into(imageView);
}
physicsLayout.getPhysics().onLayout(true);
mPhysicsLayout.getPhysics().onLayout(true);
}
}
Loading
Loading
@@ -3,20 +3,25 @@ package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.Spinner;
 
import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer;
import com.commit451.elasticdragdismisslayout.ElasticDragDismissFrameLayout;
import com.commit451.elasticdragdismisslayout.ElasticDragDismissListener;
import com.commit451.gitlab.LabCoatApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.AssigneeSpinnerAdapter;
import com.commit451.gitlab.adapter.MilestoneSpinnerAdapter;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.event.IssueChangedEvent;
import com.commit451.gitlab.event.IssueCreatedEvent;
Loading
Loading
@@ -33,15 +38,19 @@ 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;
 
/**
* Activity to input new issues, but not really a dialog at all wink wink
*/
public class AddIssueActivity extends MorphActivity {
public class AddIssueActivity extends MorphActivity implements ATEActivityThemeCustomizer {
@Override
public int getActivityTheme() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
R.style.Activity_Translucent : R.style.ActivityLight_Translucent;
}
 
private static final String KEY_PROJECT = "project";
private static final String KEY_ISSUE = "issue";
Loading
Loading
@@ -55,31 +64,37 @@ public class AddIssueActivity extends MorphActivity {
return intent;
}
 
@Bind(R.id.root) ViewGroup mRoot;
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.title_text_input_layout) TextInputLayout mTitleInputLayout;
@Bind(R.id.title) EditText mTitleInput;
@Bind(R.id.description) EditText mDescriptionInput;
@Bind(R.id.progress) View mProgress;
@Bind(R.id.assignee_progress) View mAssigneeProgress;
@Bind(R.id.assignee_spinner) Spinner mAssigneeSpinner;
@Bind(R.id.milestone_progress) View mMilestoneProgress;
@Bind(R.id.milestone_spinner) Spinner mMilestoneSpinner;
@Bind(R.id.root)
ElasticDragDismissFrameLayout mRoot;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.title_text_input_layout)
TextInputLayout mTitleInputLayout;
@Bind(R.id.title)
EditText mTitleInput;
@Bind(R.id.description)
EditText mDescriptionInput;
@Bind(R.id.progress)
View mProgress;
@Bind(R.id.assignee_progress)
View mAssigneeProgress;
@Bind(R.id.assignee_spinner)
Spinner mAssigneeSpinner;
@Bind(R.id.milestone_progress)
View mMilestoneProgress;
@Bind(R.id.milestone_spinner)
Spinner mMilestoneSpinner;
 
private Project mProject;
private Issue mIssue;
private HashSet<Member> mMembers;
 
private final Callback<List<Milestone>> mMilestonesCallback = new Callback<List<Milestone>>() {
private final Callback<List<Milestone>> mMilestonesCallback = new EasyCallback<List<Milestone>>() {
@Override
public void onResponse(Response<List<Milestone>> response, Retrofit retrofit) {
public void onResponse(@NonNull List<Milestone> response) {
mMilestoneProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
mMilestoneSpinner.setVisibility(View.GONE);
return;
}
mMilestoneSpinner.setVisibility(View.VISIBLE);
MilestoneSpinnerAdapter milestoneSpinnerAdapter = new MilestoneSpinnerAdapter(AddIssueActivity.this, response.body());
MilestoneSpinnerAdapter milestoneSpinnerAdapter = new MilestoneSpinnerAdapter(AddIssueActivity.this, response);
mMilestoneSpinner.setAdapter(milestoneSpinnerAdapter);
if (mIssue != null) {
mMilestoneSpinner.setSelection(milestoneSpinnerAdapter.getSelectedItemPosition(mIssue.getMilestone()));
Loading
Loading
@@ -87,24 +102,17 @@ public class AddIssueActivity extends MorphActivity {
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mMilestoneProgress.setVisibility(View.GONE);
mMilestoneSpinner.setVisibility(View.GONE);
}
};
 
private final Callback<List<Member>> mAssigneeCallback = new Callback<List<Member>>() {
private final Callback<List<Member>> mAssigneeCallback = new EasyCallback<List<Member>>() {
@Override
public void onResponse(Response<List<Member>> response, Retrofit retrofit) {
if (!response.isSuccess()) {
mAssigneeProgress.setVisibility(View.GONE);
mAssigneeSpinner.setVisibility(View.GONE);
return;
}
if (response.body() != null) {
mMembers.addAll(response.body());
}
public void onResponse(@NonNull List<Member> response) {
mMembers.addAll(response);
if (mProject.belongsToGroup()) {
Timber.d("Project belongs to a group, loading those users too");
GitLabClient.instance().getGroupMembers(mProject.getNamespace().getId()).enqueue(mGroupMembersCallback);
Loading
Loading
@@ -114,55 +122,44 @@ public class AddIssueActivity extends MorphActivity {
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mAssigneeSpinner.setVisibility(View.GONE);
mAssigneeProgress.setVisibility(View.GONE);
}
};
 
private final Callback<List<Member>> mGroupMembersCallback = new Callback<List<Member>>() {
private final Callback<List<Member>> mGroupMembersCallback = new EasyCallback<List<Member>>() {
@Override
public void onResponse(Response<List<Member>> response, Retrofit retrofit) {
if (!response.isSuccess()) {
mAssigneeSpinner.setVisibility(View.GONE);
return;
}
if (response.body() != null) {
mMembers.addAll(response.body());
}
public void onResponse(@NonNull List<Member> response) {
mMembers.addAll(response);
setAssignees();
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mAssigneeSpinner.setVisibility(View.GONE);
mAssigneeProgress.setVisibility(View.GONE);
}
};
 
private final Callback<Issue> mIssueCreatedCallback = new Callback<Issue>() {
private final Callback<Issue> mIssueCreatedCallback = new EasyCallback<Issue>() {
 
@Override
public void onResponse(Response<Issue> response, Retrofit retrofit) {
if (!response.isSuccess()) {
Snackbar.make(mRoot, getString(R.string.failed_to_create_issue), Snackbar.LENGTH_SHORT)
.show();
return;
}
public void onResponse(@NonNull Issue response) {
if (mIssue == null) {
LabCoatApp.bus().post(new IssueCreatedEvent(response.body()));
LabCoatApp.bus().post(new IssueCreatedEvent(response));
} else {
LabCoatApp.bus().post(new IssueChangedEvent(response.body()));
LabCoatApp.bus().post(new IssueChangedEvent(response));
}
dismiss();
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
Snackbar.make(mRoot, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.failed_to_create_issue), Snackbar.LENGTH_SHORT)
.show();
}
};
Loading
Loading
@@ -205,6 +202,16 @@ public class AddIssueActivity extends MorphActivity {
mToolbar.inflateMenu(R.menu.menu_add_milestone);
}
 
mRoot.addListener(new ElasticDragDismissListener() {
@Override
public void onDrag(float elasticOffset, float elasticOffsetPixels, float rawOffset, float rawOffsetPixels) {
}
@Override
public void onDragDismissed() {
onBackPressed();
}
});
load();
}
 
Loading
Loading
@@ -239,11 +246,11 @@ public class AddIssueActivity extends MorphActivity {
}
 
private void save() {
if(!TextUtils.isEmpty(mTitleInput.getText())) {
if (!TextUtils.isEmpty(mTitleInput.getText())) {
mTitleInputLayout.setError(null);
showLoading();
Long assigneeId = null;
if (mAssigneeSpinner.getAdapter() != null ) {
if (mAssigneeSpinner.getAdapter() != null) {
//the user did make a selection of some sort. So update it
Member member = (Member) mAssigneeSpinner.getSelectedItem();
if (member == null) {
Loading
Loading
@@ -269,8 +276,7 @@ public class AddIssueActivity extends MorphActivity {
mDescriptionInput.getText().toString(),
assigneeId,
milestoneId);
}
else {
} else {
mTitleInputLayout.setError(getString(R.string.required_field));
}
}
Loading
Loading
Loading
Loading
@@ -4,6 +4,8 @@ package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.Toolbar;
Loading
Loading
@@ -13,12 +15,17 @@ import android.view.View;
import android.widget.Button;
import android.widget.EditText;
 
import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer;
import com.commit451.elasticdragdismisslayout.ElasticDragDismissFrameLayout;
import com.commit451.elasticdragdismisslayout.ElasticDragDismissListener;
import com.commit451.gitlab.LabCoatApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.event.MilestoneChangedEvent;
import com.commit451.gitlab.event.MilestoneCreatedEvent;
import com.commit451.gitlab.model.api.Milestone;
import com.commit451.gitlab.util.AppThemeUtil;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
 
import org.parceler.Parcels;
Loading
Loading
@@ -29,12 +36,16 @@ import java.util.Date;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import timber.log.Timber;
 
public class AddMilestoneActivity extends MorphActivity {
public class AddMilestoneActivity extends MorphActivity implements ATEActivityThemeCustomizer {
@Override
public int getActivityTheme() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
R.style.Activity_Translucent : R.style.ActivityLight_Translucent;
}
 
private static final String KEY_PROJECT_ID = "project_id";
private static final String KEY_MILESTONE = "milestone";
Loading
Loading
@@ -53,7 +64,7 @@ public class AddMilestoneActivity extends MorphActivity {
}
 
@Bind(R.id.root)
View mRoot;
ElasticDragDismissFrameLayout mRoot;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.title_text_input_layout)
Loading
Loading
@@ -79,6 +90,7 @@ public class AddMilestoneActivity extends MorphActivity {
now.get(Calendar.MONTH),
now.get(Calendar.DAY_OF_MONTH)
);
dpd.setAccentColor(AppThemeUtil.resolveAccentColor(this));
dpd.show(getFragmentManager(), "date_picker");
}
 
Loading
Loading
@@ -105,25 +117,21 @@ public class AddMilestoneActivity extends MorphActivity {
}
};
 
private Callback<Milestone> mMilestoneCallback = new Callback<Milestone>() {
private Callback<Milestone> mMilestoneCallback = new EasyCallback<Milestone>() {
 
@Override
public void onResponse(Response<Milestone> response, Retrofit retrofit) {
public void onResponse(@NonNull Milestone response) {
mProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
showError();
return;
}
if (mMilestone == null) {
LabCoatApp.bus().post(new MilestoneCreatedEvent(response.body()));
LabCoatApp.bus().post(new MilestoneCreatedEvent(response));
} else {
LabCoatApp.bus().post(new MilestoneChangedEvent(response.body()));
LabCoatApp.bus().post(new MilestoneChangedEvent(response));
}
finish();
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
showError();
Loading
Loading
@@ -158,6 +166,15 @@ public class AddMilestoneActivity extends MorphActivity {
return false;
}
});
mRoot.addListener(new ElasticDragDismissListener() {
@Override
public void onDrag(float elasticOffset, float elasticOffsetPixels, float rawOffset, float rawOffsetPixels) {}
@Override
public void onDragDismissed() {
onBackPressed();
}
});
}
 
private void createMilestone() {
Loading
Loading
Loading
Loading
@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
Loading
Loading
@@ -14,13 +15,17 @@ import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
 
import com.commit451.gitlab.LabCoatApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.UsersAdapter;
import com.commit451.gitlab.animation.HideRunnable;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.api.exception.HttpException;
import com.commit451.gitlab.dialog.AccessDialog;
import com.commit451.gitlab.event.MemberAddedEvent;
import com.commit451.gitlab.model.api.Group;
Loading
Loading
@@ -37,9 +42,7 @@ import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import timber.log.Timber;
 
/**
Loading
Loading
@@ -62,12 +65,18 @@ public class AddUserActivity extends MorphActivity {
return intent;
}
 
@Bind(R.id.root) View mRoot;
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.search) EditText mUserSearch;
@Bind(R.id.swipe_layout) SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list) RecyclerView mRecyclerView;
@Bind(R.id.clear) View mClearView;
@Bind(R.id.root)
ViewGroup mRoot;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.search)
EditText mUserSearch;
@Bind(R.id.swipe_layout)
SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list)
RecyclerView mRecyclerView;
@Bind(R.id.clear)
View mClearView;
GridLayoutManager mUserLinearLayoutManager;
 
@OnClick(R.id.clear)
Loading
Loading
@@ -77,6 +86,7 @@ public class AddUserActivity extends MorphActivity {
public void run() {
mClearView.setVisibility(View.GONE);
mUserSearch.getText().clear();
KeyboardUtil.showKeyboard(AddUserActivity.this, mUserSearch);
}
});
}
Loading
Loading
@@ -123,17 +133,15 @@ public class AddUserActivity extends MorphActivity {
 
private final TextWatcher mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
 
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (TextUtils.isEmpty(s)) {
mClearView.animate().alpha(0.0f).withEndAction(new Runnable() {
@Override
public void run() {
mClearView.setVisibility(View.GONE);
}
});
mClearView.animate()
.alpha(0.0f)
.withEndAction(new HideRunnable(mClearView));
} else {
mClearView.setVisibility(View.VISIBLE);
mClearView.animate().alpha(1.0f);
Loading
Loading
@@ -141,49 +149,7 @@ public class AddUserActivity extends MorphActivity {
}
 
@Override
public void afterTextChanged(Editable s) {}
};
private final Callback<List<UserBasic>> mUserCallback = new Callback<List<UserBasic>>() {
@Override
public void onResponse(Response<List<UserBasic>> response, Retrofit retrofit) {
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
if (!response.isSuccess()) {
return;
}
mAdapter.setData(response.body());
mNextPageUrl = PaginationUtil.parse(response).getNext();
Timber.d("Next page url is %s", mNextPageUrl);
}
@Override
public void onFailure(Throwable t) {
Timber.e(t, null);
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error_users), Snackbar.LENGTH_SHORT)
.show();
}
};
private final Callback<List<UserBasic>> mMoreUsersCallback = new Callback<List<UserBasic>>() {
@Override
public void onResponse(Response<List<UserBasic>> response, Retrofit retrofit) {
mLoading = false;
mAdapter.setLoading(false);
if (!response.isSuccess()) {
return;
}
mAdapter.addData(response.body());
mNextPageUrl = PaginationUtil.parse(response).getNext();
}
@Override
public void onFailure(Throwable t) {
Timber.e(t, null);
mAdapter.setLoading(false);
public void afterTextChanged(Editable s) {
}
};
 
Loading
Loading
@@ -213,27 +179,65 @@ public class AddUserActivity extends MorphActivity {
}
};
 
private final Callback<Member> mAddGroupMemeberCallback = new Callback<Member>() {
private final Callback<List<UserBasic>> mUserCallback = new EasyCallback<List<UserBasic>>() {
@Override
public void onResponse(Response<Member> response, Retrofit retrofit) {
if (!response.isSuccess()) {
//Conflict
if (response.code() == 409) {
Snackbar.make(mRoot, R.string.error_user_conflict, Snackbar.LENGTH_SHORT)
.show();
}
return;
}
public void onResponse(@NonNull List<UserBasic> response) {
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
mAdapter.setData(response);
mNextPageUrl = PaginationUtil.parse(getResponse()).getNext();
Timber.d("Next page url is %s", mNextPageUrl);
}
@Override
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
Snackbar.make(mRoot, getString(R.string.connection_error_users), Snackbar.LENGTH_SHORT)
.show();
}
};
private final Callback<List<UserBasic>> mMoreUsersCallback = new EasyCallback<List<UserBasic>>() {
@Override
public void onResponse(@NonNull List<UserBasic> response) {
mLoading = false;
mAdapter.setLoading(false);
mAdapter.addData(response);
mNextPageUrl = PaginationUtil.parse(getResponse()).getNext();
}
@Override
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mAdapter.setLoading(false);
}
};
private final Callback<Member> mAddGroupMemeberCallback = new EasyCallback<Member>() {
@Override
public void onResponse(@NonNull Member response) {
Snackbar.make(mRoot, R.string.user_added_successfully, Snackbar.LENGTH_SHORT)
.show();
mAccessDialog.dismiss();
dismiss();
LabCoatApp.bus().post(new MemberAddedEvent(response.body()));
LabCoatApp.bus().post(new MemberAddedEvent(response));
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
if (t instanceof HttpException) {
//Conflict
if (((HttpException) t).getCode() == 409) {
Snackbar.make(mRoot, R.string.error_user_conflict, Snackbar.LENGTH_SHORT)
.show();
}
} else {
Snackbar.make(mRoot, R.string.error_failed_to_add_user, Snackbar.LENGTH_SHORT)
.show();
}
}
};
 
Loading
Loading
package com.commit451.gitlab.activity;
 
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
 
import com.afollestad.appthemeengine.ATEActivity;
import com.commit451.gitlab.R;
 
/**
* Created by Jawn on 7/27/2015.
*/
public class BaseActivity extends AppCompatActivity {
public class BaseActivity extends ATEActivity {
@Nullable
@Override
public final String getATEKey() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
"dark_theme" : "light_theme";
}
 
public boolean hasEmptyFields(TextInputLayout... textInputLayouts) {
boolean hasEmptyField = false;
Loading
Loading
Loading
Loading
@@ -3,16 +3,18 @@ package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.DiffAdapter;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.api.Diff;
import com.commit451.gitlab.model.api.Project;
Loading
Loading
@@ -24,9 +26,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;
 
/**
Loading
Loading
@@ -44,6 +44,7 @@ public class DiffActivity extends BaseActivity {
return intent;
}
 
@Bind(R.id.root) ViewGroup mRoot;
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.swipe_layout) SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list) RecyclerView mDiffRecyclerView;
Loading
Loading
@@ -53,27 +54,19 @@ public class DiffActivity extends BaseActivity {
private Project mProject;
private RepositoryCommit mCommit;
 
private Callback<List<Diff>> mDiffCallback = new Callback<List<Diff>>() {
private Callback<List<Diff>> mDiffCallback = new EasyCallback<List<Diff>>() {
@Override
public void onResponse(Response<List<Diff>> response, Retrofit retrofit) {
public void onResponse(@NonNull List<Diff> response) {
mSwipeRefreshLayout.setRefreshing(false);
if (!response.isSuccess()) {
return;
}
for (Diff diff : response.body()) {
Timber.d("diff text: "+ diff.getDiff());
}
mDiffAdapter.setData(response.body());
mDiffAdapter.setData(response);
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
mSwipeRefreshLayout.setRefreshing(false);
Timber.e(t, null);
mMessageText.setText(R.string.connection_error);
mMessageText.setVisibility(View.VISIBLE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
 
Loading
Loading
@@ -95,7 +88,7 @@ public class DiffActivity extends BaseActivity {
});
mToolbar.setTitle(mCommit.getShortId());
 
mDiffAdapter = new DiffAdapter(new DiffAdapter.Listener() {
mDiffAdapter = new DiffAdapter(mCommit, new DiffAdapter.Listener() {
@Override
public void onDiffClicked(Diff diff) {
 
Loading
Loading
Loading
Loading
@@ -15,7 +15,6 @@ import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.util.Base64;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
Loading
Loading
@@ -23,8 +22,10 @@ import android.webkit.MimeTypeMap;
import android.webkit.WebView;
 
import com.commit451.gitlab.R;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.api.RepositoryFile;
import com.commit451.gitlab.observable.DecodeObservableFactory;
 
import java.io.File;
import java.io.FileOutputStream;
Loading
Loading
@@ -35,9 +36,10 @@ import java.nio.charset.Charset;
 
import butterknife.Bind;
import butterknife.ButterKnife;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import timber.log.Timber;
 
public class FileActivity extends BaseActivity {
Loading
Loading
@@ -71,63 +73,23 @@ public class FileActivity extends BaseActivity {
private long mProjectId;
private String mPath;
private String mRef;
private RepositoryFile mRepositoryFile;
private String mFileName;
private byte[] mBlob;
private @Option int mOption;
 
private final Callback<RepositoryFile> mFileResponseCallback = new Callback<RepositoryFile>() {
private final Callback<RepositoryFile> mRepositoryFileCallback = new EasyCallback<RepositoryFile>() {
@Override
public void onResponse(Response<RepositoryFile> response, Retrofit retrofit) {
public void onResponse(@NonNull RepositoryFile response) {
mProgressView.setVisibility(View.GONE);
if (!response.isSuccess()) {
Snackbar.make(getWindow().getDecorView(), R.string.file_load_error, Snackbar.LENGTH_SHORT)
.show();
return;
}
if (response.body().getSize() > MAX_FILE_SIZE) {
Snackbar.make(getWindow().getDecorView(), R.string.file_too_big, Snackbar.LENGTH_SHORT)
.show();
return;
}
// Receiving side
mFileName = response.body().getFileName();
mBlob = Base64.decode(response.body().getContent(), Base64.DEFAULT);
String content;
String mimeType = null;
String extension = fileExt(mFileName);
if (extension != null) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mimeType != null) {
mimeType = mimeType.toLowerCase();
}
}
if (mimeType != null && mimeType.startsWith("image/")) {
String imageURL = "data:" + mimeType + ";base64," + response.body().getContent();
content = "<!DOCTYPE html><html><head><link href=\"github.css\" rel=\"stylesheet\" /></head><body><img style=\"width: 100%;\" src=\"" + imageURL + "\"></body></html>";
} else {
String text = new String(mBlob, Charset.forName("UTF-8"));
content = "<!DOCTYPE html><html><head><link href=\"github.css\" rel=\"stylesheet\" /></head><body><pre><code>" + Html.escapeHtml(text) + "</code></pre><script src=\"highlight.pack.js\"></script><script>hljs.initHighlightingOnLoad();</script></body></html>";
}
mFileBlobView.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf8", null);
mToolbar.setTitle(mFileName);
mToolbar.inflateMenu(R.menu.file);
bindFile(response);
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mProgressView.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), R.string.file_load_error, Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, R.string.file_load_error, Snackbar.LENGTH_SHORT)
.show();
}
};
Loading
Loading
@@ -171,7 +133,83 @@ public class FileActivity extends BaseActivity {
 
private void loadData() {
mProgressView.setVisibility(View.VISIBLE);
GitLabClient.instance().getFile(mProjectId, mPath, mRef).enqueue(mFileResponseCallback);
GitLabClient.instance().getFile(mProjectId, mPath, mRef).enqueue(mRepositoryFileCallback);
}
private void bindFile(RepositoryFile repositoryFile) {
mRepositoryFile = repositoryFile;
mFileName = repositoryFile.getFileName();
mToolbar.setTitle(mFileName);
if (repositoryFile.getSize() > MAX_FILE_SIZE) {
Snackbar.make(mRoot, R.string.file_too_big, Snackbar.LENGTH_SHORT)
.show();
} else {
loadBlob(repositoryFile);
}
}
private void loadBlob(RepositoryFile repositoryFile) {
DecodeObservableFactory.newDecode(repositoryFile.getContent())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<byte[]>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {
Snackbar.make(mRoot, R.string.failed_to_load, Snackbar.LENGTH_SHORT)
.show();
}
@Override
public void onNext(byte[] bytes) {
bindBlob(bytes);
}
});
}
private void bindBlob(byte[] blob) {
mBlob = blob;
String content;
String mimeType = null;
String extension = fileExt(mFileName);
if (extension != null) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mimeType != null) {
mimeType = mimeType.toLowerCase();
}
}
if (mimeType != null && mimeType.startsWith("image/")) {
String imageURL = "data:" + mimeType + ";base64," + mRepositoryFile.getContent();
content = "<!DOCTYPE html>" +
"<html>" +
"<body>" +
"<img style=\"width: 100%;\" src=\"" + imageURL + "\">" +
"</body>" +
"</html>";
} else {
String text = new String(mBlob, Charset.forName("UTF-8"));
content = "<!DOCTYPE html>" +
"<html>" +
"<head>" +
"<link href=\"github.css\" rel=\"stylesheet\" />" +
"</head>" +
"<body>" +
"<pre><code>" +
Html.escapeHtml(text) +
"</code></pre>" +
"<script src=\"highlight.pack.js\"></script>" +
"<script>hljs.initHighlightingOnLoad();</script>" +
"</body>" +
"</html>";
}
mFileBlobView.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf8", null);
mToolbar.inflateMenu(R.menu.menu_file);
}
 
@TargetApi(23)
Loading
Loading
@@ -213,13 +251,13 @@ public class FileActivity extends BaseActivity {
outputStream = new FileOutputStream(targetFile);
outputStream.write(mBlob);
 
Snackbar.make(getWindow().getDecorView(), getString(R.string.file_saved), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.file_saved), Snackbar.LENGTH_SHORT)
.show();
 
return targetFile;
} catch (IOException e) {
Timber.e(e, null);
Snackbar.make(getWindow().getDecorView(), getString(R.string.save_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.save_error), Snackbar.LENGTH_SHORT)
.show();
} finally {
if (outputStream != null) {
Loading
Loading
@@ -231,7 +269,7 @@ public class FileActivity extends BaseActivity {
}
}
} else {
Snackbar.make(getWindow().getDecorView(), getString(R.string.save_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.save_error), Snackbar.LENGTH_SHORT)
.show();
}
 
Loading
Loading
@@ -241,7 +279,7 @@ public class FileActivity extends BaseActivity {
private void openFile() {
File file = saveBlob();
if (file == null) {
Snackbar.make(getWindow().getDecorView(), getString(R.string.open_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.open_error), Snackbar.LENGTH_SHORT)
.show();
return;
}
Loading
Loading
@@ -259,7 +297,7 @@ public class FileActivity extends BaseActivity {
startActivity(intent);
} catch (ActivityNotFoundException | SecurityException e) {
Timber.e(e, null);
Snackbar.make(getWindow().getDecorView(), getString(R.string.open_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.open_error), Snackbar.LENGTH_SHORT)
.show();
}
}
Loading
Loading
Loading
Loading
@@ -6,6 +6,8 @@ import android.os.Bundle;
import com.commit451.gitlab.BuildConfig;
import com.commit451.gitlab.data.Prefs;
import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.util.AppThemeUtil;
import com.commit451.gitlab.ssl.CustomKeyManager;
import com.commit451.gitlab.util.NavigationManager;
 
import java.util.List;
Loading
Loading
@@ -20,6 +22,7 @@ public class GitlabActivity extends Activity {
 
@Override
protected void onCreate(Bundle savedInstanceState) {
AppThemeUtil.setupDefaultConfigs(this);
super.onCreate(savedInstanceState);
 
int savedVersion = Prefs.getSavedVersion(this);
Loading
Loading
@@ -32,13 +35,44 @@ public class GitlabActivity extends Activity {
if(accounts.isEmpty()) {
NavigationManager.navigateToLogin(this);
} else {
NavigationManager.navigateToProjects(this);
loadPrivateKey(accounts, 0);
return;
}
 
// Always finish this activity
finish();
}
 
private void loadPrivateKey(final List<Account> accounts, final int i) {
if (i >= accounts.size()) {
runOnUiThread(new Runnable() {
@Override
public void run() {
NavigationManager.navigateToProjects(GitlabActivity.this);
finish();
}
});
return;
}
String alias = accounts.get(i).getPrivateKeyAlias();
if (alias != null && !CustomKeyManager.isCached(alias)) {
CustomKeyManager.cache(this, alias, new CustomKeyManager.KeyCallback() {
@Override
public void onSuccess(CustomKeyManager.KeyEntry entry) {
loadPrivateKey(accounts, i + 1);
}
@Override
public void onError(Exception e) {
loadPrivateKey(accounts, i + 1);
}
});
} else {
loadPrivateKey(accounts, i + 1);
}
}
/**
* Perform an upgrade from one version to another. This should only be one time upgrade things
*/
Loading
Loading
Loading
Loading
@@ -8,6 +8,8 @@ import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
Loading
Loading
@@ -17,28 +19,36 @@ 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.adapter.GroupPagerAdapter;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.model.api.GroupDetail;
import com.commit451.gitlab.transformation.PaletteTransformation;
import com.commit451.gitlab.util.AppThemeUtil;
 
import org.parceler.Parcels;
 
import butterknife.Bind;
import butterknife.ButterKnife;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import timber.log.Timber;
 
/**
* See the things about the group
* Created by John on 10/14/15.
*/
public class GroupActivity extends BaseActivity {
public class GroupActivity extends BaseActivity implements ATEActivityThemeCustomizer {
@Override
public int getActivityTheme() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
R.style.Activity_Group : R.style.ActivityLight_Group;
}
 
private static final String KEY_GROUP = "key_group";
private static final String KEY_GROUP_ID = "key_group_id";
Loading
Loading
@@ -62,18 +72,14 @@ public class GroupActivity extends BaseActivity {
@Bind(R.id.tabs) TabLayout mTabLayout;
@Bind(R.id.backdrop) ImageView mBackdrop;
 
private final Callback<GroupDetail> mGroupCallback = new Callback<GroupDetail>() {
private final Callback<GroupDetail> mGroupCallback = new EasyCallback<GroupDetail>() {
@Override
public void onResponse(Response<GroupDetail> response, Retrofit retrofit) {
if (!response.isSuccess()) {
showError();
return;
}
bind(response.body());
public void onResponse(@NonNull GroupDetail response) {
bind(response);
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
showError();
}
Loading
Loading
@@ -85,6 +91,12 @@ public class GroupActivity extends BaseActivity {
setContentView(R.layout.activity_group);
ButterKnife.bind(this);
 
// Default content and scrim colors
mCollapsingToolbarLayout.setContentScrimColor(
Config.primaryColor(this, AppThemeUtil.resolveThemeKey(this)));
mCollapsingToolbarLayout.setStatusBarScrimColor(
Config.primaryColorDark(this, AppThemeUtil.resolveThemeKey(this)));
mToolbar.setNavigationIcon(R.drawable.ic_back_24dp);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
Loading
Loading
@@ -127,8 +139,8 @@ public class GroupActivity 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
@@ -4,6 +4,8 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
Loading
Loading
@@ -14,8 +16,10 @@ import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.TextView;
 
import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.GroupAdapter;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.util.NavigationManager;
Loading
Loading
@@ -26,16 +30,20 @@ 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;
 
/**
* Displays the groups of the current user
* Created by Jawn on 10/4/2015.
*/
public class GroupsActivity extends BaseActivity {
public class GroupsActivity extends BaseActivity implements ATEActivityThemeCustomizer {
@Override
public int getActivityTheme() {
return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ?
R.style.Activity_Groups : R.style.ActivityLight_Groups;
}
 
public static Intent newInstance(Context context) {
Intent intent = new Intent(context, GroupsActivity.class);
Loading
Loading
@@ -66,47 +74,42 @@ public class GroupsActivity extends BaseActivity {
}
};
 
private final Callback<List<Group>> mGroupsCallback = new Callback<List<Group>>() {
private final Callback<List<Group>> mGroupsCallback = new EasyCallback<List<Group>>() {
@Override
public void onResponse(Response<List<Group>> response, Retrofit retrofit) {
public void onResponse(@NonNull List<Group> response) {
mLoading = false;
mSwipeRefreshLayout.setRefreshing(false);
if (!response.isSuccess()) {
return;
}
if (response.body().isEmpty()) {
if (response.isEmpty()) {
mMessageText.setText(R.string.no_groups);
mMessageText.setVisibility(View.VISIBLE);
mGroupRecyclerView.setVisibility(View.GONE);
} else {
mGroupAdapter.setGroups(response.body());
mGroupAdapter.setGroups(response);
mMessageText.setVisibility(View.GONE);
mGroupRecyclerView.setVisibility(View.VISIBLE);
}
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mSwipeRefreshLayout.setRefreshing(false);
mLoading = false;
mMessageText.setVisibility(View.VISIBLE);
mMessageText.setText(R.string.connection_error);
}
};
 
private final Callback<List<Group>> mMoreGroupsCallback = new Callback<List<Group>>() {
private final Callback<List<Group>> mMoreGroupsCallback = new EasyCallback<List<Group>>() {
@Override
public void onResponse(Response<List<Group>> response, Retrofit retrofit) {
public void onResponse(@NonNull List<Group> response) {
mLoading = false;
if (!response.isSuccess()) {
return;
}
mGroupAdapter.addGroups(response.body());
mNextPageUrl = PaginationUtil.parse(response).getNext();
mGroupAdapter.addGroups(response);
mNextPageUrl = PaginationUtil.parse(getResponse()).getNext();
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mLoading = false;
}
Loading
Loading
@@ -153,6 +156,7 @@ public class GroupsActivity extends BaseActivity {
}
 
private void load() {
mMessageText.setVisibility(View.GONE);
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
Loading
Loading
Loading
Loading
@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
Loading
Loading
@@ -12,12 +13,14 @@ import android.support.v7.widget.Toolbar;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
 
import com.commit451.gitlab.LabCoatApp;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.IssueDetailsAdapter;
import com.commit451.gitlab.api.EasyCallback;
import com.commit451.gitlab.api.GitLabClient;
import com.commit451.gitlab.event.IssueChangedEvent;
import com.commit451.gitlab.event.IssueReloadEvent;
Loading
Loading
@@ -37,9 +40,7 @@ import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import retrofit2.Callback;
import timber.log.Timber;
 
/**
Loading
Loading
@@ -57,12 +58,20 @@ public class IssueActivity extends BaseActivity {
return intent;
}
 
@Bind(R.id.toolbar) Toolbar mToolbar;
@Bind(R.id.issue_title) TextView mIssueTitle;
@Bind(R.id.swipe_layout) SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list) RecyclerView mNotesRecyclerView;
@Bind(R.id.new_note_edit) EditText mNewNoteEdit;
@Bind(R.id.progress) View mProgress;
@Bind(R.id.root)
ViewGroup mRoot;
@Bind(R.id.toolbar)
Toolbar mToolbar;
@Bind(R.id.issue_title)
TextView mIssueTitle;
@Bind(R.id.swipe_layout)
SwipeRefreshLayout mSwipeRefreshLayout;
@Bind(R.id.list)
RecyclerView mNotesRecyclerView;
@Bind(R.id.new_note_edit)
EditText mNewNoteEdit;
@Bind(R.id.progress)
View mProgress;
 
@OnClick(R.id.new_note_button)
public void onNewNoteClick() {
Loading
Loading
@@ -103,7 +112,7 @@ public class IssueActivity extends BaseActivity {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share:
IntentUtil.share(getWindow().getDecorView(), mIssue.getUrl(mProject));
IntentUtil.share(mRoot, mIssue.getUrl(mProject));
return true;
case R.id.action_close:
closeOrOpenIssue();
Loading
Loading
@@ -113,60 +122,49 @@ public class IssueActivity extends BaseActivity {
}
};
 
private Callback<List<Note>> mNotesCallback = new Callback<List<Note>>() {
private Callback<List<Note>> mNotesCallback = new EasyCallback<List<Note>>() {
 
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
public void onResponse(@NonNull List<Note> response) {
mLoading = false;
if (!response.isSuccess()) {
return;
}
mSwipeRefreshLayout.setRefreshing(false);
mNextPageUrl = PaginationUtil.parse(response).getNext();
mIssueDetailsAdapter.setNotes(response.body());
mNextPageUrl = PaginationUtil.parse(getResponse()).getNext();
mIssueDetailsAdapter.setNotes(response);
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
mLoading = false;
Timber.e(t, null);
mSwipeRefreshLayout.setRefreshing(false);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
 
private Callback<List<Note>> mMoreNotesCallback = new Callback<List<Note>>() {
private Callback<List<Note>> mMoreNotesCallback = new EasyCallback<List<Note>>() {
 
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
public void onResponse(@NonNull List<Note> response) {
mLoading = false;
if (!response.isSuccess()) {
return;
}
mIssueDetailsAdapter.setLoading(false);
mNextPageUrl = PaginationUtil.parse(response).getNext();
mIssueDetailsAdapter.addNotes(response.body());
mNextPageUrl = PaginationUtil.parse(getResponse()).getNext();
mIssueDetailsAdapter.addNotes(response);
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
mLoading = false;
Timber.e(t, null);
mIssueDetailsAdapter.setLoading(false);
}
};
 
private final Callback<Issue> mOpenCloseCallback = new Callback<Issue>() {
private final Callback<Issue> mOpenCloseCallback = new EasyCallback<Issue>() {
@Override
public void onResponse(Response<Issue> response, Retrofit retrofit) {
public void onResponse(@NonNull Issue response) {
mProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
Snackbar.make(getWindow().getDecorView(), getString(R.string.error_changing_issue), Snackbar.LENGTH_SHORT)
.show();
return;
}
mIssue = response.body();
mIssue = response;
LabCoatApp.bus().post(new IssueChangedEvent(mIssue));
LabCoatApp.bus().post(new IssueReloadEvent());
setOpenCloseMenuStatus();
Loading
Loading
@@ -174,31 +172,28 @@ public class IssueActivity extends BaseActivity {
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.error_changing_issue), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.error_changing_issue), Snackbar.LENGTH_SHORT)
.show();
}
};
 
private Callback<Note> mPostNoteCallback = new Callback<Note>() {
private Callback<Note> mPostNoteCallback = new EasyCallback<Note>() {
 
@Override
public void onResponse(Response<Note> response, Retrofit retrofit) {
if (!response.isSuccess()) {
return;
}
public void onResponse(@NonNull Note response) {
mProgress.setVisibility(View.GONE);
mIssueDetailsAdapter.addNote(response.body());
mIssueDetailsAdapter.addNote(response);
mNotesRecyclerView.smoothScrollToPosition(IssueDetailsAdapter.getHeaderCount());
}
 
@Override
public void onFailure(Throwable t) {
public void onAllFailure(Throwable t) {
Timber.e(t, null);
mProgress.setVisibility(View.GONE);
Snackbar.make(getWindow().getDecorView(), getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
Snackbar.make(mRoot, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show();
}
};
Loading
Loading
@@ -222,7 +217,7 @@ public class IssueActivity extends BaseActivity {
}
});
mToolbar.setSubtitle(mProject.getNameWithNamespace());
mToolbar.inflateMenu(R.menu.issue);
mToolbar.inflateMenu(R.menu.menu_issue);
mOpenCloseMenuItem = mToolbar.getMenu().findItem(R.id.action_close);
mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
 
Loading
Loading
@@ -285,7 +280,7 @@ public class IssueActivity extends BaseActivity {
private void postNote() {
String body = mNewNoteEdit.getText().toString();
 
if(body.length() < 1) {
if (body.length() < 1) {
return;
}
 
Loading
Loading
@@ -303,7 +298,7 @@ public class IssueActivity extends BaseActivity {
mProgress.setVisibility(View.VISIBLE);
if (mIssue.getState() == Issue.State.CLOSED) {
GitLabClient.instance().updateIssueStatus(mProject.getId(), mIssue.getId(), Issue.STATE_REOPEN)
.enqueue(mOpenCloseCallback);
.enqueue(mOpenCloseCallback);
} else {
GitLabClient.instance().updateIssueStatus(mProject.getId(), mIssue.getId(), Issue.STATE_CLOSE)
.enqueue(mOpenCloseCallback);
Loading
Loading
package com.commit451.gitlab.activity;
 
import android.Manifest;
import android.accounts.AccountManager;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Dialog;
Loading
Loading
@@ -10,13 +11,19 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatAutoCompleteTextView;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.Patterns;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.TextView;
 
import com.commit451.gitlab.LabCoatApp;
Loading
Loading
@@ -29,55 +36,81 @@ import com.commit451.gitlab.event.ReloadDataEvent;
import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.model.api.UserFull;
import com.commit451.gitlab.model.api.UserLogin;
import com.commit451.gitlab.ssl.CustomHostnameVerifier;
import com.commit451.gitlab.ssl.CustomKeyManager;
import com.commit451.gitlab.ssl.X509CertificateException;
import com.commit451.gitlab.ssl.X509Util;
import com.commit451.gitlab.util.KeyboardUtil;
import com.commit451.gitlab.util.NavigationManager;
import com.commit451.gitlab.view.EmailAutoCompleteTextView;
import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.HttpUrl;
 
import java.net.ConnectException;
import java.security.cert.CertificateEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
 
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
 
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import timber.log.Timber;
 
public class LoginActivity extends BaseActivity {
 
private static final String EXTRA_SHOW_CLOSE = "show_close";
private static final int PERMISSION_REQUEST_GET_ACCOUNTS = 1337;
private static Pattern sTokenPattern = Pattern.compile("^[A-Za-z0-9-_]*$");
 
public static Intent newInstance(Context context) {
return newInstance(context, false);
}
public static Intent newInstance(Context context, boolean showClose) {
Intent intent = new Intent(context, LoginActivity.class);
intent.putExtra(EXTRA_SHOW_CLOSE, showClose);
return intent;
}
 
@Bind(R.id.root) View mRoot;
@Bind(R.id.url_hint) TextInputLayout mUrlHint;
@Bind(R.id.url_input) TextView mUrlInput;
@Bind(R.id.user_input_hint) TextInputLayout mUserHint;
@Bind(R.id.user_input) EmailAutoCompleteTextView mUserInput;
@Bind(R.id.password_hint) TextInputLayout mPasswordHint;
@Bind(R.id.password_input) TextView mPasswordInput;
@Bind(R.id.token_hint) TextInputLayout mTokenHint;
@Bind(R.id.token_input) TextView mTokenInput;
@Bind(R.id.normal_login) View mNormalLogin;
@Bind(R.id.token_login) View mTokenLogin;
@Bind(R.id.progress) View mProgress;
@Bind(R.id.root)
View mRoot;
@Bind(R.id.close)
View mClose;
@Bind(R.id.url_hint)
TextInputLayout mUrlHint;
@Bind(R.id.url_input)
TextView mUrlInput;
@Bind(R.id.user_input_hint)
TextInputLayout mUserHint;
@Bind(R.id.user_input)
AppCompatAutoCompleteTextView mUserInput;
@Bind(R.id.password_hint)
TextInputLayout mPasswordHint;
@Bind(R.id.password_input)
TextView mPasswordInput;
@Bind(R.id.token_hint)
TextInputLayout mTokenHint;
@Bind(R.id.token_input)
TextView mTokenInput;
@Bind(R.id.normal_login)
View mNormalLogin;
@Bind(R.id.token_login)
View mTokenLogin;
@Bind(R.id.progress)
View mProgress;
 
private boolean mIsNormalLogin = true;
private String mTrustedCertificate;
private String mAuthorizationHeader;
private Account mAccount;
 
private final TextView.OnEditorActionListener onEditorActionListener = new TextView.OnEditorActionListener() {
Loading
Loading
@@ -88,6 +121,11 @@ public class LoginActivity extends BaseActivity {
}
};
 
@OnClick(R.id.close)
public void onCloseClick() {
onBackPressed();
}
@OnClick(R.id.show_normal_link)
public void showNormalLogin(TextView loginTypeTextView) {
if (mNormalLogin.getVisibility() == View.VISIBLE) {
Loading
Loading
@@ -152,8 +190,21 @@ public class LoginActivity extends BaseActivity {
 
mAccount = new Account();
mAccount.setServerUrl(uri);
mAccount.setTrustedCertificate(mTrustedCertificate);
mAccount.setAuthorizationHeader(mAuthorizationHeader);
login();
}
private void login() {
// This seems useless - But believe me, it makes everything work! Don't remove it.
// (OkHttpClientProvider caches the clients and needs a new account to recreate them)
Account newAccount = new Account();
newAccount.setServerUrl(mAccount.getServerUrl());
newAccount.setTrustedCertificate(mAccount.getTrustedCertificate());
newAccount.setTrustedHostname(mAccount.getTrustedHostname());
newAccount.setPrivateKeyAlias(mAccount.getPrivateKeyAlias());
newAccount.setAuthorizationHeader(mAccount.getAuthorizationHeader());
mAccount = newAccount;
 
if (mIsNormalLogin) {
connect(true);
Loading
Loading
@@ -162,32 +213,70 @@ public class LoginActivity extends BaseActivity {
}
}
 
private void loginWithPrivateToken() {
KeyChain.choosePrivateKeyAlias(this, new KeyChainAliasCallback() {
@Override
public void alias(String alias) {
mAccount.setPrivateKeyAlias(alias);
if (alias != null) {
if (!CustomKeyManager.isCached(alias)) {
CustomKeyManager.cache(LoginActivity.this, alias, new CustomKeyManager.KeyCallback() {
@Override
public void onSuccess(CustomKeyManager.KeyEntry entry) {
runOnUiThread(new Runnable() {
@Override
public void run() {
login();
}
});
}
@Override
public void onError(Exception e) {
mAccount.setPrivateKeyAlias(null);
Timber.e(e, "Failed to load private key");
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
login();
}
});
}
}
}
}, null, null, mAccount.getServerUrl().getHost(), mAccount.getServerUrl().getPort(), null);
}
private Callback<UserLogin> mLoginCallback = new Callback<UserLogin>() {
 
@Override
public void onResponse(Response<UserLogin> response, Retrofit retrofit) {
mTrustedCertificate = null;
if (!response.isSuccess()) {
public void onResponse(Call<UserLogin> call, Response<UserLogin> response) {
if (!response.isSuccessful()) {
handleConnectionResponse(response);
return;
}
mAccount.setPrivateToken(response.body().getPrivateToken());
loadUser();
}
 
@Override
public void onFailure(Throwable t) {
mTrustedCertificate = null;
public void onFailure(Call<UserLogin> call, Throwable t) {
Timber.e(t, null);
handleConnectionError(t);
}
};
 
private Callback<UserFull> mTestUserCallback = new Callback<UserFull>() {
@Override
public void onResponse(Response<UserFull> response, Retrofit retrofit) {
public void onResponse(Call<UserFull> call, Response<UserFull> response) {
mProgress.setVisibility(View.GONE);
if (!response.isSuccess()) {
if (!response.isSuccessful()) {
handleConnectionResponse(response);
return;
}
Loading
Loading
@@ -203,8 +292,7 @@ public class LoginActivity extends BaseActivity {
}
 
@Override
public void onFailure(Throwable t) {
mTrustedCertificate = null;
public void onFailure(Call<UserFull> call, Throwable t) {
Timber.e(t, null);
handleConnectionError(t);
}
Loading
Loading
@@ -215,6 +303,10 @@ public class LoginActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
boolean showClose = getIntent().getBooleanExtra(EXTRA_SHOW_CLOSE, false);
mClose.setVisibility(showClose ? View.VISIBLE : View.GONE);
mPasswordInput.setOnEditorActionListener(onEditorActionListener);
mTokenInput.setOnEditorActionListener(onEditorActionListener);
mUserInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
Loading
Loading
@@ -230,7 +322,7 @@ public class LoginActivity extends BaseActivity {
@TargetApi(23)
private void checkAccountPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED) {
mUserInput.retrieveAccounts();
retrieveAccounts();
} else {
requestPermissions(new String[]{Manifest.permission.GET_ACCOUNTS}, PERMISSION_REQUEST_GET_ACCOUNTS);
}
Loading
Loading
@@ -240,8 +332,8 @@ public class LoginActivity extends BaseActivity {
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_GET_ACCOUNTS: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mUserInput.retrieveAccounts();
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
retrieveAccounts();
}
}
}
Loading
Loading
@@ -252,19 +344,17 @@ public class LoginActivity extends BaseActivity {
mProgress.setAlpha(0.0f);
mProgress.animate().alpha(1.0f);
 
if(byAuth) {
if (byAuth) {
connectByAuth();
}
else {
} else {
connectByToken();
}
}
 
private void connectByAuth() {
if(mUserInput.getText().toString().contains("@")) {
if (mUserInput.getText().toString().contains("@")) {
GitLabClient.instance(mAccount).loginWithEmail(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
}
else {
} else {
GitLabClient.instance(mAccount).loginWithUsername(mUserInput.getText().toString(), mPasswordInput.getText().toString()).enqueue(mLoginCallback);
}
}
Loading
Loading
@@ -281,7 +371,8 @@ public class LoginActivity extends BaseActivity {
private void handleConnectionError(Throwable t) {
mProgress.setVisibility(View.GONE);
 
if(t instanceof SSLHandshakeException && t.getCause() instanceof X509CertificateException) {
if (t instanceof SSLHandshakeException && t.getCause() instanceof X509CertificateException) {
mAccount.setTrustedCertificate(null);
String fingerprint = null;
try {
fingerprint = X509Util.getFingerPrint(((X509CertificateException) t.getCause()).getChain()[0]);
Loading
Loading
@@ -297,8 +388,8 @@ public class LoginActivity extends BaseActivity {
@Override
public void onClick(DialogInterface dialog, int which) {
if (finalFingerprint != null) {
mTrustedCertificate = finalFingerprint;
onLoginClick();
mAccount.setTrustedCertificate(finalFingerprint);
login();
}
 
dialog.dismiss();
Loading
Loading
@@ -312,7 +403,36 @@ public class LoginActivity extends BaseActivity {
})
.show();
 
((TextView)d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
} else if (t instanceof SSLPeerUnverifiedException && t.getMessage().toLowerCase().contains("hostname")) {
mAccount.setTrustedHostname(null);
final String finalHostname = CustomHostnameVerifier.getLastFailedHostname();
Dialog d = new AlertDialog.Builder(this)
.setTitle(R.string.hostname_title)
.setMessage(R.string.hostname_message)
.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (finalHostname != null) {
mAccount.setTrustedHostname(finalHostname);
login();
}
dialog.dismiss();
}
})
.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
} else if (t instanceof ConnectException) {
Snackbar.make(mRoot, t.getLocalizedMessage(), Snackbar.LENGTH_LONG)
.show();
} else {
Snackbar.make(mRoot, getString(R.string.login_error), Snackbar.LENGTH_LONG)
.show();
Loading
Loading
@@ -323,6 +443,8 @@ public class LoginActivity extends BaseActivity {
mProgress.setVisibility(View.GONE);
switch (response.code()) {
case 401:
mAccount.setAuthorizationHeader(null);
String header = response.headers().get("WWW-Authenticate");
if (header != null) {
handleBasicAuthentication(response);
Loading
Loading
@@ -331,6 +453,9 @@ public class LoginActivity extends BaseActivity {
Snackbar.make(mRoot, getString(R.string.login_unauthorized), Snackbar.LENGTH_LONG)
.show();
return;
case 404:
Snackbar.make(mRoot, getString(R.string.login_404_error), Snackbar.LENGTH_LONG)
.show();
default:
Snackbar.make(mRoot, getString(R.string.login_error), Snackbar.LENGTH_LONG)
.show();
Loading
Loading
@@ -355,13 +480,12 @@ public class LoginActivity extends BaseActivity {
HttpLoginDialog dialog = new HttpLoginDialog(this, realm, new HttpLoginDialog.LoginListener() {
@Override
public void onLogin(String username, String password) {
mAuthorizationHeader = Credentials.basic(username, password);
onLoginClick();
mAccount.setAuthorizationHeader(Credentials.basic(username, password));
login();
}
 
@Override
public void onCancel() {
mAuthorizationHeader = null;
}
});
dialog.show();
Loading
Loading
@@ -380,4 +504,35 @@ public class LoginActivity extends BaseActivity {
}
return false;
}
/**
* Manually retrieve the accounts, typically used for API 23+ after getting the permission. Called automatically
* on creation, but needs to be recalled if the permission is granted later
*/
public void retrieveAccounts() {
Collection<String> accounts = getEmailAccounts();
if (accounts != null && !accounts.isEmpty()) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
R.layout.support_simple_spinner_dropdown_item,
new ArrayList<>(accounts));
mUserInput.setAdapter(adapter);
}
}
/**
* Get all the accounts that appear to be email accounts. HashSet so that we do not get duplicates
*
* @return list of email accounts
*/
private Set<String> getEmailAccounts() {
HashSet<String> emailAccounts = new HashSet<>();
AccountManager manager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
final android.accounts.Account[] accounts = manager.getAccounts();
for (android.accounts.Account account : accounts) {
if (!TextUtils.isEmpty(account.name) && Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
emailAccounts.add(account.name);
}
}
return emailAccounts;
}
}
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