• This repository has been archived on 08/Dec/2019
  • Stars
    star
    1,999
  • Rank 23,176 (Top 0.5 %)
  • Language
    Kotlin
  • License
    Apache License 2.0
  • Created over 7 years ago
  • Updated over 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

[DEPRECATED]

Aesthetic

/esหˆTHedik/: adjective, concerned with beauty or the appreciation of beauty.

jCenter Build Status Codacy Badge License

You can download an APK of the sample project.


Table of Contents

  1. Gradle Dependency
  2. Integration
  3. Configuration
  4. Attributes
    1. Base Values
    2. Standard Colors
    3. Standard Text Colors
    4. Custom Attributes
  5. Advanced Views
    1. Toolbars
    2. Snackbars
    3. CardViews
    4. TabLayouts
    5. BottomNavigationViews
    6. NavigationViews
    7. SwipeRefreshLayouts
  6. Custom Views and Manual Application
  7. Ignoring Views

Gradle Dependency

Add this to your app module's build.gradle file:

dependencies {
  
  implementation 'com.afollestad:aesthetic:1.0.0-beta05'
}

Integration

Aesthetic is integrated at a per-Activity level. The simplest way is to have your Activities extend AestheticActivity.

class MyActivity : AestheticActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
  }
}

If you don't want to or cannot extend this class, you can manually tell Aesthetic about lifecycle events:

class MyActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    Aesthetic.attach(this)  // MUST come before super.onCreate(...)
    super.onCreate(savedInstanceState)
  }

  override fun onResume() {
    super.onResume()
    Aesthetic.resume(this)
  }

  override fun onPause() {
    Aesthetic.pause(this)
    super.onPause()
  }
}

Configuration

Aesthetic provides a isFirstTime field which returns true until you apply theme configuration at least once.

You can use this to setup defaults on app launch.

class MyActivity : AestheticActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // If we haven't set any defaults, do that now
    if (Aesthetic.isFirstTime) {
        Aesthetic.config {
          ...
        }
    }
  }
}

There are two ways to "configure" Aesthetic, with the config method:

Aesthetic.config {
  colorPrimaryRes(R.color.blue)
  ...
}

Or by chaining the setters and calling apply():

Aesthetic.get()
  .colorPrimaryRes(R.color.blue)
  ...
  .apply() // don't forget apply() with this way

If you are using Java, you cannot use the config method.


Attributes

Attributes are the foundation of this library. They link your UI to dynamically changing colors.

Attributes exist natively on Android, but they are not dynamic - they are rather set in your Activity themes and are pre-determined at compile-time. This library gets around that.

Base Values

Aesthetic.config {
  // Set to false for light themes, true for dark.
  // By default, is based on whether textColorPrimary is light/dark.
  isDark(false)
  
  // Causes an Activity recreate, calls setTheme(Int) on it.
  activityTheme(R.style.MyActivityTheme)
  
  // ON makes status bar icons black, and vice versa. AUTO bases it on 
  // the status bar color, e.g. white -> light mode, black -> normal mode.
  // This has no effect below API 23 (Marshmallow). 
  lightStatusBarMode(AutoSwitchMode.AUTO)
  
  // ON makes navigation bar icons black, and vice versa. AUTO bases it on 
  // the navigation bar color, e.g. white -> light mode, black -> normal mode.
  // This has no effect below API 26 (Oreo).
  lightNavigationBarMode(AutoSwitchMode.AUTO)
}

Standard Colors

Aesthetic.config {
  // ?colorPrimary, used for Toolbars, etc.
  colorPrimaryRes(R.color.blue)
  // ?colorPrimaryDark, used for status bars, etc.
  colorPrimaryDark(R.color.blue)
  // ?colorAccent, used for input fields, buttons, etc.
  colorAccentRes(R.color.blue)
  
  // Defaults to colorPrimaryDark.
  colorStatusBarRes(R.color.blue)
  // Sets to colorPrimaryDark. 
  colorStatusBarAuto() 
  
  // Defaults to the value in your activity theme, or black.
  colorNavigationBarRes(R.color.blue)
  // Sets nav bar color to match ?colorPrimaryDark. 
  // If the color is light and light nav bar mode is disabled, it is forced to black.
  colorNavigationBarAuto()
  
  // Defaults to the value in your activity theme.
  colorWindowBackgroundRes(R.color.blue)
}

The methods which end with Res take a color resource. Remove Res to pass a literal (hardcoded) color integer.


Standard Text Colors

Aesthetic.config {
  // ?android:textColorPrimary
  textColorPrimaryRes(R.color.black)
  // ?android:textColorSecondary
  textColorSecondaryRes(R.color.dark_gray)
  
  // ?android:textColorPrimaryInverse
  textColorPrimaryInverseRes(R.color.white)
  // ?android:textColorSecondaryInverse
  textColorSecondaryInverseRes(R.color.light_gray)
}

The methods which end with Res take a color resource. Remove Res to pass a literal (hardcoded) color integer.


Custom Attributes

