diff --git a/app/build.gradle b/app/build.gradle index e6a515e023d8d2c082fa20dd5f73cf5b5cae6de5..4195957e08b9ecf42a748d9626b49255d05d924b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -52,7 +52,7 @@ dependencies { 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') { + compile('com.squareup.retrofit:converter-simplexml:2.0.0-beta2') { exclude group: 'xpp3', module: 'xpp3' exclude group: 'stax', module: 'stax-api' exclude group: 'stax', module: 'stax' @@ -82,4 +82,13 @@ dependencies { compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') { transitive = true; } + compile('com.github.afollestad:app-theme-engine:1.0.1@aar') { + transitive = true + } + compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { + transitive = true + } + compile('com.github.afollestad.material-dialogs:commons:0.8.5.3@aar') { + transitive = true + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3909174678c99d60d3fc75b9e0ceb909c5f8a041..6b1aedca895a6994b4e5c2ed887027461fcb7a19 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,11 +30,9 @@ - + - + - + - + + diff --git a/app/src/main/java/com/commit451/gitlab/activity/AboutActivity.java b/app/src/main/java/com/commit451/gitlab/activity/AboutActivity.java index 1120874c210a52c89fae54a303f80eed7f1c41f5..775fcf37dacb99e25411e21414c6a1d6065c966a 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/AboutActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/AboutActivity.java @@ -56,8 +56,6 @@ public class AboutActivity extends BaseActivity { ViewGroup mRoot; @Bind(R.id.toolbar) Toolbar mToolbar; - @Bind(R.id.toolbar_title) - TextView mToolbarTitle; @Bind(R.id.contributors) TextView mContributors; @Bind(R.id.physics_layout) @@ -118,7 +116,7 @@ public class AboutActivity extends BaseActivity { onBackPressed(); } }); - mToolbarTitle.setText(R.string.about); + mToolbar.setTitle(R.string.about); mPhysicsLayout.getPhysics().enableFling(); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); diff --git a/app/src/main/java/com/commit451/gitlab/activity/AddIssueActivity.java b/app/src/main/java/com/commit451/gitlab/activity/AddIssueActivity.java index 613c3846a1f4f3ae3317197a127b8df8c099cfc4..c98937630fad31944d14831ecc679d3e320157d0 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/AddIssueActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/AddIssueActivity.java @@ -3,6 +3,7 @@ package com.commit451.gitlab.activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.design.widget.TextInputLayout; @@ -13,6 +14,7 @@ import android.view.View; 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; @@ -42,7 +44,13 @@ 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"; diff --git a/app/src/main/java/com/commit451/gitlab/activity/AddMilestoneActivity.java b/app/src/main/java/com/commit451/gitlab/activity/AddMilestoneActivity.java index fd02f83d3eb4bc516c86854dd32855f1156c4366..19ae72e25e852f7641953387bdc65d09456cc3a4 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/AddMilestoneActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/AddMilestoneActivity.java @@ -4,6 +4,7 @@ package com.commit451.gitlab.activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.design.widget.TextInputLayout; @@ -14,6 +15,7 @@ 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; @@ -23,6 +25,7 @@ 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; @@ -36,7 +39,13 @@ import butterknife.OnClick; import retrofit.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"; @@ -81,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"); } diff --git a/app/src/main/java/com/commit451/gitlab/activity/BaseActivity.java b/app/src/main/java/com/commit451/gitlab/activity/BaseActivity.java index 7c45a1efbbb6a29f0de7007750dc5488d2df5805..64bb6c77ddaaed0f0bf60428157672c790c66ba6 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/BaseActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/BaseActivity.java @@ -1,15 +1,25 @@ 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; diff --git a/app/src/main/java/com/commit451/gitlab/activity/GitlabActivity.java b/app/src/main/java/com/commit451/gitlab/activity/GitlabActivity.java index 09e2ffcdedd4f462f31edbc1b558029d4ba1c838..3681583ca7c4b611e7ade6a9dba73e2133c25287 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/GitlabActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/GitlabActivity.java @@ -6,6 +6,7 @@ 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; @@ -21,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); diff --git a/app/src/main/java/com/commit451/gitlab/activity/GroupActivity.java b/app/src/main/java/com/commit451/gitlab/activity/GroupActivity.java index 55b85f645e7b20f77b6fc79981d3a78874d06f78..b01538c7b3cd19eb0d33cb300c361f43d9c73940 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/GroupActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/GroupActivity.java @@ -8,6 +8,7 @@ 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; @@ -18,6 +19,9 @@ 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; @@ -26,6 +30,7 @@ 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; @@ -37,7 +42,13 @@ import timber.log.Timber; /** * See the things about the group */ -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"; @@ -80,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 @@ -122,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) diff --git a/app/src/main/java/com/commit451/gitlab/activity/GroupsActivity.java b/app/src/main/java/com/commit451/gitlab/activity/GroupsActivity.java index 09f9bb5b723aa33e5d24e53c572f4ea6fd1a1d5a..6b27764c812ffd24e55133b68ac0471a0db71174 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/GroupsActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/GroupsActivity.java @@ -4,6 +4,7 @@ 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; @@ -15,6 +16,7 @@ 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; @@ -35,7 +37,13 @@ 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); diff --git a/app/src/main/java/com/commit451/gitlab/activity/LoginActivity.java b/app/src/main/java/com/commit451/gitlab/activity/LoginActivity.java index f44ce449a23fad083fa1918b0679526d8a8247b6..383afd82788b60b2c505dbb737e6f7a87ecb09a1 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/LoginActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/LoginActivity.java @@ -1,6 +1,7 @@ package com.commit451.gitlab.activity; import android.Manifest; +import android.accounts.AccountManager; import android.annotation.TargetApi; import android.app.AlertDialog; import android.app.Dialog; @@ -16,9 +17,13 @@ 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; @@ -43,8 +48,12 @@ 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; @@ -72,7 +81,7 @@ public class LoginActivity extends BaseActivity { @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.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; @@ -283,7 +292,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); } @@ -294,7 +303,7 @@ public class LoginActivity extends BaseActivity { switch (requestCode) { case PERMISSION_REQUEST_GET_ACCOUNTS: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - mUserInput.retrieveAccounts(); + retrieveAccounts(); } } } @@ -467,4 +476,34 @@ 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 accounts = getEmailAccounts(); + if (accounts != null && !accounts.isEmpty()) { + ArrayAdapter 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 getEmailAccounts() { + HashSet 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; + } } diff --git a/app/src/main/java/com/commit451/gitlab/activity/MilestoneActivity.java b/app/src/main/java/com/commit451/gitlab/activity/MilestoneActivity.java index 2b4e934ba0e1fc9ead3e4ca15897b996da75d422..07cccd98f372a9d92213a52bb11093a9123afeb0 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/MilestoneActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/MilestoneActivity.java @@ -17,6 +17,7 @@ import android.widget.TextView; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.MilestoneIssuesAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -201,6 +202,7 @@ public class MilestoneActivity extends BaseActivity { mIssuesRecyclerView.setAdapter(mMilestoneIssuesAdapter); mIssuesLayoutManager = new LinearLayoutManager(this); mIssuesRecyclerView.setLayoutManager(mIssuesLayoutManager); + mIssuesRecyclerView.addItemDecoration(new DividerItemDecoration(this)); mIssuesRecyclerView.addOnScrollListener(mOnScrollListener); mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override diff --git a/app/src/main/java/com/commit451/gitlab/activity/MorphActivity.java b/app/src/main/java/com/commit451/gitlab/activity/MorphActivity.java index 2941f844d5c59998a63b85ba814939c0788decfd..4794354d175ed4b93c9e1d404848625faf94dbef 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/MorphActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/MorphActivity.java @@ -10,10 +10,12 @@ import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import com.afollestad.appthemeengine.Config; import com.commit451.easel.Easel; import com.commit451.gitlab.R; import com.commit451.gitlab.transition.MorphDialogToFab; import com.commit451.gitlab.transition.MorphFabToDialog; +import com.commit451.gitlab.util.AppThemeUtil; /** * Activity that morphs from a FAB. Make sure the view you want to morph has the view id R.id.mRoot and @@ -27,7 +29,7 @@ public class MorphActivity extends BaseActivity { throw new IllegalStateException("Cannot pass an empty view"); } if (Build.VERSION.SDK_INT >= 21) { - int fabColor = Easel.getThemeAttrColor(this, R.attr.colorAccent); + int fabColor = Config.accentColor(this, AppThemeUtil.resolveThemeKey(this)); int dialogColor = Easel.getThemeAttrColor(this, android.R.attr.windowBackground); setupSharedElementTransitionsFab(this, root, fabColor, diff --git a/app/src/main/java/com/commit451/gitlab/activity/ProjectActivity.java b/app/src/main/java/com/commit451/gitlab/activity/ProjectActivity.java index b77932e4ca71b54c544e00b57ccce51dee394a3d..e25536d505567cde97ab6767820ca6bf5031dc5e 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/ProjectActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/ProjectActivity.java @@ -20,6 +20,7 @@ import android.widget.TextView; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.adapter.SectionsPagerAdapter; +import com.commit451.gitlab.adapter.ThemedArrayAdapter; import com.commit451.gitlab.animation.HideRunnable; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -121,7 +122,7 @@ public class ProjectActivity extends BaseActivity { mBranchSpinner.setAlpha(0.0f); mBranchSpinner.animate().alpha(1.0f); // Set up the dropdown list navigation in the action bar. - mBranchSpinner.setAdapter(new ArrayAdapter<>(ProjectActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, response)); + mBranchSpinner.setAdapter(new ThemedArrayAdapter<>(ProjectActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, response)); } for (int i = 0; i < response.size(); i++) { if (response.get(i).getName().equals(mProject.getDefaultBranch())) { diff --git a/app/src/main/java/com/commit451/gitlab/activity/ProjectsActivity.java b/app/src/main/java/com/commit451/gitlab/activity/ProjectsActivity.java index a6812207c74ec7fcda9ff6b5cd642579ed89a970..e007fef1c111081dfe25a9e29b64c957d5ab49ab 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/ProjectsActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/ProjectsActivity.java @@ -3,6 +3,7 @@ package com.commit451.gitlab.activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.design.widget.NavigationView; import android.support.design.widget.TabLayout; import android.support.v4.view.GravityCompat; @@ -12,6 +13,7 @@ import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.view.View; +import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.adapter.ProjectsPagerAdapter; @@ -26,7 +28,13 @@ import butterknife.ButterKnife; * Shows the projects * Created by Jawn on 9/21/2015. */ -public class ProjectsActivity extends BaseActivity { +public class ProjectsActivity extends BaseActivity implements ATEActivityThemeCustomizer { + + @Override + public int getActivityTheme() { + return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ? + R.style.Activity_Projects : R.style.ActivityLight_Projects; + } public static Intent newInstance(Context context) { Intent intent = new Intent(context, ProjectsActivity.class); diff --git a/app/src/main/java/com/commit451/gitlab/activity/SettingsActivity.java b/app/src/main/java/com/commit451/gitlab/activity/SettingsActivity.java index 098b75560c075195a685a08020e00f2da8efd434..b2fc337e1fec7f56214e665da7f008a6d8d164ea 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/SettingsActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/SettingsActivity.java @@ -2,27 +2,131 @@ package com.commit451.gitlab.activity; import android.content.Context; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; +import com.afollestad.appthemeengine.Config; +import com.afollestad.appthemeengine.prefs.ATEColorPreference; +import com.afollestad.materialdialogs.color.ColorChooserDialog; import com.commit451.gitlab.R; +import butterknife.Bind; import butterknife.ButterKnife; /** * Settings screens are fun! * Created by John on 11/10/15. */ -public class SettingsActivity extends BaseActivity { +public class SettingsActivity extends BaseActivity + implements ColorChooserDialog.ColorCallback { public static Intent newInstance(Context context) { Intent intent = new Intent(context, SettingsActivity.class); return intent; } + @Bind(R.id.toolbar) Toolbar toolbar; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); ButterKnife.bind(this); + toolbar.setNavigationIcon(R.drawable.ic_back_24dp); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + toolbar.setTitle(R.string.settings); + + if (savedInstanceState == null) { + getFragmentManager().beginTransaction().replace(R.id.settings_container, new SettingsFragment()).commit(); + } else { + SettingsFragment frag = (SettingsFragment) getFragmentManager().findFragmentById(R.id.settings_container); + if (frag != null) frag.invalidateSettings(); + } + } + + @Override + public void onColorSelection(@NonNull ColorChooserDialog dialog, @ColorInt int selectedColor) { + final Config config = ATE.config(this, getATEKey()); + switch (dialog.getTitle()) { + case R.string.primary_color: + config.primaryColor(selectedColor); + break; + case R.string.accent_color: + config.accentColor(selectedColor); + break; + } + config.commit(); + recreate(); // recreation needed to reach the checkboxes in the preferences layout + } + + public static class SettingsFragment extends PreferenceFragment { + + String mAteKey; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + invalidateSettings(); + } + + public void invalidateSettings() { + mAteKey = ((SettingsActivity) getActivity()).getATEKey(); + + ATEColorPreference primaryColorPref = (ATEColorPreference) findPreference("primary_color"); + primaryColorPref.setColor(Config.primaryColor(getActivity(), mAteKey), Color.BLACK); + primaryColorPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + new ColorChooserDialog.Builder((SettingsActivity) getActivity(), R.string.primary_color) + .preselect(Config.primaryColor(getActivity(), mAteKey)) + .show(); + return true; + } + }); + + ATEColorPreference accentColorPref = (ATEColorPreference) findPreference("accent_color"); + accentColorPref.setColor(Config.accentColor(getActivity(), mAteKey), Color.BLACK); + accentColorPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + new ColorChooserDialog.Builder((SettingsActivity) getActivity(), R.string.accent_color) + .preselect(Config.accentColor(getActivity(), mAteKey)) + .show(); + return true; + } + }); + + findPreference("dark_theme").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + // Marks both theme configs as changed so MainActivity restarts itself on return + Config.markChanged(getActivity(), "light_theme"); + Config.markChanged(getActivity(), "dark_theme"); + // The dark_theme preference value gets saved by Android in the default PreferenceManager. + // It's used in getATEKey() of both the Activities. + getActivity().recreate(); + return true; + } + }); + } } } diff --git a/app/src/main/java/com/commit451/gitlab/activity/UserActivity.java b/app/src/main/java/com/commit451/gitlab/activity/UserActivity.java index c0702e7c12397ed03e118faa994796905cc81fd8..9012685a30823e53cf976fbc0eff3b86f26a9928 100644 --- a/app/src/main/java/com/commit451/gitlab/activity/UserActivity.java +++ b/app/src/main/java/com/commit451/gitlab/activity/UserActivity.java @@ -9,6 +9,7 @@ import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.design.widget.CollapsingToolbarLayout; import android.support.v4.app.FragmentTransaction; import android.support.v7.graphics.Palette; @@ -16,11 +17,15 @@ import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.ImageView; +import com.afollestad.appthemeengine.Config; +import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer; +import com.afollestad.appthemeengine.util.ATEUtil; import com.commit451.easel.Easel; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.fragment.FeedFragment; import com.commit451.gitlab.model.api.UserBasic; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.transformation.PaletteTransformation; import com.commit451.gitlab.util.ImageUtil; @@ -33,7 +38,13 @@ import butterknife.ButterKnife; * User activity, which shows the user! * Created by Jawn on 9/21/2015. */ -public class UserActivity extends BaseActivity { +public class UserActivity extends BaseActivity implements ATEActivityThemeCustomizer { + + @Override + public int getActivityTheme() { + return PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", true) ? + R.style.Activity_User : R.style.ActivityLight_User; + } private static final String KEY_USER = "user"; @@ -55,6 +66,15 @@ public class UserActivity extends BaseActivity { setContentView(R.layout.activity_user); ButterKnife.bind(this); mUser = Parcels.unwrap(getIntent().getParcelableExtra(KEY_USER)); + + // Default content and scrim colors + mCollapsingToolbarLayout.setContentScrimColor( + Config.primaryColor(this, AppThemeUtil.resolveThemeKey(this))); + mCollapsingToolbarLayout.setStatusBarScrimColor( + Config.primaryColorDark(this, AppThemeUtil.resolveThemeKey(this))); + mCollapsingToolbarLayout.setCollapsedTitleTextColor(Color.WHITE); + mCollapsingToolbarLayout.setExpandedTitleColor(Color.WHITE); + mToolbar.setNavigationIcon(R.drawable.ic_back_24dp); mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override @@ -91,8 +111,8 @@ public class UserActivity extends BaseActivity { private void bindPalette(Palette palette) { int animationTime = 1000; - int vibrantColor = palette.getVibrantColor(Easel.getThemeAttrColor(this, R.attr.colorPrimary)); - int darkerColor = Easel.getDarkerColor(vibrantColor); + int vibrantColor = palette.getVibrantColor(AppThemeUtil.resolvePrimaryColor(this)); + int darkerColor = ATEUtil.darkenColor(vibrantColor); if (Build.VERSION.SDK_INT >= 21) { Easel.getNavigationBarColorAnimator(getWindow(), darkerColor) diff --git a/app/src/main/java/com/commit451/gitlab/adapter/DividerItemDecoration.java b/app/src/main/java/com/commit451/gitlab/adapter/DividerItemDecoration.java new file mode 100644 index 0000000000000000000000000000000000000000..762dde0c84c5ec59306a7fabd9f63c266396750f --- /dev/null +++ b/app/src/main/java/com/commit451/gitlab/adapter/DividerItemDecoration.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.commit451.gitlab.adapter; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import com.commit451.gitlab.R; + +public class DividerItemDecoration extends RecyclerView.ItemDecoration { + private static final int[] ATTRS = new int[]{ + android.R.attr.listDivider + }; + private Drawable mDivider; + private int mDividerHeight; + + private boolean mShowFirstDivider = true; + private boolean mShowLastDivider = false; + + public DividerItemDecoration(Context context) { + final TypedArray a = context.obtainStyledAttributes(ATTRS); + mDivider = a.getDrawable(0); + a.recycle(); + mDividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height); + } + + public DividerItemDecoration(Context context, boolean first) { + this(context); + mShowFirstDivider = first; + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + drawVertical(c, parent); + } + + public void drawVertical(Canvas c, RecyclerView parent) { + final int left = parent.getPaddingLeft(); + final int right = parent.getWidth() - parent.getPaddingRight(); + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + if (isSkipped(child, parent)) continue; + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child + .getLayoutParams(); + final int top = child.getBottom() + params.bottomMargin; + final int bottom = top + mDividerHeight; + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, + RecyclerView.State state) { + if (isSkipped(view, parent)) return; + outRect.set(0, 0, 0, mDividerHeight); + } + + private boolean isSkipped(View child, RecyclerView parent) { + int position = parent.getChildAdapterPosition(child); + // Skip the first divider if needed + if (!mShowFirstDivider && position == 0) return true; + // Skip the last divider if needed + if (!mShowLastDivider && position == parent.getAdapter().getItemCount() - 1) return true; + // Otherwise don't skip + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/commit451/gitlab/adapter/ThemedArrayAdapter.java b/app/src/main/java/com/commit451/gitlab/adapter/ThemedArrayAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..b04c3a57a1c5e8b1d4cae4c3d6f490aa0b944eba --- /dev/null +++ b/app/src/main/java/com/commit451/gitlab/adapter/ThemedArrayAdapter.java @@ -0,0 +1,557 @@ +/* + * 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 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 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 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()); + } + + /** + * 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()); + } + + /** + * 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 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 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 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 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; + } + + /** + *

Sets the layout resource to create the drop down views.

+ * + * @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. + *

+ * 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. + */ + public static ThemedArrayAdapter createFromResource(Context context, + @ArrayRes int textArrayResId, @LayoutRes int textViewResId) { + CharSequence[] strings = context.getResources().getTextArray(textArrayResId); + return new ThemedArrayAdapter(context, textViewResId, strings); + } + + /** + * {@inheritDoc} + */ + public Filter getFilter() { + if (mFilter == null) { + mFilter = new ArrayFilter(); + } + return mFilter; + } + + /** + *

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.

+ */ + private class ArrayFilter extends Filter { + @Override + protected FilterResults performFiltering(CharSequence prefix) { + FilterResults results = new FilterResults(); + + if (mOriginalValues == null) { + synchronized (mLock) { + mOriginalValues = new ArrayList(mObjects); + } + } + + if (prefix == null || prefix.length() == 0) { + ArrayList list; + synchronized (mLock) { + list = new ArrayList(mOriginalValues); + } + results.values = list; + results.count = list.size(); + } else { + String prefixString = prefix.toString().toLowerCase(); + + ArrayList values; + synchronized (mLock) { + values = new ArrayList(mOriginalValues); + } + + final int count = values.size(); + final ArrayList newValues = new ArrayList(); + + 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) results.values; + if (results.count > 0) { + notifyDataSetChanged(); + } else { + notifyDataSetInvalidated(); + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/commit451/gitlab/dialog/AccessDialog.java b/app/src/main/java/com/commit451/gitlab/dialog/AccessDialog.java index e307f05193296133be99d564f4ac8697e6d740ba..dc64ad4186c2efe2ba73b320f45a5f41edd8341b 100644 --- a/app/src/main/java/com/commit451/gitlab/dialog/AccessDialog.java +++ b/app/src/main/java/com/commit451/gitlab/dialog/AccessDialog.java @@ -8,12 +8,18 @@ import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Toast; +import com.afollestad.appthemeengine.ATE; +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; import com.commit451.gitlab.R; import com.commit451.gitlab.adapter.AccessAdapter; 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.Member; +import com.commit451.gitlab.util.AppThemeUtil; + +import java.util.Arrays; import butterknife.Bind; import butterknife.ButterKnife; @@ -24,16 +30,10 @@ import timber.log.Timber; /** * Change a users access level, either for a group or for a project */ -public class AccessDialog extends AppCompatDialog { - - @Bind(R.id.list) RecyclerView mRecyclerView; - AccessAdapter mAdapter; - @Bind(R.id.progress) View mProgress; - @Bind(R.id.content_root) View mContentRoot; +public class AccessDialog extends MaterialDialog { - @OnClick(R.id.apply) void onApply() { - String accessLevel = mAdapter.getSelectedValue(); + String accessLevel = mRoleNames[getSelectedIndex()]; if (accessLevel == null) { Toast.makeText(getContext(), R.string.please_select_access_level, Toast.LENGTH_LONG) .show(); @@ -42,7 +42,6 @@ public class AccessDialog extends AppCompatDialog { } } - @OnClick(R.id.cancel_button) void onCancel() { dismiss(); } @@ -51,7 +50,6 @@ public class AccessDialog extends AppCompatDialog { OnAccessAppliedListener mAccessAppliedListener; String[] mRoleNames; - String[] mRoleValues; long mProjectId = -1; Group mGroup; Member mMember; @@ -60,7 +58,7 @@ public class AccessDialog extends AppCompatDialog { @Override public void onResponse(@NonNull Member response) { if (mAccessChangedListener != null) { - mAccessChangedListener.onAccessChanged(mMember, mAdapter.getSelectedValue()); + mAccessChangedListener.onAccessChanged(mMember, mRoleNames[getSelectedIndex()]); } dismiss(); } @@ -86,25 +84,39 @@ public class AccessDialog extends AppCompatDialog { } private AccessDialog(Context context, Member member, Group group, long projectId) { - super(context); - setContentView(R.layout.dialog_access); - ButterKnife.bind(this); + super(new MaterialDialog.Builder(context) + .items((group == null) ? R.array.project_role_names : R.array.group_role_names) + .itemsCallbackSingleChoice(-1, new ListCallbackSingleChoice() { + @Override + public boolean onSelection(MaterialDialog materialDialog, View view, int i, CharSequence charSequence) { + return true; + } + }) + .progress(true, 0) // So we can later show loading progress + .positiveText(R.string.action_apply) + .negativeText(R.string.md_cancel_label)); + mRoleNames = getContext().getResources().getStringArray((group == null) + ? R.array.project_role_names + : R.array.group_role_names); + getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + onApply(); + } + }); + getActionButton(DialogAction.NEGATIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + onCancel(); + } + }); mMember = member; - if (group == null) { - mRoleValues = getContext().getResources().getStringArray(R.array.project_role_values); - mRoleNames = getContext().getResources().getStringArray(R.array.project_role_names); - } else { - mRoleValues = getContext().getResources().getStringArray(R.array.group_role_values); - mRoleNames = getContext().getResources().getStringArray(R.array.group_role_names); - } mGroup = group; mProjectId = projectId; - mAdapter = new AccessAdapter(getContext(), mRoleNames); if (mMember != null) { - mAdapter.setSelectedAccess(Member.getAccessLevel(mMember.getAccessLevel())); + setSelectedIndex(Arrays.asList(mRoleNames).indexOf( + Member.getAccessLevel(mMember.getAccessLevel()))); } - mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - mRecyclerView.setAdapter(mAdapter); } private void changeAccess(int accessLevel) { @@ -123,8 +135,7 @@ public class AccessDialog extends AppCompatDialog { } public void showLoading() { - mContentRoot.animate().alpha(0.0f); - mProgress.setVisibility(View.VISIBLE); + getActionButton(DialogAction.POSITIVE).setEnabled(false); } private void onError() { diff --git a/app/src/main/java/com/commit451/gitlab/fragment/BaseFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/BaseFragment.java index 94fe465ce79924c7fa68cc0d721b19aee85b5747..661fb8933ac129fd6392a9e1c918e7574ed60be1 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/BaseFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/BaseFragment.java @@ -1,7 +1,9 @@ package com.commit451.gitlab.fragment; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.event.ReloadDataEvent; +import com.commit451.gitlab.util.AppThemeUtil; import com.squareup.otto.Subscribe; import android.os.Bundle; diff --git a/app/src/main/java/com/commit451/gitlab/fragment/CommitsFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/CommitsFragment.java index 89f2919353bc4ee4e382a31b77665f5a98bfc03c..e9665c6291dcb6a9d555d22b719ad562451b934c 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/CommitsFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/CommitsFragment.java @@ -15,6 +15,7 @@ import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.activity.ProjectActivity; import com.commit451.gitlab.adapter.CommitsAdapter; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.event.ProjectReloadEvent; @@ -139,6 +140,7 @@ public class CommitsFragment extends BaseFragment { mCommitsAdapter = new CommitsAdapter(mCommitsAdapterListener); mCommitsLayoutManager = new LinearLayoutManager(getActivity()); mCommitsListView.setLayoutManager(mCommitsLayoutManager); + mCommitsListView.addItemDecoration(new DividerItemDecoration(getActivity())); mCommitsListView.setAdapter(mCommitsAdapter); mCommitsListView.addOnScrollListener(mOnScrollListener); diff --git a/app/src/main/java/com/commit451/gitlab/fragment/FeedFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/FeedFragment.java index 36a097ba08b5d4a423c7afafb5888f200b36960d..c592e107f5ddeda6ed1896d5e5459e5d86142cfa 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/FeedFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/FeedFragment.java @@ -13,6 +13,7 @@ import android.widget.TextView; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.FeedAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -107,6 +108,7 @@ public class FeedFragment extends BaseFragment { mFeedAdapter = new FeedAdapter(mFeedAdapterListener); mEntryListView.setLayoutManager(new LinearLayoutManager(getActivity())); + mEntryListView.addItemDecoration(new DividerItemDecoration(getActivity())); mEntryListView.setAdapter(mFeedAdapter); mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { diff --git a/app/src/main/java/com/commit451/gitlab/fragment/FilesFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/FilesFragment.java index 0d30d68bfc391b61aa3f57500db26726c0b9e3e5..314a2a543c5966f7d74f43e2d49259e7413eb461 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/FilesFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/FilesFragment.java @@ -19,6 +19,7 @@ import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.activity.ProjectActivity; import com.commit451.gitlab.adapter.BreadcrumbAdapter; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.FilesAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -146,6 +147,7 @@ public class FilesFragment extends BaseFragment { mFilesAdapter = new FilesAdapter(mFilesAdapterListener); mFilesListView.setLayoutManager(new LinearLayoutManager(getActivity())); + mFilesListView.addItemDecoration(new DividerItemDecoration(getActivity())); mFilesListView.setAdapter(mFilesAdapter); mBreadcrumbAdapter = new BreadcrumbAdapter(); diff --git a/app/src/main/java/com/commit451/gitlab/fragment/IssuesFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/IssuesFragment.java index 2cae412d2b31e57a784e3a55e04ef6cc279f08d7..936ad82d0884e1e9bedf5e5d3edea0389ace24ce 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/IssuesFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/IssuesFragment.java @@ -18,6 +18,7 @@ import android.widget.TextView; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.activity.ProjectActivity; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.IssuesAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -175,6 +176,7 @@ public class IssuesFragment extends BaseFragment { mIssuesAdapter = new IssuesAdapter(mIssuesAdapterListener); mIssuesLayoutManager = new LinearLayoutManager(getActivity()); mIssueListView.setLayoutManager(mIssuesLayoutManager); + mIssueListView.addItemDecoration(new DividerItemDecoration(getActivity())); mIssueListView.setAdapter(mIssuesAdapter); mIssueListView.addOnScrollListener(mOnScrollListener); diff --git a/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestCommitsFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestCommitsFragment.java index b30232dc54a0b8bf94781c8d9e743e6ee62451a4..a29cfc91e433fd7dc6aa5dfa7f8b83a84e7e7da1 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestCommitsFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestCommitsFragment.java @@ -13,6 +13,7 @@ import android.widget.TextView; import com.commit451.gitlab.R; import com.commit451.gitlab.adapter.CommitsAdapter; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.MergeRequest; @@ -152,6 +153,7 @@ public class MergeRequestCommitsFragment extends BaseFragment { mCommitsAdapter = new CommitsAdapter(mCommitsAdapterListener); mCommitsLayoutManager = new LinearLayoutManager(getActivity()); mCommitsListView.setLayoutManager(mCommitsLayoutManager); + mCommitsListView.addItemDecoration(new DividerItemDecoration(getActivity())); mCommitsListView.setAdapter(mCommitsAdapter); mCommitsListView.addOnScrollListener(mOnScrollListener); diff --git a/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestsFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestsFragment.java index b595e1924fb32dffbb80d68d763f28730c74e2ee..8a26d1ca8b90b101a3a07ed574ddda1cf8a1e9e7 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestsFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/MergeRequestsFragment.java @@ -17,6 +17,7 @@ import android.widget.TextView; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.activity.ProjectActivity; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.MergeRequestAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -158,6 +159,7 @@ public class MergeRequestsFragment extends BaseFragment { mMergeRequestAdapter = new MergeRequestAdapter(mMergeRequestAdapterListener); mMergeLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mMergeLayoutManager); + mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity())); mRecyclerView.setAdapter(mMergeRequestAdapter); mRecyclerView.addOnScrollListener(mOnScrollListener); diff --git a/app/src/main/java/com/commit451/gitlab/fragment/MilestonesFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/MilestonesFragment.java index b4e90484629287a5da87e02b21f5ba33d7451160..f74b39842dd8d46fb2cd31184b12fbd5e3fa6cc6 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/MilestonesFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/MilestonesFragment.java @@ -18,6 +18,7 @@ import android.widget.TextView; import com.commit451.gitlab.LabCoatApp; import com.commit451.gitlab.R; import com.commit451.gitlab.activity.ProjectActivity; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.MilestoneAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -179,6 +180,7 @@ public class MilestonesFragment extends BaseFragment { mMilestoneAdapter = new MilestoneAdapter(mMilestoneListener); mMilestoneLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mMilestoneLayoutManager); + mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity())); mRecyclerView.setAdapter(mMilestoneAdapter); mRecyclerView.addOnScrollListener(mOnScrollListener); diff --git a/app/src/main/java/com/commit451/gitlab/fragment/ProjectsFragment.java b/app/src/main/java/com/commit451/gitlab/fragment/ProjectsFragment.java index 07b7cfb9e89e02ff53b54dec9c621c4a80768aea..7706f7c354e12b5f17a4ca982100d2538fc5a7e0 100644 --- a/app/src/main/java/com/commit451/gitlab/fragment/ProjectsFragment.java +++ b/app/src/main/java/com/commit451/gitlab/fragment/ProjectsFragment.java @@ -12,6 +12,7 @@ import android.view.ViewGroup; import android.widget.TextView; import com.commit451.gitlab.R; +import com.commit451.gitlab.adapter.DividerItemDecoration; import com.commit451.gitlab.adapter.ProjectsAdapter; import com.commit451.gitlab.api.EasyCallback; import com.commit451.gitlab.api.GitLabClient; @@ -177,6 +178,7 @@ public class ProjectsFragment extends BaseFragment { mProjectsAdapter = new ProjectsAdapter(getActivity(), mProjectsListener); mLayoutManager = new LinearLayoutManager(getActivity()); mProjectsListView.setLayoutManager(mLayoutManager); + mProjectsListView.addItemDecoration(new DividerItemDecoration(getActivity())); mProjectsListView.setAdapter(mProjectsAdapter); mProjectsListView.addOnScrollListener(mOnScrollListener); diff --git a/app/src/main/java/com/commit451/gitlab/util/AppThemeUtil.java b/app/src/main/java/com/commit451/gitlab/util/AppThemeUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..c94f8ef402f4f2005f34a1ad145bc166e624c0ab --- /dev/null +++ b/app/src/main/java/com/commit451/gitlab/util/AppThemeUtil.java @@ -0,0 +1,48 @@ +package com.commit451.gitlab.util; + +import android.content.Context; +import android.util.TypedValue; + +import com.afollestad.appthemeengine.ATE; +import com.afollestad.appthemeengine.Config; +import com.commit451.gitlab.R; + +public class AppThemeUtil { + + public static void setupDefaultConfigs(Context context) { + if (!ATE.config(context, "light_theme").isConfigured(0)) { + ATE.config(context, "light_theme") + .activityTheme(R.style.AppThemeLight) + .primaryColorRes(R.color.primary_default) + .accentColorRes(R.color.accent_default) + .coloredNavigationBar(false) + .commit(); + } + if (!ATE.config(context, "dark_theme").isConfigured(0)) { + ATE.config(context, "dark_theme") + .activityTheme(R.style.AppTheme) + .primaryColorRes(R.color.primary_default) + .accentColorRes(R.color.accent_default) + .coloredNavigationBar(true) + .commit(); + } + } + + public static String resolveThemeKey(Context context) { + TypedValue typedValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.ate_key, typedValue, true); + return (String) typedValue.coerceToString(); + } + + public static int resolvePrimaryColor(Context context) { + return Config.primaryColor(context, resolveThemeKey(context)); + } + + public static int resolvePrimaryColorDark(Context context) { + return Config.primaryColorDark(context, resolveThemeKey(context)); + } + + public static int resolveAccentColor(Context context) { + return Config.accentColor(context, resolveThemeKey(context)); + } +} diff --git a/app/src/main/java/com/commit451/gitlab/util/IntentUtil.java b/app/src/main/java/com/commit451/gitlab/util/IntentUtil.java index 527fba45550e7fd4ddd6cb88cb494d5e73ddb769..b817ff509a4bb3047cd6e3fc6c58fc8047514a94 100644 --- a/app/src/main/java/com/commit451/gitlab/util/IntentUtil.java +++ b/app/src/main/java/com/commit451/gitlab/util/IntentUtil.java @@ -9,6 +9,7 @@ import android.support.design.widget.Snackbar; import android.text.TextUtils; import android.view.View; +import com.afollestad.appthemeengine.Config; import com.commit451.easel.Easel; import com.commit451.gitlab.R; import com.commit451.gitlab.customtabs.BrowserFallback; @@ -26,7 +27,7 @@ public class IntentUtil { } CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder(); - intentBuilder.setToolbarColor(Easel.getThemeAttrColor(activity, R.attr.colorPrimary)); + intentBuilder.setToolbarColor(Config.primaryColor(activity, AppThemeUtil.resolveThemeKey(activity))); intentBuilder.setStartAnimations(activity, R.anim.fade_in, R.anim.do_nothing); intentBuilder.setExitAnimations(activity, R.anim.do_nothing, R.anim.fade_out); CustomTabsActivityHelper.openCustomTab(activity, intentBuilder.build(), Uri.parse(url), new BrowserFallback()); diff --git a/app/src/main/java/com/commit451/gitlab/util/NavigationManager.java b/app/src/main/java/com/commit451/gitlab/util/NavigationManager.java index f877f3cc2aab70583347e5c4df725e042bfc1a82..f61f456a09dfd9f4d5839f0aade66fca6da3ad4b 100644 --- a/app/src/main/java/com/commit451/gitlab/util/NavigationManager.java +++ b/app/src/main/java/com/commit451/gitlab/util/NavigationManager.java @@ -25,6 +25,7 @@ import com.commit451.gitlab.activity.MilestoneActivity; import com.commit451.gitlab.activity.ProjectActivity; import com.commit451.gitlab.activity.ProjectsActivity; import com.commit451.gitlab.activity.SearchActivity; +import com.commit451.gitlab.activity.SettingsActivity; import com.commit451.gitlab.activity.UserActivity; import com.commit451.gitlab.model.Account; import com.commit451.gitlab.model.api.Group; @@ -47,6 +48,10 @@ public class NavigationManager { activity.startActivity(AboutActivity.newInstance(activity)); } + public static void navigateToSettings(Activity activity) { + activity.startActivity(SettingsActivity.newInstance(activity)); + } + public static void navigateToProject(Activity activity, Project project) { activity.startActivity(ProjectActivity.newInstance(activity, project)); } diff --git a/app/src/main/java/com/commit451/gitlab/view/GitLabCardView.java b/app/src/main/java/com/commit451/gitlab/view/GitLabCardView.java new file mode 100644 index 0000000000000000000000000000000000000000..e8233f4ad1c54aa8913bb82a31087732fb9c8156 --- /dev/null +++ b/app/src/main/java/com/commit451/gitlab/view/GitLabCardView.java @@ -0,0 +1,54 @@ +package com.commit451.gitlab.view; + +import android.content.Context; +import android.graphics.Rect; +import android.os.Build; +import android.support.v7.widget.CardView; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +public class GitLabCardView extends CardView { + + private boolean mAreMarginsAdjusted = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + private Rect mShadowPadding; + + public GitLabCardView(Context context) { + super(context); + } + + public GitLabCardView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public GitLabCardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + /** + * This makes sure that the CardView looks correct on pre-Lollipop devices + */ + @Override + public void setShadowPadding(int left, int top, int right, int bottom) { + super.setShadowPadding(left, top, right, bottom); + mShadowPadding = new Rect(left, top, right, bottom); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Update the margins to clip the outer border on pre-Lollipop devices + if (!mAreMarginsAdjusted) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec) + + mShadowPadding.left + mShadowPadding.right, MeasureSpec.getMode(widthMeasureSpec)); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) + + mShadowPadding.top + mShadowPadding.bottom, MeasureSpec.getMode(heightMeasureSpec)); + MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); + params.setMargins(params.leftMargin - mShadowPadding.left, + params.topMargin - mShadowPadding.top, + params.rightMargin - mShadowPadding.right, + params.bottomMargin - mShadowPadding.bottom); + requestLayout(); + mAreMarginsAdjusted = true; + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/app/src/main/java/com/commit451/gitlab/view/GitLabNavigationView.java b/app/src/main/java/com/commit451/gitlab/view/GitLabNavigationView.java index 284a3c9ccc352e11ea841e1c99ae9fe4a4dfc490..991363a408ec5a31c73e113ffa5c8fd25c17306d 100644 --- a/app/src/main/java/com/commit451/gitlab/view/GitLabNavigationView.java +++ b/app/src/main/java/com/commit451/gitlab/view/GitLabNavigationView.java @@ -82,6 +82,10 @@ public class GitLabNavigationView extends NavigationView { } LabCoatApp.bus().post(new CloseDrawerEvent()); return true; + case R.id.nav_settings: + LabCoatApp.bus().post(new CloseDrawerEvent()); + NavigationManager.navigateToSettings((Activity) getContext()); + return true; case R.id.nav_about: LabCoatApp.bus().post(new CloseDrawerEvent()); NavigationManager.navigateToAbout((Activity) getContext()); @@ -178,7 +182,7 @@ public class GitLabNavigationView extends NavigationView { mAccountList.setLayoutManager(new LinearLayoutManager(getContext())); addView(mAccountList); LayoutParams params = (FrameLayout.LayoutParams) mAccountList.getLayoutParams(); - params.setMargins(0, getResources().getDimensionPixelSize(R.dimen.navigation_drawer_header_height), 0, 0); + params.setMargins(0, getResources().getDimensionPixelSize(R.dimen.account_header_height), 0, 0); mAccountList.setBackgroundColor(colorPrimary); mAccountList.setVisibility(View.GONE); mAccountAdapter = new AccountsAdapter(getContext(), mAccountsAdapterListener); diff --git a/app/src/main/java/com/commit451/gitlab/view/GitLabProgressView.java b/app/src/main/java/com/commit451/gitlab/view/GitLabProgressView.java new file mode 100644 index 0000000000000000000000000000000000000000..422299ab76032913d4561e9dfd04451f2d8ff845 --- /dev/null +++ b/app/src/main/java/com/commit451/gitlab/view/GitLabProgressView.java @@ -0,0 +1,29 @@ +package com.commit451.gitlab.view; + +import android.content.Context; +import android.preference.PreferenceManager; +import android.util.AttributeSet; + +import com.afollestad.appthemeengine.Config; +import com.commit451.gitlab.util.AppThemeUtil; +import com.pnikosis.materialishprogress.ProgressWheel; + +/** + * A subclass of ProgressWheel that automagically themes itself to the accent color + */ +public class GitLabProgressView extends ProgressWheel { + + public GitLabProgressView(Context context) { + super(context); + init(); + } + + public GitLabProgressView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + setBarColor(Config.accentColor(getContext(), AppThemeUtil.resolveThemeKey(getContext()))); + } +} diff --git a/app/src/main/java/com/commit451/gitlab/view/GitLabSwipeRefreshLayout.java b/app/src/main/java/com/commit451/gitlab/view/GitLabSwipeRefreshLayout.java index e69e2a252569662cfdf1db556a9005b5674e9025..9dcc887e2aaeac5694ae01d312308ee24f07d081 100644 --- a/app/src/main/java/com/commit451/gitlab/view/GitLabSwipeRefreshLayout.java +++ b/app/src/main/java/com/commit451/gitlab/view/GitLabSwipeRefreshLayout.java @@ -4,7 +4,9 @@ import android.content.Context; import android.support.v4.widget.SwipeRefreshLayout; import android.util.AttributeSet; +import com.afollestad.appthemeengine.Config; import com.commit451.gitlab.R; +import com.commit451.gitlab.util.AppThemeUtil; /** @@ -24,6 +26,8 @@ public class GitLabSwipeRefreshLayout extends SwipeRefreshLayout { } private void init() { - setColorSchemeResources(R.color.red, R.color.orange, R.color.yellow); + int accentColor = Config.accentColor(getContext(), + AppThemeUtil.resolveThemeKey(getContext())); + setColorSchemeColors(accentColor, accentColor, accentColor); } } diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/AccessViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/AccessViewHolder.java index 31566824f4052a5ecce292036cf7d719745c7d88..8868fc8a991e09730f345623d8256c34aeb2d0e0 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/AccessViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/AccessViewHolder.java @@ -8,7 +8,9 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/AccountFooterViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/AccountFooterViewHolder.java index 5a16231bc886a1060b43c95b6a418476324600f2..29ba0fb9a3c383a4101ab8442e9e3b884b28a0a1 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/AccountFooterViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/AccountFooterViewHolder.java @@ -5,7 +5,9 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/AccountViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/AccountViewHolder.java index 8cccf80325df4c24e280d1f909b00fa9df579ddc..7db0315924b3990dccc22cc58b12043539dc0d49 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/AccountViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/AccountViewHolder.java @@ -8,10 +8,12 @@ import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.Account; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.ImageUtil; import butterknife.Bind; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/AssigneeSpinnerViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/AssigneeSpinnerViewHolder.java index da6d31217280b9451fc08e7728be3e841d5a61d7..4f4e1d4582208d5aa7c94e9c88652f923780a42f 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/AssigneeSpinnerViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/AssigneeSpinnerViewHolder.java @@ -1,5 +1,6 @@ package com.commit451.gitlab.viewHolder; +import android.graphics.PorterDuff; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -8,10 +9,13 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; +import com.afollestad.appthemeengine.Config; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Member; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.ImageUtil; import butterknife.Bind; @@ -42,6 +46,9 @@ public class AssigneeSpinnerViewHolder extends RecyclerView.ViewHolder { if (user == null) { mUsernameView.setText(R.string.no_assignee); mImageView.setImageResource(R.drawable.ic_assign_24dp); + mImageView.getDrawable().setColorFilter(Config.textColorPrimary( + mImageView.getContext(), AppThemeUtil.resolveThemeKey(mImageView.getContext())), + PorterDuff.Mode.SRC_IN); } else { mUsernameView.setText(user.getUsername()); GitLabClient.getPicasso() diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/BreadcrumbViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/BreadcrumbViewHolder.java index 3fa614a24f86768827e42ea6bc0577d1382262d8..8ab4289a4e2c341d635b006d1a95389be1a18100 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/BreadcrumbViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/BreadcrumbViewHolder.java @@ -1,6 +1,7 @@ package com.commit451.gitlab.viewHolder; -import android.support.v4.content.ContextCompat; +import android.graphics.Color; +import android.graphics.PorterDuff; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -8,7 +9,10 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.Config; +import com.afollestad.appthemeengine.util.ATEUtil; import com.commit451.gitlab.R; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; @@ -27,18 +31,26 @@ public class BreadcrumbViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.breadcrumb_text) TextView mTextView; @Bind(R.id.breadcrumb_arrow) ImageView mArrowView; + private int mPrimaryTextColor; + private int mSecondaryTextColor; + public BreadcrumbViewHolder(View view) { super(view); ButterKnife.bind(this, view); + mPrimaryTextColor = ATEUtil.isColorLight(Config.primaryColor(view.getContext(), + AppThemeUtil.resolveThemeKey(view.getContext()))) ? Color.BLACK : Color.WHITE; + mSecondaryTextColor = ATEUtil.adjustAlpha(mPrimaryTextColor, 0.5f); + // We need to tint arrow based on text color + mArrowView.setColorFilter(mSecondaryTextColor, PorterDuff.Mode.SRC_IN); } public void bind(String breadcrumb, boolean showArrow) { mTextView.setText(breadcrumb); if (showArrow) { - mTextView.setTextColor(ContextCompat.getColor(itemView.getContext(), R.color.white_60)); + mTextView.setTextColor(mSecondaryTextColor); mArrowView.setVisibility(View.VISIBLE); } else { - mTextView.setTextColor(ContextCompat.getColor(itemView.getContext(), R.color.white)); + mTextView.setTextColor(mPrimaryTextColor); mArrowView.setVisibility(View.GONE); } } diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/CommitViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/CommitViewHolder.java index 4f8e24a7f371428dd871980ff659f87b3dcba144..c157df421c096b08ceced0d5cc5b0c5af57668cb 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/CommitViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/CommitViewHolder.java @@ -7,10 +7,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.RepositoryCommit; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import com.commit451.gitlab.util.ImageUtil; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/DiffHeaderViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/DiffHeaderViewHolder.java index cd2a4aee1e9700132f477a8b59aea1d9252c4da6..d973d4f769cf7cea03afbc690ef99a6ca4d56816 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/DiffHeaderViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/DiffHeaderViewHolder.java @@ -4,10 +4,15 @@ import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import com.commit451.gitlab.R; +import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.RepositoryCommit; +import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.DateUtils; +import com.commit451.gitlab.util.ImageUtil; import butterknife.Bind; import butterknife.ButterKnife; @@ -23,7 +28,11 @@ public class DiffHeaderViewHolder extends RecyclerView.ViewHolder { return new DiffHeaderViewHolder(view); } - @Bind(R.id.title) TextView mTitle; + @Bind(R.id.commit_author_image) ImageView mImageView; + @Bind(R.id.commit_author) TextView mAuthorView; + @Bind(R.id.commit_time) TextView mTimeView; + @Bind(R.id.commit_title) TextView mTitleView; + @Bind(R.id.commit_message) TextView mMessageView; public DiffHeaderViewHolder(View view) { super(view); @@ -31,6 +40,26 @@ public class DiffHeaderViewHolder extends RecyclerView.ViewHolder { } public void bind(RepositoryCommit commit) { - mTitle.setText(commit.getTitle()); + GitLabClient.getPicasso() + .load(ImageUtil.getAvatarUrl(commit.getAuthorEmail(), itemView.getResources().getDimensionPixelSize(R.dimen.image_size))) + .transform(new CircleTransformation()) + .into(mImageView); + + mAuthorView.setText(commit.getAuthorName()); + mTimeView.setText(DateUtils.getRelativeTimeSpanString(itemView.getContext(), commit.getCreatedAt())); + mTitleView.setText(commit.getTitle()); + String message = extractMessage(commit.getTitle(), commit.getMessage()); + mMessageView.setText(message); + mMessageView.setVisibility(message.isEmpty() ? View.GONE : View.VISIBLE); + } + + /** + * This extracts the trailing part of the title as it is displayed in the GitLab web interface + * (the commit message also contains the commit title) + */ + private String extractMessage(String title, String message) { + boolean ellipsis = title.endsWith("\u2026") && message.charAt(title.length() - 1) != '\u2026'; + String trailing = message.substring(title.length() - (ellipsis ? 1 : 0)); + return trailing.equals("\u2026") ? "" : ((ellipsis ? "\u2026" : "") + trailing).trim(); } } diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/DiffViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/DiffViewHolder.java index 08087a65f3c43e3005146a2ea24185c35d68bba4..8ecd711bd346c3fe0255333667467841fcc7bdf8 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/DiffViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/DiffViewHolder.java @@ -6,9 +6,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.alorma.diff.lib.DiffTextView; import com.commit451.gitlab.R; import com.commit451.gitlab.model.api.Diff; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/FeedEntryViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/FeedEntryViewHolder.java index c0b7009c5f2f83d18a823fe9a2ab179b556e9b0a..81deaf1e8dd95cfd9fe01f9707d9fc8f64919522 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/FeedEntryViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/FeedEntryViewHolder.java @@ -8,10 +8,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.rss.Entry; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/FileViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/FileViewHolder.java index 9b9a9294f4517f73dba1f79115db1f0cc6169280..18dab171f59047b0393e70befcbc73679480204a 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/FileViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/FileViewHolder.java @@ -8,8 +8,10 @@ import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.model.api.RepositoryTreeObject; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/GroupViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/GroupViewHolder.java index 7ff1efca79bf76c524d3acb7641e0ba7b08e4d80..652dbb6f7a28215a68f2dbba84e149e6adf6355b 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/GroupViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/GroupViewHolder.java @@ -8,9 +8,11 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Group; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/IssueHeaderViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/IssueHeaderViewHolder.java index 1be76f221d30b227cce7cead3888dae881a5be84..2f5e27d114bbf97716498b33a27fc239171bc77d 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/IssueHeaderViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/IssueHeaderViewHolder.java @@ -9,10 +9,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Issue; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import com.commit451.gitlab.util.ImageUtil; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/IssueViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/IssueViewHolder.java index f4cc3d58c92037ccf9e8cda6b83c619822e9bc5b..9f223a745e1c497d41e5dea3f465566850408c8f 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/IssueViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/IssueViewHolder.java @@ -7,10 +7,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Issue; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import com.commit451.gitlab.util.ImageUtil; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestHeaderViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestHeaderViewHolder.java index 645f0b747dcd6f42e5f95f8b6bc4a8c9c48c9542..cec761a89b07807bb67678118d38ef299e50f0c4 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestHeaderViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestHeaderViewHolder.java @@ -9,10 +9,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.MergeRequest; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import com.commit451.gitlab.util.ImageUtil; import com.commit451.gitlab.util.PicassoImageGetter; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestViewHolder.java index 98722b8844d60673b7ac2604fe30cab05640f1b0..0ac1daeab9045028e5e69db77a6b394c2587a3f7 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/MergeRequestViewHolder.java @@ -7,10 +7,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.MergeRequest; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.ImageUtil; import butterknife.Bind; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneHeaderViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneHeaderViewHolder.java index 048d4673d88511cb5fd6615f1bcc07e17bc64429..86fab437f18a4ff446716718b26360dd8f6ea956 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneHeaderViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneHeaderViewHolder.java @@ -6,8 +6,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.model.api.Milestone; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import butterknife.Bind; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneSpinnerViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneSpinnerViewHolder.java index 8154a4ef31769f7b71246ec5389e17f0f331d88e..c4baf79f99f8708ceba7df83c121351247ee56be 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneSpinnerViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneSpinnerViewHolder.java @@ -7,8 +7,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.model.api.Milestone; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneViewHolder.java index 86fdbd7d8998172c5057d0e7993dad8751df2a58..f9e11e4a423b9b2df4ab2ca34d4d064bf81df8fb 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/MilestoneViewHolder.java @@ -6,8 +6,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.model.api.Milestone; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import butterknife.Bind; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/NoteViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/NoteViewHolder.java index f0b25c53ff2872f3a71423acc8a49225c60d92a3..823ca6e6d42e93946227717f0c77edbaecf623da 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/NoteViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/NoteViewHolder.java @@ -8,10 +8,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Note; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.DateUtils; import com.commit451.gitlab.util.ImageUtil; import com.commit451.gitlab.util.PicassoImageGetter; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberFooterViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberFooterViewHolder.java index 021351518df8dc90617094629957de092b24e952..5b7206742b0a439f37a0aa5385996c026f3c6ad0 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberFooterViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberFooterViewHolder.java @@ -6,8 +6,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.model.api.ProjectNamespace; +import com.commit451.gitlab.util.AppThemeUtil; import butterknife.Bind; import butterknife.ButterKnife; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberViewHolder.java index 818cf7c3c6608769ac9b0fc227eb865186615ed9..77c572dc695e67fafcb67c20b059d9c2c26813c5 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectMemberViewHolder.java @@ -8,9 +8,11 @@ import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Member; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.ImageUtil; import butterknife.Bind; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectViewHolder.java index 204d417d126742d2dd22e89f40356957d1a1d3f7..33c76d7f56d1b33069dfcf3ca7fbd04d32830a10 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/ProjectViewHolder.java @@ -10,10 +10,12 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.Project; import com.commit451.gitlab.transformation.CircleTransformation; +import com.commit451.gitlab.util.AppThemeUtil; import com.github.ivbaranov.mli.MaterialLetterIcon; import butterknife.Bind; diff --git a/app/src/main/java/com/commit451/gitlab/viewHolder/UserViewHolder.java b/app/src/main/java/com/commit451/gitlab/viewHolder/UserViewHolder.java index 082f2d3425a1df1ce2bd9ac63345ee2858f69e09..737edb359412364f9933fdeda039b89f5729ff58 100644 --- a/app/src/main/java/com/commit451/gitlab/viewHolder/UserViewHolder.java +++ b/app/src/main/java/com/commit451/gitlab/viewHolder/UserViewHolder.java @@ -7,9 +7,11 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.appthemeengine.ATE; import com.commit451.gitlab.R; import com.commit451.gitlab.api.GitLabClient; import com.commit451.gitlab.model.api.UserBasic; +import com.commit451.gitlab.util.AppThemeUtil; import com.commit451.gitlab.util.ImageUtil; import butterknife.Bind; diff --git a/app/src/main/res/drawable/ic_settings_24dp.xml b/app/src/main/res/drawable/ic_settings_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..c8802a0998da0d38414511423ca4be20c18e1e44 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 943ab1935cd43e6aa201b8c8424c03bd13d26e10..1322f83b613f0af374b37312b2f2b8243344511d 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -15,18 +15,7 @@ - - - - + android:layout_height="?attr/actionBarSize" /> diff --git a/app/src/main/res/layout/activity_add_issue.xml b/app/src/main/res/layout/activity_add_issue.xml index 7363fd416de22d6f41cc79bf1e054d6788eb7035..b40826be2ff7375155c94f2b41b8553a145c6f13 100644 --- a/app/src/main/res/layout/activity_add_issue.xml +++ b/app/src/main/res/layout/activity_add_issue.xml @@ -17,15 +17,14 @@ + android:layout_height="?attr/actionBarSize"/> @@ -111,6 +111,7 @@ android:id="@+id/milestone_spinner" android:layout_width="match_parent" android:layout_height="wrap_content" + android:tag="tint|primary_text" android:visibility="gone"/> diff --git a/app/src/main/res/layout/activity_add_milestone.xml b/app/src/main/res/layout/activity_add_milestone.xml index 92d2be78cd93a1769927cf6e9e198f429f1bc504..219119dc306daf47ed512e592d07f5b295bcc803 100644 --- a/app/src/main/res/layout/activity_add_milestone.xml +++ b/app/src/main/res/layout/activity_add_milestone.xml @@ -17,15 +17,14 @@ + android:layout_height="?attr/actionBarSize"/> + android:layout_height="?attr/actionBarSize"> + android:layout_height="?attr/actionBarSize" /> diff --git a/app/src/main/res/layout/activity_file.xml b/app/src/main/res/layout/activity_file.xml index 8799a3c940427bfe3b33daf6a27706a951567b4a..ed073b12dd534bac60bb7f36c9644b92164be019 100644 --- a/app/src/main/res/layout/activity_file.xml +++ b/app/src/main/res/layout/activity_file.xml @@ -15,8 +15,7 @@ + android:layout_height="?attr/actionBarSize" /> diff --git a/app/src/main/res/layout/activity_group.xml b/app/src/main/res/layout/activity_group.xml index 3bcedec7616d2a29acdc5e66abab3b1122033968..50a0ba8ea220dffbcf7037e33fe81fa440e5b775 100644 --- a/app/src/main/res/layout/activity_group.xml +++ b/app/src/main/res/layout/activity_group.xml @@ -11,14 +11,14 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> + android:theme="@style/ThemeOverlay.AppCompat.Dark"> @@ -44,8 +45,10 @@ diff --git a/app/src/main/res/layout/activity_groups.xml b/app/src/main/res/layout/activity_groups.xml index 86a385e98e4d218fe06fd4f772c2723f363b9900..fc50cece6e7a3c300073128412d17446819aa844 100644 --- a/app/src/main/res/layout/activity_groups.xml +++ b/app/src/main/res/layout/activity_groups.xml @@ -21,8 +21,7 @@ + android:layout_height="?attr/actionBarSize" /> @@ -63,7 +62,6 @@ android:layout_height="match_parent" android:layout_gravity="start" android:clickable="true" - android:fitsSystemWindows="true" - /> + android:fitsSystemWindows="true" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_issue.xml b/app/src/main/res/layout/activity_issue.xml index 66e0c97928aec56ab3028093074fc2191b37ebf5..10315d96e8a78836299ca846aa71d55de7efcead 100644 --- a/app/src/main/res/layout/activity_issue.xml +++ b/app/src/main/res/layout/activity_issue.xml @@ -20,8 +20,7 @@ + android:layout_height="?attr/actionBarSize" /> @@ -55,6 +55,7 @@ android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_edit_24dp" + android:tag="tint_selector|accent_color" app:fabSize="mini" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end"/> diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index b3aa8e10f5d46d698742ae977d6281ab055841b8..0fa26f3cc6f95dca613258de731faaefe8b7e2d8 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -1,27 +1,26 @@ - + android:tag="background|primary_color"> + android:layout_marginRight="@dimen/activity_horizontal_margin" + android:orientation="vertical"> + android:inputType="textUri" + android:tag="tint|primary_color_dependent,text_color|primary_color_dependent,text_color_hint|primary_color_dependent" + android:text="@string/url_gitlab"> @@ -48,38 +48,40 @@ android:layout_height="wrap_content" android:orientation="vertical"> - - - - - - - - - + + + + + + - - + android:layout_height="wrap_content"> + + + + - - - - + android:layout_height="wrap_content"> + + + + android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -122,15 +125,15 @@ android:id="@+id/login_button" android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="@dimen/padding_normal" android:layout_gravity="bottom" + android:background="?attr/selectableItemBackground" android:gravity="center_horizontal" - android:textColor="?attr/colorAccent" + android:padding="@dimen/padding_normal" + android:tag="text_color|accent_color" android:text="@string/login_button" android:textAllCaps="true" - app:typeface="roboto_medium" - android:background="?attr/selectableItemBackground"/> + app:typeface="roboto_medium" /> - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_merge_request.xml b/app/src/main/res/layout/activity_merge_request.xml index a48bd7cd87bcf4d7fac8f0c10be875df9de123fe..f735d50c27086441a307237f68328e0d6fa9e235 100644 --- a/app/src/main/res/layout/activity_merge_request.xml +++ b/app/src/main/res/layout/activity_merge_request.xml @@ -15,8 +15,7 @@ + android:layout_height="?attr/actionBarSize"/> + android:layout_height="?attr/actionBarSize" /> @@ -53,6 +52,7 @@ android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_edit_24dp" + android:tag="tint_selector|accent_color" app:fabSize="mini" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end"/> @@ -63,7 +63,8 @@ android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_margin="@dimen/padding_normal" - android:src="@drawable/ic_add_24dp" /> + android:src="@drawable/ic_add_24dp" + android:tag="tint_selector|accent_color" /> diff --git a/app/src/main/res/layout/activity_project.xml b/app/src/main/res/layout/activity_project.xml index 4479fbd011cca07f7f64e358dc26c0fb92bb5469..a94d4c74b2e6e943b70d80081e631677895c6bff 100644 --- a/app/src/main/res/layout/activity_project.xml +++ b/app/src/main/res/layout/activity_project.xml @@ -15,13 +15,13 @@ + android:layout_height="?attr/actionBarSize"> diff --git a/app/src/main/res/layout/activity_projects.xml b/app/src/main/res/layout/activity_projects.xml index 4a38c8b26898b0c6ba27056b196bf0b7178e888c..c0368a444634c584ee7ba0f40312b386975c3db7 100644 --- a/app/src/main/res/layout/activity_projects.xml +++ b/app/src/main/res/layout/activity_projects.xml @@ -21,8 +21,7 @@ + android:layout_height="?attr/actionBarSize" /> + android:clickable="true" + android:fitsSystemWindows="true" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 24862c2f0bb7c2e879a2ef6f05e8a7075266e975..ac97b74567613e5a0bb3c4afdf4ff2cd346838d0 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -14,8 +14,7 @@ + android:layout_height="?attr/actionBarSize"> - - - - - - - - - - - - - - - - + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:layout_height="?attr/actionBarSize" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_user.xml b/app/src/main/res/layout/activity_user.xml index f202ceaa8824a1238fb0dcc4c53f4eab573ad288..964cac99e88ac1e85f15117562fd8b524254007d 100644 --- a/app/src/main/res/layout/activity_user.xml +++ b/app/src/main/res/layout/activity_user.xml @@ -11,15 +11,16 @@ android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="@dimen/user_header_image_size" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:theme="@style/ThemeOverlay.AppCompat.Dark"> diff --git a/app/src/main/res/layout/dialog_access.xml b/app/src/main/res/layout/dialog_access.xml index ca846b021fbeaf12ea5074e9e62dafdf36ff455f..bdcf1ddbc30b8da0c626f547b95ef34d876aa38d 100644 --- a/app/src/main/res/layout/dialog_access.xml +++ b/app/src/main/res/layout/dialog_access.xml @@ -28,8 +28,8 @@ android:layout_height="wrap_content" android:layout_weight="1" android:focusable="true" - android:text="@string/cancel_button" - android:textColor="?attr/colorAccent" /> + android:tag="text_color|accent_color" + android:text="@string/cancel_button" />