All of the "attributes" shown and used in examples above are shown with shortcut methods that assign a color to a specific pre-existing attribute, such as colorPrimary from AndroidX.

You can define custom attributes that are usable in layouts. You can assign colors to theme like you would the predefined attributes above.

First, you need to define the attribute in /values/attrs.xml:

<resources>
  <attr format="color" name="my_custom_attr"/>
</resources>

Then you need to define a default in your Activity's theme so that Android's LayoutInflater can resolve something initially:

<style name="MyActivityTheme" parent="Theme.AppCompat.Light">
  <item name="my_custom_attr">#000000</item>
</style>

You can use this attribute in your layouts:

<TextView
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="Hello, World!"
  android:textColor="?my_custom_attr"
  />

And you can assign dynamic values to it with Aesthetic:

Aesthetic.config {

   attributeRes(R.attr.your_attribute, R.color.blue)
}

The methods which end with Res take a color resource. Remove Res to pass a literal (hardcoded) color integer.


Advanced Views

To make Aesthetic a bit more plug-and-play, and to support views that can't necessarily be color-themed from XML, additional options are available for certain types of views.

Toolbars

Special properties are provided for Toolbar icons (navigation icon, overflow icon, etc.) and the title and subtitle colors, so that they don't have to be paired with textColorPrimary, etc.

Aesthetic.config {

  // Defaults to black or white based on the darkness of ?colorPrimary.
  toolbarIconColorRes(R.color.white)
   
  // Defaults to black or white based on the darkness of ?colorPrimary. 
  toolbarTitleColorRes(R.color.white)
  // Defaults to a faded version of the title color.
  toolbarSubtitleColorRes(R.color.light_gray)
}

You can override these (not including the icon color) at a per-layout basis as well:

<androidx.appcompat.widget.Toolbar
  ...
  android:background="?some_color"
  app:titleTextColor="?some_color"
  app:subtitleTextColor="?some_color"
  />

If you do not manually override background, the Toolbar will automatically default to the value of ?colorPrimary.


Snackbars

Aesthetic.config {
  // The color of the main text on a Snackbar
  snackbarTextColorDefault()
  snackbarTextColorRes(R.color.white)
  
  // The color of the action on a Snackbar, if there is one.
  snackbarActionTextColorRes(R.color.blue)
  
  // The background color of Snackbar.
  snackbarBackgroundColorDefault()
  snackbarBackgroundColorRes(R.color.dark_gray)
}

CardViews

Aesthetic.config {
  // The background of CardViews is different because of the 
  // rounding and elevation. This supports those elements.
  colorCardViewBackgroundRes(R.color.white)
}

TabLayouts

Note: the color of text and icons in tab layouts will match that of Toolbars (using the toolbarIconColor and toolbarTitleColor attributes).

Aesthetic.config {  
  // The selected tab's underline will be the primary color.
  tabLayoutIndicatorMode(ColorMode.PRIMARY)
  // The selected tab's underline will be the accent color.
  tabLayoutIndicatorMode(ColorMode.ACCENT)
  
  // The tab layout's background will be the primary color.
  tabLayoutBackgroundMode(ColorMode.PRIMARY)
  // The tab layout's background will be the accent color.
  tabLayoutBackgroundMode(ColorMode.ACCENT)
}

BottomNavigationViews

Aesthetic.config {
  // The tabs' background will be black or white based on the darkness 
  // of the overall theme.
  bottomNavigationBackgroundMode(BottomNavBgMode.BLACK_WHITE_AUTO)
  // The tabs' background will be the primary color.
  bottomNavigationBackgroundMode(BottomNavBgMode.PRIMARY)
  // The tabs' background will be the dark primary color.
  bottomNavigationBackgroundMode(BottomNavBgMode.PRIMARY_DARK)
  // The tabs' background will be the accent color.
  bottomNavigationBackgroundMode(BottomNavBgMode.ACCENT)
  // This library will not do any automatic background color theming of bottom nav views.
  bottomNavigationBackgroundMode(BottomNavBgMode.NONE)
  
  // The selected tab's icon will be tinted with the primary color.
  bottomNavigationIconTextMode(BottomNavIconTextMode.SELECTED_PRIMARY)
  // The selected tab's icon will be tinted with the accent color. 
  bottomNavigationIconTextMode(BottomNavIconTextMode.SELECTED_ACCENT)
  // The selected tab's icon will be tinted black or white based on 
  // the darkness of the overall theme.
  bottomNavigationIconTextMode(BottomNavIconTextMode.BLACK_WHITE_AUTO)
  // This library will not do any automatic icon/text theming of bottom nav views.
  bottomNavigationIconTextMode(BottomNavBgMode.NONE)
}

NavigationViews

Aesthetic.config {  
  // The selected drawer item will be tinted with the primary color.
  navigationViewMode(NavigationViewMode.SELECTED_PRIMARY)
  
  // The selected drawer item will be tinted with the accent color. 
  navigationViewMode(NavigationViewMode.SELECTED_ACCENT)
  
  // This library will not apply any auto theming to NavigationViews. 
  navigationViewMode(NavigationViewMode.NONE)
}

SwipeRefreshLayouts

Aesthetic.config {

  // You can pass one more more comma-separated colors. 
  // The colors that the refreshing indicator rotates through in a loop.
  swipeRefreshLayoutColorsRes(R.color.red, R.color.blue)
}

Custom Views and Manual Application

Aesthetic will not automatically theme most custom views, with some exceptions such as background color, text color, hint text color, an image view tint (these are handled without swapping view types).

Aesthetic makes it easy to subscribe to color changes so that you can manually apply colors to views that need them.For an example, you can subscribe to pre-defined attributes, such as colorPrimary():

val subscription = Aesthetic.get()
  .colorPrimary()
  .subscribe { color ->
      // Use color (an integer)
  }
      
// Later, you should unsubscribe, e.g. when your Activity pauses or your View detaches from its Window
subscription.dispose()

If you only need the latest value and no further updates:

Aesthetic.get()
  .colorPrimary()
  .take(1)
  .subscribe { color ->
      // Use color (an integer)
  }

You can do the same with custom attributes by switching colorPrimary() with attribute(R.attr.your_attr).


You can even setup an inflation delegate to auto-swap views at inflation time, like Aesthetic does with a lot of stock/AndroidX views. This delegate is not called for views that Aesthetic already swaps internally.

class MyInflationDelegate : InflationDelegate {

  override fun createView(
    context: Context,
    attrs: AttributeSet?,
    name: String,
    viewId: Int
  ): View? = when (name) {
    "com.somelibrary.CustomView" -> ThemedCustomView(context, attrs)
    else -> null
  }
}

Aesthetic.setInflationDelegate(MyInflationDelegate())

Ignoring Views

You can make this library ignore specific views from being themed with tags:

// Can also be set in you layout XML
view.setTag(":aesthetic_ignore")

view.setTag(R.id.aesthetic_ignore, "anything other than null")

More Repositories

1

material-dialogs

๐Ÿ˜ A beautiful, fluid, and extensible dialogs API for Kotlin & Android.
Kotlin
19,672
star
2

drag-select-recyclerview

๐Ÿ‘‡ Easy Google Photos style multi-selection for RecyclerViews, powered by Kotlin and AndroidX.
Kotlin
1,969
star
3

photo-affix

๐Ÿ“ท Stitch your photos together vertically or horizontally easily!
Kotlin
1,008
star
4

material-cab

๐Ÿš• An Android & Kotlin library for placing and manipulating Contextual Action Bars in your UI.
Kotlin
982
star
5

assent

๐Ÿ™ Android Runtime Permissions made easy and compact, for Kotlin and AndroidX. With coroutines support!
Kotlin
851
star
6

ason

[DEPRECATED]: Prefer Moshi, Jackson, Gson, or LoganSquare
Java
758
star
7

recyclical

๐Ÿš€ An easy-to-use, extensible Kotlin DSL for setting up and manipulating RecyclerViews.
Kotlin
716
star
8

vvalidator

๐Ÿค– An easy to use form validator for Kotlin & Android.
Kotlin
658
star
9

mnml

๐Ÿ“น A minimal, beautiful screen recorder for Android.
Kotlin
656
star
10

nock-nock

๐Ÿšช Monitor and validate your websites to maintain maximum uptime.
Kotlin
377
star
11

inline-activity-result

Receive Activity results inline, without any boilerplate. Optional coroutines and RxJava support.
Kotlin
316
star
12

rxkprefs

๐Ÿ›  A small Kotlin library to make shared preferences easy + RxJava and Coroutines support
Kotlin
277
star
13

ulfberht

๐Ÿ—ก๏ธ A small but powerful & opinionated DI library. Written in Kotlin, and powered by annotation processing.
Kotlin
251
star
14

viewpagerdots

๐Ÿ‘€ Simple, compact Kotlin library for ViewPager page indicators.
Kotlin
189
star
15

date-picker

๐Ÿ“… Custom responsive date picker widget for Android, written in Kotlin.
Kotlin
159
star
16

assure

A Kotlin library that makes biometric authentication quick and easy.
Kotlin
67
star
17

arctic-icon-request

An easy to use Icon Request API for Kotlin, with traditional email capabilities plus the Arctic Manager API.
Kotlin
60
star
18

af.codes

๐ŸŒ The source code of my personal website.
HTML
31
star
19

pi-feeder

My WIP Raspberry Pi auto pet feeder system.
CSS
31
star
20

pi-feeder-android

A simple client for my Pi Feeder IoT device. Used for discovery and basic setup, scheduling is left to the web dashboard.
Java
19
star
21

node-deploy

A Git and HTTP powered deployment system for Node.js apps.
JavaScript
8
star
22

web-recording-experiments

Experiments with recording audio and video from the web. This repo is incomplete, right now. I will be adding more.
JavaScript
4
star
23

trifles

JavaScript
3
star
24

color-render

JavaScript
3
star
25

afollestad

2
star