├── .editorconfig
├── .gitignore
├── .travis.yml
├── LICENSE.txt
├── README.md
├── build.gradle
├── demo-main
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── jaredrummler
│ │ └── cyanea
│ │ └── demo
│ │ ├── MainApp.kt
│ │ ├── activities
│ │ ├── DrawerActivity.kt
│ │ ├── MainActivity.kt
│ │ └── RecyclerViewActivity.kt
│ │ └── fragments
│ │ ├── AboutFragment.kt
│ │ ├── DialogsFragment.kt
│ │ ├── OtherFragment.kt
│ │ └── WidgetsFragment.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_apple_24dp.xml
│ ├── ic_dialogs_24px.xml
│ ├── ic_drawer_menu_24px.xml
│ ├── ic_facebook_24dp.xml
│ ├── ic_github_white_24dp.xml
│ ├── ic_google_24dp.xml
│ ├── ic_hamburger_menu_white_24dp.xml
│ ├── ic_instagram_24dp.xml
│ ├── ic_launcher_background.xml
│ ├── ic_settings_white_24dp.xml
│ ├── ic_share_white_24dp.xml
│ ├── ic_theme_swithcer_24dp.xml
│ └── ic_twitter_24dp.xml
│ ├── font
│ ├── font_raleway.xml
│ ├── font_raleway_light.xml
│ ├── font_raleway_medium.xml
│ ├── font_raleway_semibold.xml
│ ├── raleway_bold.ttf
│ ├── raleway_light.ttf
│ ├── raleway_medium.ttf
│ ├── raleway_regular.ttf
│ └── raleway_semibold.ttf
│ ├── layout
│ ├── activity_drawer.xml
│ ├── activity_main.xml
│ ├── activity_recycler_view.xml
│ ├── cat_chip_topic.xml
│ ├── drawer_header.xml
│ ├── fragment_about.xml
│ ├── fragment_dialogs.xml
│ ├── fragment_other.xml
│ ├── fragment_widgets.xml
│ └── item_rv.xml
│ ├── menu
│ ├── bottom_bar_menu.xml
│ ├── bottom_sheet_menu.xml
│ ├── drawer_menu.xml
│ ├── main_menu.xml
│ └── popup_menu.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── demo-simple-java
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── jaredrummler
│ │ └── cyanea
│ │ └── javademo
│ │ └── MainActivity.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_main.xml
│ └── content_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── demo.apk
├── gradle.properties
├── gradle
├── gradle-mvn-push.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── themes
│ │ │ └── cyanea_themes.json
│ ├── java
│ │ └── com
│ │ │ └── jaredrummler
│ │ │ └── cyanea
│ │ │ ├── Constants.kt
│ │ │ ├── Cyanea.kt
│ │ │ ├── CyaneaApp.kt
│ │ │ ├── CyaneaResources.kt
│ │ │ ├── CyaneaThemes.kt
│ │ │ ├── Extensions.kt
│ │ │ ├── app
│ │ │ ├── BaseCyaneaActivity.kt
│ │ │ ├── CyaneaActivity.kt
│ │ │ ├── CyaneaAppCompatActivity.kt
│ │ │ ├── CyaneaFragment.kt
│ │ │ ├── CyaneaFragmentActivity.kt
│ │ │ └── CyaneaPreferenceActivity.kt
│ │ │ ├── delegate
│ │ │ ├── BaseAppCompatDelegate.kt
│ │ │ ├── CyaneaDelegate.kt
│ │ │ ├── CyaneaDelegateImplBase.kt
│ │ │ ├── CyaneaDelegateImplV19.kt
│ │ │ ├── CyaneaDelegateImplV21.kt
│ │ │ ├── CyaneaDelegateImplV23.kt
│ │ │ ├── CyaneaDelegateImplV24.kt
│ │ │ ├── CyaneaDelegateImplV26.kt
│ │ │ └── CyaneaDelegateImplV29.kt
│ │ │ ├── inflator
│ │ │ ├── CyaneaContextWrapper.kt
│ │ │ ├── CyaneaInflationDelegate.kt
│ │ │ ├── CyaneaLayoutInflater.kt
│ │ │ ├── CyaneaViewFactory.kt
│ │ │ ├── CyaneaViewProcessor.kt
│ │ │ └── decor
│ │ │ │ ├── AttrsDecorator.kt
│ │ │ │ ├── CyaneaDecorator.kt
│ │ │ │ └── FontDecorator.kt
│ │ │ ├── prefs
│ │ │ ├── CyaneaSettingsActivity.kt
│ │ │ ├── CyaneaSettingsFragment.kt
│ │ │ ├── CyaneaTheme.kt
│ │ │ ├── CyaneaThemePickerActivity.kt
│ │ │ ├── CyaneaThemePickerAdapter.kt
│ │ │ └── CyaneaThemePickerFragment.kt
│ │ │ ├── tinting
│ │ │ ├── CyaneaTinter.kt
│ │ │ ├── EdgeEffectTint.kt
│ │ │ ├── MenuTint.kt
│ │ │ ├── SystemBarTint.kt
│ │ │ └── WidgetTint.kt
│ │ │ └── utils
│ │ │ ├── ColorFilterCompat.kt
│ │ │ ├── ColorUtils.kt
│ │ │ └── Reflection.kt
│ ├── res-public
│ │ └── values
│ │ │ └── public.xml
│ └── res
│ │ ├── color
│ │ ├── cyanea_accent.xml
│ │ ├── cyanea_accent_dark.xml
│ │ ├── cyanea_accent_light.xml
│ │ ├── cyanea_bg_dark.xml
│ │ ├── cyanea_bg_dark_darker.xml
│ │ ├── cyanea_bg_dark_lighter.xml
│ │ ├── cyanea_bg_light.xml
│ │ ├── cyanea_bg_light_darker.xml
│ │ ├── cyanea_bg_light_lighter.xml
│ │ ├── cyanea_primary.xml
│ │ ├── cyanea_primary_dark.xml
│ │ └── cyanea_primary_light.xml
│ │ ├── drawable-hdpi
│ │ └── cyanea_popup_background.9.png
│ │ ├── drawable-mdpi
│ │ └── cyanea_popup_background.9.png
│ │ ├── drawable-v21
│ │ ├── cyanea_bg_button_accent.xml
│ │ └── cyanea_bg_button_primary.xml
│ │ ├── drawable-xhdpi
│ │ └── cyanea_popup_background.9.png
│ │ ├── drawable-xxhdpi
│ │ └── cyanea_popup_background.9.png
│ │ ├── drawable
│ │ ├── cyanea_accent.xml
│ │ ├── cyanea_bg_button_accent.xml
│ │ ├── cyanea_bg_button_primary.xml
│ │ ├── cyanea_bg_dark.xml
│ │ ├── cyanea_bg_dark_darker.xml
│ │ ├── cyanea_bg_dark_lighter.xml
│ │ ├── cyanea_bg_light.xml
│ │ ├── cyanea_bg_light_darker.xml
│ │ ├── cyanea_bg_light_lighter.xml
│ │ ├── cyanea_bg_popup_dark.xml
│ │ ├── cyanea_bg_popup_light.xml
│ │ ├── cyanea_check.xml
│ │ ├── cyanea_fab_add.xml
│ │ ├── cyanea_primary.xml
│ │ └── cyanea_primary_dark.xml
│ │ ├── layout
│ │ ├── cyanea_item_theme.xml
│ │ └── cyanea_theme_picker.xml
│ │ ├── values-land
│ │ └── dimens.xml
│ │ ├── values-pt
│ │ └── strings.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── attrs.xml
│ │ ├── bools.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ │ └── xml
│ │ └── pref_cyanea.xml
│ └── test
│ └── java
│ └── com
│ └── jaredrummler
│ └── cyanea
│ ├── CyaneaResourcesTest.kt
│ ├── CyaneaTest.kt
│ └── utils
│ └── ReflectionTest.kt
└── settings.gradle
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 |
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Gradle
2 | .gradle
3 | build
4 |
5 | ### IntelliJ IDEA
6 | .idea
7 | **.iml
8 |
9 | ### Local configuration file (sdk path, etc)
10 | local.properties
11 |
12 | ### Android
13 | *.jks
14 | *.dex
15 |
16 | ### Android Studio
17 | captures/
18 |
19 | ### Java
20 | *.class
21 |
22 | ### Windows
23 | Desktop.ini
24 | Thumbs.db
25 | ehthumbs.db
26 |
27 | ### OSX
28 | .DS_Store
29 |
30 | ### Linux
31 | *~
32 | .fuse_hidden*
33 | .directory
34 | .Trash-*
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 |
3 | jdk: oraclejdk8
4 |
5 | install:
6 | - yes | sdkmanager "tools" &>/dev/null
7 | - yes | sdkmanager "platform-tools" &>/dev/null
8 | - yes | sdkmanager "platforms;android-28" &>/dev/null
9 | - yes | sdkmanager --update &>/dev/null
10 | - yes | sdkmanager --licenses &>/dev/null
11 |
12 | script: ./gradlew clean ktlintCheck assembleDebug testDebug -Pci -s
13 |
14 | branches:
15 | except:
16 | - gh-pages
17 |
18 | sudo: false
19 |
20 | before_cache:
21 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
22 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
23 |
24 | cache:
25 | directories:
26 | - $HOME/.gradle/caches/
27 | - $HOME/.gradle/wrapper/
28 | - $HOME/.android/build-cache
29 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | // ---- DEPENDENCIES ----
3 | // @formatter:off
4 | ext.buildConfig = [
5 | compileSdk : 29,
6 | targetSdk : 29,
7 | minSdk : 14,
8 | gradlePlugin : '4.0.0'
9 | ]
10 |
11 | ext.versions = [
12 | kotlin : '1.3.72',
13 | androidx : '1.1.0',
14 | material : '1.1.0',
15 | preference : '1.0.0',
16 | constraintlayout : '1.1.3',
17 | colorpicker : '1.0.5',
18 | junit : '4.12',
19 | mockito_kotlin : '2.0.0',
20 | mockito_core : '2.23.4'
21 | ]
22 |
23 | ext.deps = [
24 | 'androidx': [
25 | 'appCompat' : "androidx.appcompat:appcompat:${versions.androidx}",
26 | 'constraintLayout' : "androidx.constraintlayout:constraintlayout:${versions.constraintlayout}",
27 | 'preferences' : "androidx.preference:preference:${versions.preference}"
28 | ],
29 | 'kotlin': [
30 | 'stdlib': [
31 | 'jdk' : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
32 | ]
33 | ],
34 | 'material' : "com.google.android.material:material:${versions.material}",
35 | 'colorpicker' : "com.jaredrummler:colorpicker-compat:${versions.colorpicker}",
36 | 'junit' : "junit:junit:${versions.junit}",
37 | 'mockito': [
38 | 'core' : "org.mockito:mockito-core:${versions.mockito_core}",
39 | 'kotlin' : "com.nhaarman.mockitokotlin2:mockito-kotlin:${versions.mockito_kotlin}"
40 | ]
41 | ]
42 | // @formatter:on
43 |
44 | repositories {
45 | google()
46 | gradlePluginPortal()
47 | }
48 |
49 | dependencies {
50 | classpath "com.android.tools.build:gradle:${buildConfig.gradlePlugin}"
51 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
52 | classpath 'org.jlleitschuh.gradle:ktlint-gradle:8.0.0'
53 | }
54 | }
55 |
56 | allprojects {
57 | repositories {
58 | google()
59 | gradlePluginPortal()
60 | }
61 |
62 | apply plugin: 'org.jlleitschuh.gradle.ktlint'
63 |
64 | configurations.all {
65 | resolutionStrategy {
66 | eachDependency { details ->
67 | if (details.requested.group == 'org.jetbrains.kotlin') {
68 | details.useVersion versions.kotlin
69 | }
70 | }
71 | }
72 | }
73 |
74 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
75 | kotlinOptions {
76 | allWarningsAsErrors = true
77 | }
78 | }
79 | }
80 |
81 | task clean(type: Delete) {
82 | delete rootProject.buildDir
83 | }
84 |
--------------------------------------------------------------------------------
/demo-main/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo-main/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'org.jetbrains.kotlin.android'
3 | apply plugin: 'org.jetbrains.kotlin.android.extensions'
4 |
5 | android {
6 | compileSdkVersion buildConfig.compileSdk
7 |
8 | defaultConfig {
9 | applicationId 'com.jaredrummler.cyanea.demo'
10 | minSdkVersion buildConfig.minSdk
11 | targetSdkVersion buildConfig.targetSdk
12 | versionCode 1
13 | versionName '1.0'
14 | vectorDrawables.useSupportLibrary true
15 | }
16 |
17 | compileOptions {
18 | sourceCompatibility JavaVersion.VERSION_1_8
19 | targetCompatibility JavaVersion.VERSION_1_8
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | }
29 |
30 | dependencies {
31 | implementation project(':library')
32 | implementation deps.kotlin.stdlib.jdk
33 | implementation deps.material
34 | implementation deps.androidx.constraintLayout
35 | }
36 |
--------------------------------------------------------------------------------
/demo-main/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/demo-main/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/demo-main/src/main/java/com/jaredrummler/cyanea/demo/MainApp.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.demo
2 |
3 | import android.app.Application
4 | import android.view.View
5 | import com.jaredrummler.cyanea.Cyanea
6 | import com.jaredrummler.cyanea.inflator.CyaneaViewProcessor
7 | import com.jaredrummler.cyanea.inflator.decor.CyaneaDecorator
8 | import com.jaredrummler.cyanea.inflator.decor.FontDecorator
9 |
10 | class MainApp : Application(), CyaneaDecorator.Provider, CyaneaViewProcessor.Provider {
11 |
12 | override fun onCreate() {
13 | super.onCreate()
14 | Cyanea.init(this, resources)
15 | Cyanea.loggingEnabled = true
16 | }
17 |
18 | override fun getViewProcessors(): Array> = arrayOf(
19 | // Add a view processor to manipulate a view when inflated.
20 | )
21 |
22 | override fun getDecorators(): Array = arrayOf(
23 | // Add a decorator to apply custom attributes to any view
24 | FontDecorator()
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/demo-main/src/main/java/com/jaredrummler/cyanea/demo/activities/DrawerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.demo.activities
2 |
3 | import android.content.res.Configuration
4 | import android.os.Bundle
5 | import android.view.MenuItem
6 | import androidx.appcompat.app.ActionBarDrawerToggle
7 | import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
8 | import com.jaredrummler.cyanea.demo.R
9 | import kotlinx.android.synthetic.main.activity_drawer.drawerLayout
10 | import kotlinx.android.synthetic.main.activity_drawer.navigationView
11 | import kotlinx.android.synthetic.main.activity_drawer.toolbar
12 |
13 | class DrawerActivity : CyaneaAppCompatActivity() {
14 |
15 | private lateinit var drawerToggle: ActionBarDrawerToggle
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_drawer)
20 | setSupportActionBar(toolbar)
21 |
22 | supportActionBar?.apply {
23 | setDisplayHomeAsUpEnabled(true)
24 | setHomeButtonEnabled(true)
25 | }
26 |
27 | drawerToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_drawer, R.string.close_drawer)
28 | drawerLayout.addDrawerListener(drawerToggle)
29 |
30 | navigationView.post { navigationView.setCheckedItem(R.id.item_twitter) }
31 |
32 | navigationView.setNavigationItemSelectedListener {
33 | navigationView.setCheckedItem(it.itemId)
34 | false
35 | }
36 | }
37 |
38 | override fun onPostCreate(savedInstanceState: Bundle?) {
39 | super.onPostCreate(savedInstanceState)
40 | drawerToggle.syncState()
41 | }
42 |
43 | override fun onConfigurationChanged(newConfig: Configuration) {
44 | super.onConfigurationChanged(newConfig)
45 | drawerToggle.onConfigurationChanged(newConfig)
46 | }
47 |
48 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
49 | return drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/demo-main/src/main/java/com/jaredrummler/cyanea/demo/activities/RecyclerViewActivity.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.demo.activities
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Toast
9 | import androidx.recyclerview.widget.DividerItemDecoration
10 | import androidx.recyclerview.widget.LinearLayoutManager
11 | import androidx.recyclerview.widget.RecyclerView
12 | import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
13 | import com.jaredrummler.cyanea.demo.R.layout
14 | import kotlinx.android.synthetic.main.activity_recycler_view.recyclerView
15 | import kotlinx.android.synthetic.main.item_rv.view.subtitleText
16 | import kotlinx.android.synthetic.main.item_rv.view.titleText
17 |
18 | class RecyclerViewActivity : CyaneaAppCompatActivity() {
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | setContentView(layout.activity_recycler_view)
23 | recyclerView.layoutManager = LinearLayoutManager(this)
24 | recyclerView.adapter = DemoAdapter()
25 | recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
26 | }
27 |
28 | class DemoAdapter : RecyclerView.Adapter() {
29 |
30 | override fun getItemCount(): Int = 100
31 |
32 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DemoViewHolder {
33 | LayoutInflater.from(parent.context).run {
34 | return DemoViewHolder(inflate(layout.item_rv, parent, false))
35 | }
36 | }
37 |
38 | @SuppressLint("SetTextI18n")
39 | override fun onBindViewHolder(holder: DemoViewHolder, position: Int) {
40 | val number = position + 1
41 | holder.itemView.titleText.text = "Item #$number"
42 | holder.itemView.subtitleText.text = (when {
43 | number % 15 == 0 -> "FizzBuzz"
44 | number % 3 == 0 -> "Fizz"
45 | number % 5 == 0 -> "Buzz"
46 | else -> number.toString()
47 | })
48 | }
49 | }
50 |
51 | class DemoViewHolder(view: View) : RecyclerView.ViewHolder(view) {
52 | init {
53 | itemView.setOnClickListener {
54 | Toast.makeText(it.context, "Clicked item #${adapterPosition + 1}", Toast.LENGTH_SHORT).show()
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/demo-main/src/main/java/com/jaredrummler/cyanea/demo/fragments/AboutFragment.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.demo.fragments
2 |
3 | import android.content.res.ColorStateList
4 | import android.graphics.Color
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import com.google.android.material.chip.Chip
10 | import com.jaredrummler.cyanea.app.CyaneaFragment
11 | import com.jaredrummler.cyanea.demo.R
12 | import kotlinx.android.synthetic.main.fragment_about.cyaneaTopics
13 |
14 | class AboutFragment : CyaneaFragment() {
15 |
16 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
17 | return inflater.inflate(R.layout.fragment_about, container, false)
18 | }
19 |
20 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
21 | loadTopics()
22 | }
23 |
24 | private fun loadTopics() {
25 | cyaneaTopics.removeAllViews()
26 | resources.getStringArray(R.array.cyanea_topics).forEach { text ->
27 | val chip = layoutInflater.inflate(R.layout.cat_chip_topic, cyaneaTopics, false) as Chip
28 | chip.chipBackgroundColor = ColorStateList.valueOf(
29 | if (cyanea.isDark) cyanea.backgroundColorLight else cyanea.backgroundColorDark
30 | )
31 | chip.setTextColor(if (cyanea.isDark) Color.WHITE else Color.BLACK)
32 | chip.text = text
33 | cyaneaTopics.addView(chip)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/demo-main/src/main/java/com/jaredrummler/cyanea/demo/fragments/OtherFragment.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.demo.fragments
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.LinearLayout
9 | import androidx.annotation.StringRes
10 | import androidx.fragment.app.Fragment
11 | import com.google.android.material.button.MaterialButton
12 | import com.jaredrummler.cyanea.demo.activities.DrawerActivity
13 | import com.jaredrummler.cyanea.demo.R
14 | import com.jaredrummler.cyanea.demo.activities.RecyclerViewActivity
15 |
16 | class OtherFragment : Fragment() {
17 |
18 | private lateinit var container: ViewGroup
19 |
20 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
21 | return inflater.inflate(R.layout.fragment_other, container, false)
22 | }
23 |
24 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
25 | container = view.findViewById(R.id.container)
26 | addButton(R.string.drawer_layout, {
27 | startActivity(Intent(requireActivity(), DrawerActivity::class.java))
28 | })
29 | addButton(R.string.recycler_view, {
30 | startActivity(Intent(requireActivity(), RecyclerViewActivity::class.java))
31 | })
32 | }
33 |
34 | private fun addButton(
35 | @StringRes stringResId: Int,
36 | action: () -> Unit,
37 | marginTop: Float = 8f,
38 | marginBottom: Float = 0f
39 | ) {
40 | val dialogLauncherButton = MaterialButton(requireActivity())
41 | dialogLauncherButton.setOnClickListener { action() }
42 | dialogLauncherButton.setText(stringResId)
43 | val params = LinearLayout.LayoutParams(
44 | LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
45 | params.topMargin = Math.round(marginTop * resources.displayMetrics.density)
46 | params.bottomMargin = Math.round(marginBottom * resources.displayMetrics.density)
47 | container.addView(dialogLauncherButton, params)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/demo-main/src/main/java/com/jaredrummler/cyanea/demo/fragments/WidgetsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.demo.fragments
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import com.jaredrummler.cyanea.demo.R
9 |
10 | class WidgetsFragment : Fragment() {
11 |
12 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
13 | return inflater.inflate(R.layout.fragment_widgets, container, false)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_apple_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_dialogs_24px.xml:
--------------------------------------------------------------------------------
1 |
16 |
22 |
25 |
28 |
31 |
32 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_drawer_menu_24px.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_facebook_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_github_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_google_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_hamburger_menu_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_instagram_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_settings_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_share_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_theme_swithcer_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/drawable/ic_twitter_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/font_raleway.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
17 |
18 |
19 |
27 |
28 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/font_raleway_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
25 |
26 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/font_raleway_medium.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
17 |
18 |
26 |
27 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/font_raleway_semibold.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
17 |
18 |
26 |
27 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/raleway_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/font/raleway_bold.ttf
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/raleway_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/font/raleway_light.ttf
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/raleway_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/font/raleway_medium.ttf
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/raleway_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/font/raleway_regular.ttf
--------------------------------------------------------------------------------
/demo-main/src/main/res/font/raleway_semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/font/raleway_semibold.ttf
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/activity_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
19 |
20 |
31 |
32 |
41 |
42 |
43 |
44 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
23 |
24 |
34 |
35 |
36 |
37 |
44 |
45 |
54 |
55 |
62 |
63 |
73 |
74 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/activity_recycler_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/cat_chip_topic.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/drawer_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/fragment_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
24 |
25 |
43 |
44 |
56 |
57 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/fragment_dialogs.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/fragment_other.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/layout/item_rv.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/menu/bottom_bar_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/menu/bottom_sheet_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/menu/drawer_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
43 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/menu/popup_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-main/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-main/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #14B09B
5 |
6 | #0359AE
7 |
8 | #EBE5D9
9 | #D4D4D4
10 | #EEE8DE
11 |
12 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 8dp
5 | 4dp
6 | 6dp
7 | 36sp
8 | 196dp
9 | 8dp
10 | 8dp
11 | 2dp
12 | 32dp
13 | 24dp
14 | 12dp
15 |
--------------------------------------------------------------------------------
/demo-main/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo-simple-java/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo-simple-java/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 | defaultConfig {
7 | applicationId 'com.jaredrummler.cyanea.javademo'
8 | minSdkVersion 22
9 | targetSdkVersion 28
10 | versionCode 1
11 | versionName '1.0'
12 | }
13 | compileOptions {
14 | sourceCompatibility JavaVersion.VERSION_1_8
15 | targetCompatibility JavaVersion.VERSION_1_8
16 | }
17 | }
18 |
19 | dependencies {
20 | implementation project(':library')
21 | implementation deps.material
22 | implementation deps.androidx.constraintLayout
23 | }
24 |
--------------------------------------------------------------------------------
/demo-simple-java/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/java/com/jaredrummler/cyanea/javademo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.javademo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 | import androidx.annotation.Nullable;
8 | import androidx.appcompat.widget.Toolbar;
9 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
10 | import com.google.android.material.snackbar.Snackbar;
11 | import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity;
12 | import com.jaredrummler.cyanea.prefs.CyaneaSettingsActivity;
13 |
14 | public class MainActivity extends CyaneaAppCompatActivity {
15 |
16 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_main);
19 | Toolbar toolbar = findViewById(R.id.toolbar);
20 | FloatingActionButton fab = findViewById(R.id.fab);
21 | setSupportActionBar(toolbar);
22 | fab.setOnClickListener((v) ->
23 | Snackbar.make(v, "Replace with your own action", Snackbar.LENGTH_LONG)
24 | .setAction("Action", null).show()
25 | );
26 | }
27 |
28 | @Override public boolean onCreateOptionsMenu(Menu menu) {
29 | getMenuInflater().inflate(R.menu.menu_main, menu);
30 | return super.onCreateOptionsMenu(menu);
31 | }
32 |
33 | @Override public boolean onOptionsItemSelected(MenuItem item) {
34 | switch (item.getItemId()) {
35 | case R.id.action_settings:
36 | startActivity(new Intent(this, CyaneaSettingsActivity.class));
37 | return true;
38 | default:
39 | return super.onOptionsItemSelected(item);
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
37 |
38 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
22 |
23 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo-simple-java/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #0288D1
4 | #FFA000
5 |
6 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Java Demo
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/demo-simple-java/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/demo.apk
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | android.useAndroidX=true
20 | android.enableJetifier=true
21 |
--------------------------------------------------------------------------------
/gradle/gradle-mvn-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getReleaseRepositoryUrl() {
25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
27 | }
28 |
29 | def getSnapshotRepositoryUrl() {
30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
31 | : "https://oss.sonatype.org/content/repositories/snapshots/"
32 | }
33 |
34 | def getRepositoryUsername() {
35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
36 | }
37 |
38 | def getRepositoryPassword() {
39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
40 | }
41 |
42 | afterEvaluate { project ->
43 | uploadArchives {
44 | repositories {
45 | mavenDeployer {
46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
47 |
48 | pom.groupId = GROUP
49 | pom.artifactId = POM_ARTIFACT_ID
50 | pom.version = VERSION_NAME
51 |
52 | repository(url: getReleaseRepositoryUrl()) {
53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
54 | }
55 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
57 | }
58 |
59 | pom.project {
60 | name POM_NAME
61 | packaging POM_PACKAGING
62 | description POM_DESCRIPTION
63 | url POM_URL
64 |
65 | scm {
66 | url POM_SCM_URL
67 | connection POM_SCM_CONNECTION
68 | developerConnection POM_SCM_DEV_CONNECTION
69 | }
70 |
71 | licenses {
72 | license {
73 | name POM_LICENCE_NAME
74 | url POM_LICENCE_URL
75 | distribution POM_LICENCE_DIST
76 | }
77 | }
78 |
79 | developers {
80 | developer {
81 | id POM_DEVELOPER_ID
82 | name POM_DEVELOPER_NAME
83 | }
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
90 | signing {
91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
92 | sign configurations.archives
93 | }
94 |
95 | task androidJavadocs(type: Javadoc) {
96 | source = android.sourceSets.main.java.srcDirs
97 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
98 | if (JavaVersion.current().isJava8Compatible()) {
99 | options.addStringOption('Xdoclint:none', '-quiet')
100 | }
101 | failOnError false
102 | }
103 |
104 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
105 | classifier = 'javadoc'
106 | from androidJavadocs.destinationDir
107 | }
108 |
109 | task androidSourcesJar(type: Jar) {
110 | classifier = 'sources'
111 | from android.sourceSets.main.java.sourceFiles
112 | }
113 |
114 | artifacts {
115 | archives androidSourcesJar
116 | archives androidJavadocsJar
117 | }
118 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon May 30 10:10:10 PDT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS="-Xmx64m"
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'org.jetbrains.kotlin.android'
3 |
4 | android {
5 | compileSdkVersion buildConfig.compileSdk
6 |
7 | defaultConfig {
8 | minSdkVersion buildConfig.minSdk
9 | targetSdkVersion buildConfig.targetSdk
10 | }
11 |
12 | compileOptions {
13 | sourceCompatibility JavaVersion.VERSION_1_8
14 | targetCompatibility JavaVersion.VERSION_1_8
15 | }
16 |
17 | sourceSets {
18 | main.res.srcDirs 'res', 'res-public'
19 | }
20 |
21 | testOptions {
22 | unitTests.returnDefaultValues = true
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation deps.kotlin.stdlib.jdk
28 | implementation deps.androidx.appCompat
29 | implementation deps.androidx.preferences
30 | implementation deps.material
31 | implementation deps.colorpicker
32 | testImplementation deps.junit
33 | testImplementation deps.mockito.core
34 | testImplementation deps.mockito.kotlin
35 | }
36 |
37 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_NAME=1.0.2
2 | VERSION_CODE=102
3 | GROUP=com.jaredrummler
4 | ARTIFACT_ID=cyanea
5 | POM_NAME=cyanea
6 | POM_ARTIFACT_ID=cyanea
7 | POM_PACKAGING=aar
8 | POM_DESCRIPTION=A dynamic theme engine for Android applications
9 | POM_URL=https://github.com/jaredrummler/Cyanea
10 | POM_SCM_URL=https://github.com/jaredrummler/Cyanea
11 | POM_SCM_CONNECTION=scm:git@github.com:jaredrummler/Cyanea.git
12 | POM_SCM_DEV_CONNECTION=scm:git@github.com:jaredrummler/Cyanea.git
13 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
14 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
15 | POM_LICENCE_DIST=repo
16 | POM_DEVELOPER_ID=jaredrummler
17 | POM_DEVELOPER_NAME=Jared Rummler
18 | SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots
19 | RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2
20 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/Constants.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea
18 |
19 | internal object Constants {
20 | internal const val NONE_TIMESTAMP = 0L
21 | internal const val LIGHT_ACTIONBAR_LUMINANCE_FACTOR = 0.75
22 | }
23 |
24 | internal object PrefKeys {
25 | internal const val PREF_FILE_NAME = "com.jaredrummler.cyanea"
26 | internal const val PREF_BASE_THEME = "base_theme"
27 | internal const val PREF_PRIMARY = "primary"
28 | internal const val PREF_PRIMARY_DARK = "primary_dark"
29 | internal const val PREF_PRIMARY_LIGHT = "primary_light"
30 | internal const val PREF_ACCENT = "accent"
31 | internal const val PREF_ACCENT_DARK = "accent_dark"
32 | internal const val PREF_ACCENT_LIGHT = "accent_light"
33 | internal const val PREF_BACKGROUND_LIGHT = "background_light"
34 | internal const val PREF_BACKGROUND_LIGHT_DARKER = "background_light_darker"
35 | internal const val PREF_BACKGROUND_LIGHT_LIGHTER = "background_light_lighter"
36 | internal const val PREF_BACKGROUND_DARK = "background_dark"
37 | internal const val PREF_BACKGROUND_DARK_DARKER = "background_dark_darker"
38 | internal const val PREF_BACKGROUND_DARK_LIGHTER = "background_dark_lighter"
39 | internal const val PREF_MENU_ICON_COLOR = "menu_icon_color"
40 | internal const val PREF_SUB_MENU_ICON_COLOR = "sub_menu_icon_color"
41 | internal const val PREF_NAVIGATION_BAR = "navigation_bar_color"
42 | internal const val PREF_SHOULD_TINT_STATUS_BAR = "should_tint_status_bar"
43 | internal const val PREF_SHOULD_TINT_NAV_BAR = "should_tint_nav_bar"
44 | internal const val PREF_TIMESTAMP = "timestamp"
45 | }
46 |
47 | internal object Defaults {
48 | internal const val DEFAULT_DARKER_FACTOR = 0.85f
49 | internal const val DEFAULT_LIGHTER_FACTOR = 0.15f
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/CyaneaApp.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea
18 |
19 | import android.app.Application
20 | import android.content.res.Resources
21 |
22 | /**
23 | * A subclass of [Application] which should be added to the AndroidManifest.
24 | *
25 | * If you cannot extend from this class you can initialize you must initialize Cyanea from your own base app:
26 | *
27 | * ```kotlin
28 | * override run onCreate() {
29 | * super.onCreate()
30 | * Cyanea.init(this, super.getResources())
31 | * }
32 | * ```
33 | */
34 | open class CyaneaApp : Application() {
35 |
36 | private val resources: CyaneaResources by lazy {
37 | CyaneaResources(super.getResources(), cyanea)
38 | }
39 |
40 | /**
41 | * The [cyanea][Cyanea] instance used to create the application's resources
42 | */
43 | open val cyanea: Cyanea by lazy { Cyanea.instance }
44 |
45 | override fun onCreate() {
46 | super.onCreate()
47 | Cyanea.init(this, super.getResources())
48 | }
49 |
50 | override fun getResources(): Resources {
51 | return if (Cyanea.isInitialized()) resources else super.getResources()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/CyaneaThemes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea
18 |
19 | import androidx.annotation.StyleRes
20 | import androidx.appcompat.app.AppCompatActivity
21 | import com.jaredrummler.cyanea.Cyanea.BaseTheme.DARK
22 | import com.jaredrummler.cyanea.Cyanea.BaseTheme.LIGHT
23 |
24 | /**
25 | * Theme that can be used in your Cyanea based activity.
26 | *
27 | * If using your own Toolbar via [AppCompatActivity.setSupportActionBar] use the following theme:
28 | *
29 | * ```kotlin
30 | * override fun getThemeResId(): Int = cyanea.themes.actionBarTheme
31 | * ```
32 | *
33 | * If using the default ActionBar use the following theme:
34 | *
35 | * ```kotlin
36 | * override fun getThemeResId(): Int = cyanea.themes.noActionBarTheme
37 | * ```
38 | */
39 | class CyaneaThemes internal constructor(private val cyanea: Cyanea) {
40 |
41 | /**
42 | * Get a ActionBar theme.
43 | *
44 | * @return One of the following themes:
45 | * [R.style.Theme_Cyanea_Dark],
46 | * [R.style.Theme_Cyanea_Dark_LightActionBar],
47 | * [R.style.Theme_Cyanea_Light],
48 | * [R.style.Theme_Cyanea_Light_DarkActionBar]
49 | */
50 | @get:StyleRes
51 | val actionBarTheme: Int
52 | get() = when (cyanea.baseTheme) {
53 | DARK ->
54 | if (cyanea.isActionBarLight)
55 | R.style.Theme_Cyanea_Dark_LightActionBar
56 | else
57 | R.style.Theme_Cyanea_Dark
58 | LIGHT ->
59 | if (cyanea.isActionBarDark)
60 | R.style.Theme_Cyanea_Light_DarkActionBar
61 | else
62 | R.style.Theme_Cyanea_Light
63 | }
64 |
65 | /**
66 | * Get a NoActionBar theme
67 | *
68 | * @return One of the following themes:
69 | * [R.style.Theme_Cyanea_Dark_NoActionBar],
70 | * [R.style.Theme_Cyanea_Light_NoActionBar],
71 | * [R.style.Theme_Cyanea_Light_DarkActionBar_NoActionBar],
72 | * [R.style.Theme_Cyanea_Dark_LightActionBar_NoActionBar]
73 | */
74 | @get:StyleRes
75 | val noActionBarTheme: Int
76 | get() = when (cyanea.baseTheme) {
77 | DARK ->
78 | if (cyanea.isActionBarLight) // Check primary color for correct actionBarTheme
79 | R.style.Theme_Cyanea_Dark_LightActionBar_NoActionBar
80 | else
81 | R.style.Theme_Cyanea_Dark_NoActionBar
82 | LIGHT ->
83 | if (cyanea.isActionBarDark) // Check primary color for correct actionBarTheme
84 | R.style.Theme_Cyanea_Light_DarkActionBar_NoActionBar
85 | else
86 | R.style.Theme_Cyanea_Light_NoActionBar
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/Extensions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea
18 |
19 | import android.content.res.Resources
20 | import android.os.Build
21 | import android.util.TypedValue
22 | import com.jaredrummler.cyanea.utils.Reflection
23 |
24 | internal fun Resources.getKey(id: Int, resolveRefs: Boolean = true) = getValue(id, resolveRefs).let {
25 | it.assetCookie.toLong() shl 32 or it.data.toLong()
26 | }
27 |
28 | internal fun Resources.getValue(id: Int, resolveRefs: Boolean = true) = TypedValue().also { value ->
29 | (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
30 | Reflection.getFieldValue(this, "mResourcesImpl")
31 | } else this)?.run {
32 | Reflection.invoke(this, "getValue",
33 | arrayOf(Int::class.java, TypedValue::class.java, Boolean::class.java),
34 | id, value, resolveRefs)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/app/BaseCyaneaActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.app
18 |
19 | import androidx.annotation.StyleRes
20 | import com.jaredrummler.cyanea.Cyanea
21 | import com.jaredrummler.cyanea.CyaneaThemes
22 | import com.jaredrummler.cyanea.delegate.CyaneaDelegate
23 |
24 | /**
25 | * Implement in each [activity][android.app.Activity] to provide a [delegate][CyaneaDelegate] for custom theming.
26 | */
27 | interface BaseCyaneaActivity {
28 |
29 | /**
30 | * The [Cyanea] instance used for styling.
31 | */
32 | val cyanea: Cyanea get() = Cyanea.instance
33 |
34 | /**
35 | * Get the theme resource id. You can use a pre-defined theme in [CyaneaThemes] or use your own theme that inherits
36 | * from a Cyanea based theme.
37 | *
38 | * If 0 is returned then Cyanea will determine whether to use a NoActionBar theme based on the current theme.
39 | *
40 | * @return A cyanea theme
41 | *
42 | * @see [CyaneaThemes.actionBarTheme]
43 | * @see [CyaneaThemes.noActionBarTheme]
44 | */
45 | @StyleRes fun getThemeResId(): Int = 0
46 | }
47 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/app/CyaneaActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.app
18 |
19 | import android.app.Activity
20 | import android.content.Context
21 | import android.content.res.Resources
22 | import android.os.Bundle
23 | import android.view.Menu
24 | import com.jaredrummler.cyanea.Cyanea
25 | import com.jaredrummler.cyanea.CyaneaResources
26 | import com.jaredrummler.cyanea.delegate.CyaneaDelegate
27 |
28 | /**
29 | * Base class for an [Activity] that uses [Cyanea] for dynamic themes.
30 | *
31 | * You must implement [BaseCyaneaActivity.getThemeResId] and return a valid cyanea theme.
32 | */
33 | abstract class CyaneaActivity : Activity(), BaseCyaneaActivity {
34 |
35 | private val delegate: CyaneaDelegate by lazy {
36 | CyaneaDelegate.create(this, cyanea, getThemeResId())
37 | }
38 |
39 | private val resources: CyaneaResources by lazy {
40 | CyaneaResources(super.getResources(), cyanea)
41 | }
42 |
43 | override fun attachBaseContext(newBase: Context) {
44 | super.attachBaseContext(delegate.wrap(newBase))
45 | }
46 |
47 | override fun onCreate(savedInstanceState: Bundle?) {
48 | delegate.onCreate(savedInstanceState)
49 | super.onCreate(savedInstanceState)
50 | }
51 |
52 | override fun onPostCreate(savedInstanceState: Bundle?) {
53 | super.onPostCreate(savedInstanceState)
54 | delegate.onPostCreate(savedInstanceState)
55 | }
56 |
57 | override fun onStart() {
58 | super.onStart()
59 | delegate.onStart()
60 | }
61 |
62 | override fun onResume() {
63 | super.onResume()
64 | delegate.onResume()
65 | }
66 |
67 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
68 | delegate.onCreateOptionsMenu(menu)
69 | return super.onCreateOptionsMenu(menu)
70 | }
71 |
72 | override fun getResources(): Resources = resources
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/app/CyaneaAppCompatActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.app
18 |
19 | import android.content.Context
20 | import android.content.res.Resources
21 | import android.os.Bundle
22 | import android.view.Menu
23 | import androidx.appcompat.app.AppCompatActivity
24 | import com.jaredrummler.cyanea.Cyanea
25 | import com.jaredrummler.cyanea.CyaneaResources
26 | import com.jaredrummler.cyanea.delegate.CyaneaDelegate
27 |
28 | /**
29 | * Base class for an [AppCompatActivity] that uses [Cyanea] for dynamic themes.
30 | *
31 | * You must implement [BaseCyaneaActivity.getThemeResId] and return a valid cyanea theme.
32 | */
33 | abstract class CyaneaAppCompatActivity : AppCompatActivity(), BaseCyaneaActivity {
34 |
35 | private val delegate: CyaneaDelegate by lazy {
36 | CyaneaDelegate.create(this, cyanea, getThemeResId())
37 | }
38 |
39 | private val resources: CyaneaResources by lazy {
40 | CyaneaResources(super.getResources(), cyanea)
41 | }
42 |
43 | override fun attachBaseContext(newBase: Context) {
44 | super.attachBaseContext(delegate.wrap(newBase))
45 | }
46 |
47 | override fun onCreate(savedInstanceState: Bundle?) {
48 | delegate.onCreate(savedInstanceState)
49 | super.onCreate(savedInstanceState)
50 | }
51 |
52 | override fun onPostCreate(savedInstanceState: Bundle?) {
53 | super.onPostCreate(savedInstanceState)
54 | delegate.onPostCreate(savedInstanceState)
55 | }
56 |
57 | override fun onStart() {
58 | super.onStart()
59 | delegate.onStart()
60 | }
61 |
62 | override fun onResume() {
63 | super.onResume()
64 | delegate.onResume()
65 | }
66 |
67 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
68 | delegate.onCreateOptionsMenu(menu)
69 | return super.onCreateOptionsMenu(menu)
70 | }
71 |
72 | override fun getResources(): Resources = resources
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/app/CyaneaFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.app
18 |
19 | import android.view.Menu
20 | import android.view.MenuInflater
21 | import androidx.fragment.app.Fragment
22 | import com.jaredrummler.cyanea.Cyanea
23 |
24 | /**
25 | * Base class for fragments[Fragment] that use [Cyanea] for dynamic themes.
26 | */
27 | open class CyaneaFragment : Fragment() {
28 |
29 | /**
30 | * The [Cyanea] instance used for styling.
31 | */
32 | open val cyanea: Cyanea get() = (activity as? BaseCyaneaActivity)?.cyanea ?: Cyanea.instance
33 |
34 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
35 | applyMenuTint(menu)
36 | super.onCreateOptionsMenu(menu, inflater)
37 | }
38 |
39 | protected open fun applyMenuTint(menu: Menu) = cyanea.tint(menu, requireActivity())
40 | }
41 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/app/CyaneaFragmentActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.app
18 |
19 | import android.content.Context
20 | import android.content.res.Resources
21 | import android.os.Bundle
22 | import android.view.Menu
23 | import androidx.fragment.app.FragmentActivity
24 | import com.jaredrummler.cyanea.Cyanea
25 | import com.jaredrummler.cyanea.CyaneaResources
26 | import com.jaredrummler.cyanea.delegate.CyaneaDelegate
27 |
28 | /**
29 | * Base class for a [FragmentActivity] that use [Cyanea] for dynamic themes.
30 | *
31 | * You must implement [BaseCyaneaActivity.getThemeResId] and return a valid cyanea theme.
32 | */
33 | abstract class CyaneaFragmentActivity : FragmentActivity(), BaseCyaneaActivity {
34 |
35 | private val delegate: CyaneaDelegate by lazy {
36 | CyaneaDelegate.create(this, cyanea, getThemeResId())
37 | }
38 |
39 | private val resources: CyaneaResources by lazy {
40 | CyaneaResources(super.getResources(), cyanea)
41 | }
42 |
43 | override fun attachBaseContext(newBase: Context) {
44 | super.attachBaseContext(delegate.wrap(newBase))
45 | }
46 |
47 | override fun onCreate(savedInstanceState: Bundle?) {
48 | delegate.onCreate(savedInstanceState)
49 | super.onCreate(savedInstanceState)
50 | }
51 |
52 | override fun onPostCreate(savedInstanceState: Bundle?) {
53 | super.onPostCreate(savedInstanceState)
54 | delegate.onPostCreate(savedInstanceState)
55 | }
56 |
57 | override fun onStart() {
58 | super.onStart()
59 | delegate.onStart()
60 | }
61 |
62 | override fun onResume() {
63 | super.onResume()
64 | delegate.onResume()
65 | }
66 |
67 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
68 | delegate.onCreateOptionsMenu(menu)
69 | return super.onCreateOptionsMenu(menu)
70 | }
71 |
72 | override fun getResources(): Resources = resources
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/delegate/BaseAppCompatDelegate.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.delegate
18 |
19 | import androidx.appcompat.app.ActionBar
20 | import androidx.appcompat.app.AppCompatDelegate
21 | import androidx.appcompat.widget.Toolbar
22 |
23 | /**
24 | * An interface to be used on an [activity][android.app.Activity] that doesn't inherit from
25 | * [AppCompatActivity][androidx.appcompat.app.AppCompatActivity] but implements and proxies the necessary calls to be
26 | * used with AppCompat.
27 | */
28 | interface BaseAppCompatDelegate {
29 |
30 | /**
31 | * Support library version of [android.app.Activity.getActionBar].
32 | *
33 | * Retrieve a reference to this activity's ActionBar.
34 | *
35 | * @return The Activity's ActionBar, or null if it does not have one.
36 | */
37 | fun getSupportActionBar(): ActionBar?
38 |
39 | /**
40 | * Set a [Toolbar][android.widget.Toolbar] to act as the [androidx.appcompat.app.ActionBar] for this Activity window.
41 | *
42 | * When set to a non-null value the [android.app.Activity.getActionBar] method will return an
43 | * [ActionBar][androidx.appcompat.app.ActionBar] object that can be used to control the given toolbar as if it were a
44 | * traditional window decor action bar. The toolbar's menu will be populated with the Activity's options menu and
45 | * the navigation button will be wired through the standard [home][android.R.id.home] menu select action.
46 | *
47 | * In order to use a Toolbar within the Activity's window content the application must not request the window
48 | * feature [FEATURE_SUPPORT_ACTION_BAR][android.view.Window.FEATURE_ACTION_BAR].
49 | *
50 | * @param toolbar Toolbar to set as the Activity's action bar, or `null` to clear it
51 | */
52 | fun setSupportActionBar(toolbar: Toolbar?)
53 |
54 | /**
55 | * @return The [AppCompatDelegate] being used by this Activity.
56 | */
57 | fun getDelegate(): AppCompatDelegate
58 | }
59 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/delegate/CyaneaDelegateImplV19.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.delegate
18 |
19 | import android.annotation.TargetApi
20 | import android.app.Activity
21 | import android.os.Build
22 | import android.os.Bundle
23 | import android.view.View
24 | import android.view.ViewGroup
25 | import android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
26 | import android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
27 | import androidx.annotation.RequiresApi
28 | import androidx.drawerlayout.widget.DrawerLayout
29 | import com.jaredrummler.cyanea.Cyanea
30 |
31 | @RequiresApi(Build.VERSION_CODES.KITKAT)
32 | @TargetApi(Build.VERSION_CODES.KITKAT)
33 | internal open class CyaneaDelegateImplV19(
34 | private val activity: Activity,
35 | private val cyanea: Cyanea,
36 | themeResId: Int
37 | ) : CyaneaDelegateImplBase(activity, cyanea, themeResId) {
38 |
39 | override fun onPostCreate(savedInstanceState: Bundle?) {
40 | tintSystemBars()
41 | super.onPostCreate(savedInstanceState)
42 | }
43 |
44 | private fun tintSystemBars() {
45 | if (cyanea.isThemeModified && Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
46 | val content = activity.findViewById(android.R.id.content)
47 | if (content is ViewGroup) {
48 | if (content.childCount == 1) {
49 | val child = content.getChildAt(0)
50 | if (child !is DrawerLayout) {
51 | child.fitsSystemWindows = true
52 | val id = activity.resources.getIdentifier(
53 | "config_enableTranslucentDecor", "bool", "android"
54 | )
55 | if (id != 0) {
56 | val enabled = activity.resources.getBoolean(id)
57 | if (enabled) {
58 | activity.window.setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS)
59 | if (cyanea.shouldTintNavBar) {
60 | activity.window.setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION)
61 | }
62 | tintBars()
63 | }
64 | }
65 | }
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/delegate/CyaneaDelegateImplV21.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.delegate
18 |
19 | import android.annotation.TargetApi
20 | import android.app.Activity
21 | import android.app.ActivityManager
22 | import android.content.ComponentName
23 | import android.content.pm.PackageManager
24 | import android.content.res.ColorStateList
25 | import android.graphics.BitmapFactory
26 | import android.graphics.drawable.BitmapDrawable
27 | import android.os.Build
28 | import android.os.Bundle
29 | import androidx.annotation.RequiresApi
30 | import com.jaredrummler.cyanea.Cyanea
31 | import com.jaredrummler.cyanea.R
32 | import com.jaredrummler.cyanea.getKey
33 | import com.jaredrummler.cyanea.utils.ColorUtils
34 | import com.jaredrummler.cyanea.utils.Reflection.Companion.getFieldValue
35 | import com.jaredrummler.cyanea.utils.Reflection.Companion.getMethod
36 |
37 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
38 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
39 | internal open class CyaneaDelegateImplV21(
40 | private val activity: Activity,
41 | private val cyanea: Cyanea,
42 | themeResId: Int
43 | ) : CyaneaDelegateImplV19(activity, cyanea, themeResId) {
44 |
45 | override fun onCreate(savedInstanceState: Bundle?) {
46 | super.onCreate(savedInstanceState)
47 | if (cyanea.isThemeModified) {
48 | when (Build.VERSION.SDK_INT) {
49 | Build.VERSION_CODES.LOLLIPOP,
50 | Build.VERSION_CODES.LOLLIPOP_MR1 -> {
51 | preloadColors()
52 | }
53 | }
54 | }
55 | }
56 |
57 | override fun onStart() {
58 | // Do not call super
59 | if (cyanea.isThemeModified) {
60 | // Set the task description with our custom primary color
61 | setTaskDescription()
62 | }
63 | }
64 |
65 | private fun setTaskDescription() {
66 | try {
67 | val color = ColorUtils.stripAlpha(cyanea.primary)
68 | val componentName = ComponentName(activity, activity::class.java)
69 | activity.packageManager.getActivityInfo(componentName, 0)
70 | .iconResource.takeIf { it != 0 }?.let { iconRes ->
71 | val td = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
72 | ActivityManager.TaskDescription(activity.title.toString(), iconRes, color)
73 | } else {
74 | val icon = BitmapFactory.decodeResource(activity.resources, iconRes) ?: return
75 | @Suppress("DEPRECATION")
76 | ActivityManager.TaskDescription(activity.title.toString(), icon, color)
77 | }
78 | activity.setTaskDescription(td)
79 | } ?: run {
80 | val icon = activity.packageManager.getApplicationIcon(activity.packageName)
81 | (icon as? BitmapDrawable)?.bitmap?.let { bitmap ->
82 | @Suppress("DEPRECATION")
83 | val td = ActivityManager.TaskDescription(activity.title.toString(), bitmap, color)
84 | activity.setTaskDescription(td)
85 | }
86 | }
87 | } catch (ignored: PackageManager.NameNotFoundException) {
88 | }
89 | }
90 |
91 | private fun preloadColors() {
92 | try {
93 | val cache = getFieldValue(activity.resources, "sPreloadedColorStateLists") ?: return
94 | val method = getMethod(cache, "put", Long::class.java, Object::class.java) ?: return
95 | for ((id, color) in hashMapOf().apply {
96 | put(R.color.cyanea_accent, cyanea.accent)
97 | }) {
98 | val csl = ColorStateList.valueOf(color)
99 | val key = activity.resources.getKey(id)
100 | method.invoke(cache, key, csl)
101 | }
102 | } catch (ex: Throwable) {
103 | Cyanea.log(TAG, "Error preloading colors", ex)
104 | }
105 | }
106 |
107 | companion object {
108 | private const val TAG = "CyaneaDelegateImplV21"
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/delegate/CyaneaDelegateImplV24.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.delegate
18 |
19 | import android.annotation.SuppressLint
20 | import android.annotation.TargetApi
21 | import android.app.Activity
22 | import android.content.res.ColorStateList
23 | import android.os.Build
24 | import android.os.Bundle
25 | import androidx.annotation.RequiresApi
26 | import com.jaredrummler.cyanea.Cyanea
27 | import com.jaredrummler.cyanea.R
28 | import com.jaredrummler.cyanea.getKey
29 | import com.jaredrummler.cyanea.utils.Reflection
30 |
31 | @RequiresApi(Build.VERSION_CODES.N)
32 | @TargetApi(Build.VERSION_CODES.N)
33 | internal open class CyaneaDelegateImplV24(
34 | private val activity: Activity,
35 | private val cyanea: Cyanea,
36 | themeResId: Int
37 | ) : CyaneaDelegateImplV23(activity, cyanea, themeResId) {
38 |
39 | override fun onCreate(savedInstanceState: Bundle?) {
40 | super.onCreate(savedInstanceState)
41 | if (cyanea.isThemeModified) {
42 | preloadColors()
43 | }
44 | }
45 |
46 | @SuppressLint("PrivateApi")
47 | private fun preloadColors() {
48 | try {
49 | val klass = Class.forName("android.content.res.ColorStateList\$ColorStateListFactory")
50 | val constructor = klass.getConstructor(ColorStateList::class.java).apply {
51 | if (!isAccessible) isAccessible = true
52 | }
53 |
54 | val mResourcesImpl = Reflection.getFieldValue(activity.resources, "mResourcesImpl") ?: return
55 | val cache = Reflection.getFieldValue(mResourcesImpl, "sPreloadedComplexColors") ?: return
56 | val method = Reflection.getMethod(cache, "put", Long::class.java, Object::class.java) ?: return
57 |
58 | for ((id, color) in hashMapOf().apply {
59 | put(R.color.cyanea_accent, cyanea.accent)
60 | }) {
61 | constructor.newInstance(ColorStateList.valueOf(color))?.let { factory ->
62 | val key = activity.resources.getKey(id)
63 | method.invoke(cache, key, factory)
64 | }
65 | }
66 | } catch (ex: Throwable) {
67 | Cyanea.log(TAG, "Error preloading colors", ex)
68 | }
69 | }
70 |
71 | companion object {
72 | private const val TAG = "CyaneaDelegateImplV24"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/delegate/CyaneaDelegateImplV26.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.delegate
18 |
19 | import android.annotation.TargetApi
20 | import android.app.Activity
21 | import android.os.Build
22 | import android.view.View
23 | import androidx.annotation.RequiresApi
24 | import com.jaredrummler.cyanea.Cyanea
25 | import com.jaredrummler.cyanea.tinting.SystemBarTint
26 | import com.jaredrummler.cyanea.utils.ColorUtils
27 |
28 | @RequiresApi(Build.VERSION_CODES.O)
29 | @TargetApi(Build.VERSION_CODES.O)
30 | internal open class CyaneaDelegateImplV26(
31 | private val activity: Activity,
32 | cyanea: Cyanea,
33 | themeResId: Int
34 | ) : CyaneaDelegateImplV24(activity, cyanea, themeResId) {
35 |
36 | override fun tintNavigationBar(color: Int, tinter: SystemBarTint) {
37 | super.tintNavigationBar(color, tinter)
38 | if (!ColorUtils.isDarkColor(color)) {
39 | activity.window.decorView.run {
40 | systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
41 | }
42 | }
43 | }
44 |
45 | companion object {
46 | private const val TAG = "CyaneaDelegateImplV26"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/delegate/CyaneaDelegateImplV29.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.delegate
18 |
19 | import android.annotation.TargetApi
20 | import android.app.Activity
21 | import android.os.Bundle
22 | import androidx.annotation.RequiresApi
23 | import com.jaredrummler.cyanea.Cyanea
24 | import com.jaredrummler.cyanea.R
25 |
26 | @RequiresApi(Build_VERSION_CODES_Q)
27 | @TargetApi(Build_VERSION_CODES_Q)
28 | internal open class CyaneaDelegateImplV29(
29 | activity: Activity,
30 | private val cyanea: Cyanea,
31 | themeResId: Int
32 | ) : CyaneaDelegateImplV26(activity, cyanea, themeResId) {
33 |
34 | override fun onCreate(savedInstanceState: Bundle?) {
35 | super.onCreate(savedInstanceState)
36 | if (!cyanea.isThemeModified) {
37 | // https://github.com/jaredrummler/Cyanea/issues/62
38 | val defaultPrimaryDark = Cyanea.getOriginalColor(R.color.cyanea_default_primary_dark)
39 | val realPrimaryDark = Cyanea.getOriginalColor(R.color.cyanea_primary_dark_reference)
40 | if (defaultPrimaryDark == realPrimaryDark) {
41 | tintBars()
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/inflator/CyaneaContextWrapper.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.inflator
18 |
19 | import android.content.Context
20 | import android.content.ContextWrapper
21 | import com.jaredrummler.cyanea.inflator.decor.CyaneaDecorator
22 |
23 | /**
24 | * A [ContextWrapper] that provides a [CyaneaLayoutInflater].
25 | */
26 | class CyaneaContextWrapper(
27 | context: Context,
28 | private val decorators: Array? = null,
29 | private val viewFactory: CyaneaViewFactory? = null
30 | ) :
31 | ContextWrapper(context) {
32 |
33 | private val inflater: CyaneaLayoutInflater by lazy {
34 | CyaneaLayoutInflater(this).apply {
35 | this.decorators = this@CyaneaContextWrapper.decorators
36 | this.viewFactory = this@CyaneaContextWrapper.viewFactory
37 | }
38 | }
39 |
40 | override fun getSystemService(name: String): Any? = when (name) {
41 | LAYOUT_INFLATER_SERVICE -> inflater
42 | else -> super.getSystemService(name)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/inflator/CyaneaInflationDelegate.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.inflator
18 |
19 | import android.content.Context
20 | import android.util.AttributeSet
21 | import android.view.View
22 | import com.jaredrummler.cyanea.Cyanea
23 |
24 | /**
25 | * Hook to create custom views at inflation time.
26 | *
27 | * @see Cyanea.setInflationDelegate
28 | */
29 | interface CyaneaInflationDelegate {
30 |
31 | /**
32 | * Hook you can supply that is called when inflating from a [CyaneaLayoutInflater].
33 | *
34 | * @param parent The parent that the created view will be placed in; note that this may be null.
35 | * @param name Tag name to be inflated.
36 | * @param context The context the view is being created in.
37 | * @param attrs Inflation attributes as specified in XML file.
38 | * @return Newly created view. Return null for the default behavior.
39 | */
40 | fun createView(parent: View?, name: String, context: Context, attrs: AttributeSet): View?
41 | }
42 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/inflator/CyaneaViewFactory.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.inflator
18 |
19 | import android.util.AttributeSet
20 | import android.view.View
21 | import com.jaredrummler.cyanea.Cyanea
22 | import java.util.Collections
23 |
24 | class CyaneaViewFactory(val cyanea: Cyanea, vararg processors: CyaneaViewProcessor) {
25 |
26 | private val processors = hashSetOf>()
27 |
28 | init {
29 | Collections.addAll(this.processors, *processors)
30 | }
31 |
32 | fun onViewCreated(view: View, attrs: AttributeSet): View {
33 | for (processor in processors) {
34 | try {
35 | if (processor.shouldProcessView(view)) {
36 | processor.process(view, attrs, cyanea)
37 | }
38 | } catch (e: Exception) {
39 | Cyanea.log(TAG, "Error processing view", e)
40 | }
41 | }
42 | return view
43 | }
44 |
45 | companion object {
46 | private const val TAG = "CyaneaViewFactory"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/inflator/decor/AttrsDecorator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.inflator.decor
18 |
19 | import android.content.Context
20 | import android.content.res.TypedArray
21 | import android.util.AttributeSet
22 | import android.util.TypedValue
23 | import android.view.View
24 |
25 | /**
26 | * A base class for a decorator that transform certain View subtypes with certain attributes. Useful when you want to
27 | * extend standard layout inflation to add your own attributes to system widgets.
28 | * If a view with type [AttrsDecorator.getType] is inflated and it has one of the attributes returned in
29 | * [AttrsDecorator.styleable] method then [AttrsDecorator.apply] will be invoked for that view.
30 | *
31 | * @param
32 | * The type or parent type of View that this decorator applies to.
33 | */
34 | abstract class AttrsDecorator : CyaneaDecorator {
35 |
36 | override fun apply(view: View, attrs: AttributeSet) {
37 | if (getType().isAssignableFrom(view.javaClass)) {
38 | val values = obtainAttributes(view.context, attrs)
39 | values?.let {
40 | try {
41 | for (i in 0 until values.length()) {
42 | val buf = TypedValue()
43 | if (it.hasValue(i) && it.getValue(i, buf)) {
44 | @Suppress("UNCHECKED_CAST")
45 | apply(view as T, it)
46 | break
47 | }
48 | }
49 | } finally {
50 | it.recycle()
51 | }
52 | }
53 | }
54 | }
55 |
56 | /**
57 | * This method will be called if a View of type T was inflated and it had one of the attributes specified by
58 | * [AttrsDecorator.styleable] set.
59 | *
60 | * @param view The view object that is being decorated.
61 | * @param typedArray A [TypedArray] for attributes.
62 | */
63 | protected abstract fun apply(view: T, typedArray: TypedArray)
64 |
65 | /**
66 | * The class for the given view
67 | *
68 | * @return The class for T
69 | */
70 | protected abstract fun getType(): Class
71 |
72 | /**
73 | * Attributes supported by this decorator.
74 | *
75 | * @return an array of android attr resource ids.
76 | */
77 | protected abstract fun styleable(): IntArray
78 |
79 | /**
80 | * The default style specified by `defStyleAttr`
81 | *
82 | * @return An attribute in the current theme that contains a reference to a style resource that supplies defaults
83 | * values for the TypedArray. Can be `0` to not look for defaults.
84 | */
85 | @Suppress("MemberVisibilityCanBePrivate")
86 | protected fun defStyleAttr(): Int = 0
87 |
88 | /**
89 | * The style resource specified in the AttributeSet (named "style").
90 | *
91 | * @return A resource identifier of a style resource that supplies default values for the TypedArray, used only if
92 | * defStyleAttr is `0` or can not be found in the theme. Can be `0` to not look for defaults.
93 | */
94 | @Suppress("MemberVisibilityCanBePrivate")
95 | protected fun defStyleRes(): Int = 0
96 |
97 | /**
98 | * Get the attributes
99 | *
100 | * @param context the context held by the view
101 | * @param attributeSet A read-only set of tag attributes.
102 | * @return a TypedArray holding an array of the attribute values.
103 | */
104 | @Suppress("MemberVisibilityCanBePrivate")
105 | protected fun obtainAttributes(context: Context, attributeSet: AttributeSet): TypedArray? =
106 | context.theme.obtainStyledAttributes(attributeSet, styleable(), defStyleAttr(), defStyleRes())
107 | }
108 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/inflator/decor/CyaneaDecorator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.inflator.decor
18 |
19 | import android.util.AttributeSet
20 | import android.view.View
21 |
22 | /**
23 | * A class that operates on already constructed views, i.e., decorates them.
24 | */
25 | interface CyaneaDecorator {
26 |
27 | /**
28 | * Decorates the given view. This method will be called for every [View] that is created.
29 | *
30 | * @param view
31 | * The view to decorate. Never null.
32 | * @param attrs
33 | * A read-only set of tag attributes.
34 | */
35 | fun apply(view: View, attrs: AttributeSet)
36 |
37 | /**
38 | * An interface that may be used in an [activity][android.app.Activity] to provide [decorators][CyaneaDecorator]
39 | * to the [delegate][com.jaredrummler.cyanea.delegate.CyaneaDelegate]
40 | */
41 | interface Provider {
42 |
43 | /**
44 | * Get an array of [decorators][CyaneaDecorator] to style views.
45 | *
46 | * @return An array of decorators for the [delegate][com.jaredrummler.cyanea.delegate.CyaneaDelegate].
47 | */
48 | fun getDecorators(): Array
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/inflator/decor/FontDecorator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.inflator.decor
18 |
19 | import android.content.res.AssetManager
20 | import android.content.res.TypedArray
21 | import android.graphics.Typeface
22 | import android.widget.TextView
23 | import com.jaredrummler.cyanea.R
24 |
25 | /**
26 | * Set a font from assets by adding an attribute to the view in your layout XML.
27 | *
28 | * ```xml
29 | *
33 | * ```
34 | */
35 | class FontDecorator : AttrsDecorator() {
36 |
37 | private val cache = mutableMapOf()
38 |
39 | override fun getType(): Class = TextView::class.java
40 |
41 | override fun styleable(): IntArray = R.styleable.FontDecorator
42 |
43 | override fun apply(view: TextView, typedArray: TypedArray) {
44 | typedArray.getString(R.styleable.FontDecorator_cyaneaFont)?.let { path ->
45 | view.typeface = getFont(view.context.assets, path)
46 | }
47 | }
48 |
49 | private fun getFont(assets: AssetManager, path: String): Typeface? {
50 | return cache[path] ?: run {
51 | try {
52 | Typeface.createFromAsset(assets, path)?.let { font ->
53 | cache[path] = font
54 | font
55 | }
56 | } catch (e: Exception) {
57 | null
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/prefs/CyaneaSettingsActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.prefs
18 |
19 | import android.os.Bundle
20 | import android.view.MenuItem
21 | import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
22 |
23 | /**
24 | * Activity to show Cyanea preferences allowing the user to modify the primary, accent and background color of the app.
25 | */
26 | open class CyaneaSettingsActivity : CyaneaAppCompatActivity() {
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | supportActionBar?.setDisplayHomeAsUpEnabled(true)
31 | if (savedInstanceState == null) {
32 | supportFragmentManager.beginTransaction()
33 | .add(android.R.id.content, CyaneaSettingsFragment.newInstance())
34 | .commit()
35 | }
36 | }
37 |
38 | override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
39 | android.R.id.home -> {
40 | finish()
41 | true
42 | }
43 | else -> super.onOptionsItemSelected(item)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/prefs/CyaneaThemePickerActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.prefs
18 |
19 | import android.os.Bundle
20 | import android.view.MenuItem
21 | import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
22 |
23 | /**
24 | * Activity to display a theme picker with pre-created themees.
25 | *
26 | * The themes will be read from assets/themes/cyanea_themes.json
27 | */
28 | class CyaneaThemePickerActivity : CyaneaAppCompatActivity() {
29 |
30 | override fun onCreate(savedInstanceState: Bundle?) {
31 | super.onCreate(savedInstanceState)
32 | supportActionBar?.setDisplayHomeAsUpEnabled(true)
33 | if (savedInstanceState == null) {
34 | supportFragmentManager.beginTransaction()
35 | .add(android.R.id.content, CyaneaThemePickerFragment.newInstance())
36 | .commit()
37 | }
38 | }
39 |
40 | override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
41 | android.R.id.home -> {
42 | finish()
43 | true
44 | }
45 | else -> super.onOptionsItemSelected(item)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/prefs/CyaneaThemePickerAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.prefs
18 |
19 | import android.content.res.ColorStateList
20 | import android.graphics.Color
21 | import android.graphics.PorterDuff
22 | import android.util.SparseArray
23 | import android.view.LayoutInflater
24 | import android.view.View
25 | import android.view.ViewGroup
26 | import android.widget.BaseAdapter
27 | import android.widget.FrameLayout
28 | import android.widget.ImageView
29 | import android.widget.LinearLayout
30 | import android.widget.TextView
31 | import androidx.annotation.IdRes
32 | import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
33 | import androidx.core.content.ContextCompat
34 | import com.google.android.material.floatingactionbutton.FloatingActionButton
35 | import com.jaredrummler.cyanea.Cyanea
36 | import com.jaredrummler.cyanea.R
37 | import com.jaredrummler.cyanea.utils.ColorUtils
38 |
39 | /**
40 | * Adapter for items in the theme picker
41 | */
42 | class CyaneaThemePickerAdapter(private val themes: List, private val cyanea: Cyanea) : BaseAdapter() {
43 |
44 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
45 | val holder: ViewHolder
46 |
47 | holder = if (convertView == null) {
48 | val inflater = LayoutInflater.from(parent.context)
49 | val view = inflater.inflate(R.layout.cyanea_item_theme, parent, false)
50 | ViewHolder(view)
51 | } else {
52 | convertView.tag as ViewHolder
53 | }
54 |
55 | val theme = themes[position]
56 |
57 | holder.find(R.id.preview).setBackgroundColor(theme.background)
58 | holder.find(R.id.action_bar_panel).setBackgroundColor(theme.primary)
59 |
60 | val fab = holder.find(R.id.fab_add)
61 | // Bug: when using the accent color, the last selected item's FAB is the same color as the newly selected FAB.
62 | // For now, slightly adjust the color.
63 | val fabMainColor = ColorUtils.lighter(theme.accent, 0.01f)
64 | fab.backgroundTintList = ColorStateList.valueOf(fabMainColor)
65 | fab.supportBackgroundTintList = ColorStateList.valueOf(fabMainColor)
66 | fab.rippleColor = theme.accentDark
67 |
68 | val title = holder.find(R.id.title)
69 | title.text = theme.themeName
70 |
71 | if (theme.isMatchingColorScheme(cyanea)) {
72 | title.setBackgroundColor(ContextCompat.getColor(parent.context, R.color.cyanea_theme_selected_color))
73 | title.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.cyanea_check, 0)
74 | } else {
75 | title.setBackgroundColor(ContextCompat.getColor(parent.context, R.color.cyanea_theme_title_bg_color))
76 | title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
77 | }
78 |
79 | val isDark = ColorUtils.isDarkColor(theme.primary, 0.75)
80 | val menuIconColor = if (isDark) Color.WHITE else Color.BLACK
81 | val drawable = DrawerArrowDrawable(parent.context)
82 | drawable.color = menuIconColor
83 |
84 | val drawer = holder.find(R.id.material_drawer_drawable)
85 | val overflow = holder.find(R.id.action_overflow)
86 | drawer.setImageDrawable(drawable)
87 | overflow.setColorFilter(menuIconColor, PorterDuff.Mode.SRC_ATOP)
88 |
89 | return holder.itemView
90 | }
91 |
92 | override fun getItem(position: Int): CyaneaTheme = themes[position]
93 |
94 | override fun getItemId(position: Int): Long = position.toLong()
95 |
96 | override fun getCount(): Int = themes.size
97 |
98 | private class ViewHolder(val itemView: View) {
99 |
100 | private val views = SparseArray()
101 |
102 | init {
103 | itemView.tag = this
104 | }
105 |
106 | fun find(@IdRes id: Int): T {
107 | views[id]?.let {
108 | @Suppress("UNCHECKED_CAST")
109 | return it as T
110 | } ?: run {
111 | val view = itemView.findViewById(id)
112 | views.put(id, view)
113 | return view
114 | }
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/prefs/CyaneaThemePickerFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.prefs
18 |
19 | import android.os.Bundle
20 | import android.view.LayoutInflater
21 | import android.view.View
22 | import android.view.ViewGroup
23 | import android.widget.AdapterView
24 | import android.widget.AdapterView.OnItemClickListener
25 | import android.widget.GridView
26 | import com.jaredrummler.cyanea.Cyanea
27 | import com.jaredrummler.cyanea.R
28 | import com.jaredrummler.cyanea.app.CyaneaFragment
29 |
30 | /**
31 | * Fragment containing the theme picker
32 | */
33 | open class CyaneaThemePickerFragment : CyaneaFragment(), OnItemClickListener {
34 |
35 | open val themesJsonAssetPath get() = "themes/cyanea_themes.json"
36 |
37 | private lateinit var gridView: GridView
38 |
39 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
40 | return inflater.inflate(R.layout.cyanea_theme_picker, container, false)
41 | }
42 |
43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
44 | super.onViewCreated(view, savedInstanceState)
45 | gridView = view.findViewById(R.id.gridView)
46 | val themes = CyaneaTheme.from(requireActivity().assets, themesJsonAssetPath)
47 | gridView.adapter = CyaneaThemePickerAdapter(themes, cyanea)
48 | gridView.onItemClickListener = this
49 | scrollToCurrentTheme(themes)
50 | }
51 |
52 | override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
53 | val theme = (gridView.adapter as CyaneaThemePickerAdapter).getItem(position)
54 | val themeName = theme.themeName
55 | Cyanea.log(TAG, "Clicked $themeName")
56 | theme.apply(cyanea).recreate(requireActivity(), smooth = true)
57 | }
58 |
59 | private fun scrollToCurrentTheme(themes: List) {
60 | var selectedTheme = -1
61 | run {
62 | themes.forEachIndexed { index, theme ->
63 | if (theme.isMatchingColorScheme(cyanea)) {
64 | selectedTheme = index
65 | return@run
66 | }
67 | }
68 | }
69 | if (selectedTheme != -1) {
70 | gridView.post {
71 | if (selectedTheme < gridView.firstVisiblePosition || selectedTheme > gridView.lastVisiblePosition) {
72 | gridView.setSelection(selectedTheme)
73 | }
74 | }
75 | }
76 | }
77 |
78 | companion object {
79 | private const val TAG = "ThemePickerFragment"
80 |
81 | fun newInstance() = CyaneaThemePickerFragment()
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/tinting/WidgetTint.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.tinting
18 |
19 | import android.graphics.PorterDuff
20 | import android.graphics.drawable.Drawable
21 | import android.os.Build
22 | import android.widget.AbsListView
23 | import android.widget.ImageView
24 | import android.widget.TextView
25 | import androidx.annotation.ColorInt
26 | import androidx.core.content.ContextCompat
27 | import com.jaredrummler.cyanea.Cyanea
28 | import com.jaredrummler.cyanea.utils.ColorFilterCompat
29 | import com.jaredrummler.cyanea.utils.Reflection
30 |
31 | /**
32 | * Contains helper functions to tint aspects of various widgets
33 | */
34 | class WidgetTint private constructor() {
35 |
36 | init {
37 | throw AssertionError("no instances")
38 | }
39 |
40 | companion object {
41 |
42 | private const val TAG = "WidgetTint"
43 |
44 | /**
45 | * Uses reflection to set the color on the fast scroll thumb in a ListView or GridView.
46 | *
47 | * @param listView The ListView or GridView.
48 | * @param color The color to set the fast scroll thumb.
49 | */
50 | fun setFastScrollThumbColor(listView: AbsListView, @ColorInt color: Int) {
51 | try {
52 | val name = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) "mFastScroll" else "mFastScroller"
53 | val scroller = Reflection.getFieldValue(listView, name)
54 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
55 | Reflection.getFieldValue(scroller, "mThumbImage")
56 | ?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
57 | } else {
58 | Reflection.getFieldValue(scroller, "mThumbDrawable")
59 | ?.colorFilter = ColorFilterCompat.SRC_ATOP.get(color)
60 | }
61 | } catch (e: Exception) {
62 | Cyanea.log(TAG, "Error tinting the fast scroll thumb", e)
63 | }
64 | }
65 |
66 | /**
67 | * Set the cursor color on an EditText.
68 | *
69 | * @param textView The view to tint, must extend or be a [TextView]
70 | * @param color The color value used to tint the cursor drawable.
71 | */
72 | fun setCursorColor(textView: TextView, @ColorInt color: Int) {
73 | try {
74 | Reflection.getField(TextView::class.java, "mCursorDrawableRes")?.let { fCursorDrawableRes ->
75 | Reflection.getField(TextView::class.java, "mEditor")?.let { fEditor ->
76 | fEditor.get(textView)?.let { editor ->
77 | Reflection.getField(editor, "mCursorDrawable")?.let { fCursorDrawable ->
78 | val cursorDrawableRes = fCursorDrawableRes.getInt(textView)
79 | ContextCompat.getDrawable(textView.context, cursorDrawableRes)?.let { drawable ->
80 | @Suppress("DEPRECATION")
81 | drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN)
82 | val drawables = arrayOf(drawable, drawable)
83 | fCursorDrawable.set(editor, drawables)
84 | }
85 | }
86 | }
87 | }
88 | }
89 | } catch (e: Exception) {
90 | Cyanea.log(TAG, "Error setting cursor color", e)
91 | }
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/cyanea/utils/ColorFilterCompat.kt:
--------------------------------------------------------------------------------
1 | package com.jaredrummler.cyanea.utils
2 |
3 | import android.graphics.BlendMode
4 | import android.graphics.BlendModeColorFilter
5 | import android.graphics.ColorFilter
6 | import android.graphics.PorterDuff
7 | import android.graphics.PorterDuffColorFilter
8 | import android.os.Build
9 | import androidx.annotation.ColorInt
10 | import androidx.annotation.RequiresApi
11 |
12 | /** Get a [ColorFilter] using [BlendMode] on API 29+ and [PorterDuff.Mode] on older APIs */
13 | internal enum class ColorFilterCompat {
14 | CLEAR, SRC, DST, SRC_OVER, DST_OVER, SRC_IN, DST_IN, SRC_OUT, DST_OUT,
15 | SRC_ATOP, DST_ATOP, XOR, DARKEN, LIGHTEN, MULTIPLY, SCREEN, ADD, OVERLAY;
16 |
17 | private val porterDuffMode: PorterDuff.Mode
18 | get() = when (this) {
19 | CLEAR -> PorterDuff.Mode.CLEAR
20 | SRC -> PorterDuff.Mode.SRC
21 | DST -> PorterDuff.Mode.DST
22 | SRC_OVER -> PorterDuff.Mode.SRC_OVER
23 | DST_OVER -> PorterDuff.Mode.DST_OVER
24 | SRC_IN -> PorterDuff.Mode.SRC_IN
25 | DST_IN -> PorterDuff.Mode.DST_IN
26 | SRC_OUT -> PorterDuff.Mode.SRC_OUT
27 | DST_OUT -> PorterDuff.Mode.DST_OUT
28 | SRC_ATOP -> PorterDuff.Mode.SRC_ATOP
29 | DST_ATOP -> PorterDuff.Mode.DST_ATOP
30 | XOR -> PorterDuff.Mode.XOR
31 | DARKEN -> PorterDuff.Mode.DARKEN
32 | LIGHTEN -> PorterDuff.Mode.LIGHTEN
33 | MULTIPLY -> PorterDuff.Mode.MULTIPLY
34 | SCREEN -> PorterDuff.Mode.SCREEN
35 | ADD -> PorterDuff.Mode.ADD
36 | OVERLAY -> PorterDuff.Mode.OVERLAY
37 | }
38 |
39 | @get:RequiresApi(Build.VERSION_CODES.Q)
40 | private val blendMode: BlendMode
41 | get() = when (this) {
42 | CLEAR -> BlendMode.CLEAR
43 | SRC -> BlendMode.SRC
44 | DST -> BlendMode.DST
45 | SRC_OVER -> BlendMode.SRC_OVER
46 | DST_OVER -> BlendMode.DST_OVER
47 | SRC_IN -> BlendMode.SRC_IN
48 | DST_IN -> BlendMode.DST_IN
49 | SRC_OUT -> BlendMode.SRC_OUT
50 | DST_OUT -> BlendMode.DST_OUT
51 | SRC_ATOP -> BlendMode.SRC_ATOP
52 | DST_ATOP -> BlendMode.DST_ATOP
53 | XOR -> BlendMode.XOR
54 | DARKEN -> BlendMode.DARKEN
55 | LIGHTEN -> BlendMode.LIGHTEN
56 | MULTIPLY -> BlendMode.MULTIPLY
57 | SCREEN -> BlendMode.SCREEN
58 | ADD -> BlendMode.PLUS
59 | OVERLAY -> BlendMode.OVERLAY
60 | }
61 |
62 | fun get(@ColorInt color: Int): ColorFilter = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
63 | BlendModeColorFilter(color, blendMode)
64 | } else {
65 | PorterDuffColorFilter(color, porterDuffMode)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/library/src/main/res-public/values/public.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_accent.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_accent_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_accent_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_bg_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_bg_dark_darker.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_bg_dark_lighter.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_bg_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_bg_light_darker.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_bg_light_lighter.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_primary.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_primary_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/color/cyanea_primary_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/cyanea_popup_background.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/library/src/main/res/drawable-hdpi/cyanea_popup_background.9.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/cyanea_popup_background.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/library/src/main/res/drawable-mdpi/cyanea_popup_background.9.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-v21/cyanea_bg_button_accent.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
22 | -
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable-v21/cyanea_bg_button_primary.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
22 | -
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/cyanea_popup_background.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/library/src/main/res/drawable-xhdpi/cyanea_popup_background.9.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/cyanea_popup_background.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaredrummler/Cyanea/2a7dc7b915cd987893b103b9bfad6c23d223681e/library/src/main/res/drawable-xxhdpi/cyanea_popup_background.9.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_accent.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_button_accent.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 | -
22 |
23 |
24 |
25 |
26 |
27 | -
28 |
29 |
30 |
31 |
32 |
33 | -
34 |
35 |
36 |
37 |
38 |
39 | -
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_button_primary.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 | -
22 |
23 |
24 |
25 |
26 | -
27 |
28 |
29 |
30 |
31 | -
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_dark_darker.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_dark_lighter.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_light_darker.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_light_lighter.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_popup_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | -
25 |
26 |
27 |
28 |
29 |
30 |
31 | -
32 |
33 |
34 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_bg_popup_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | -
25 |
26 |
27 |
28 |
29 |
30 |
31 | -
32 |
33 |
34 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_fab_add.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_primary.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/cyanea_primary_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cyanea_item_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
21 |
22 |
28 |
29 |
36 |
37 |
44 |
45 |
55 |
56 |
69 |
70 |
71 |
82 |
83 |
95 |
96 |
97 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/cyanea_theme_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 180dp
4 |
--------------------------------------------------------------------------------
/library/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Seletor de temas
3 |
4 | Temas
5 | Selecione um tema pré-instalado
6 |
7 | Cor primária
8 | Exibida com mais frequência no seu aplicativo.
9 |
10 | Cor de destaque
11 | Destaca certas partes da interface.
12 |
13 | Cor de fundo
14 | A cor de fundo do conteúdo do aplicativo.
15 | Aparência
16 |
17 | Cor da barra de navegação
18 | Aplique a cor primária à barra de navegação
19 |
--------------------------------------------------------------------------------
/library/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FFFAFAFA
5 | #FF303030
6 | #FF000000
7 | #FF182628
8 | #FF21263A
9 |
10 |
11 | - @color/cyanea_background_material_light
12 | - @color/cyanea_background_material_dark
13 | - @color/cyanea_background_black
14 | - @color/cyanea_background_dark_green
15 | - @color/cyanea_background_dark_blue
16 |
17 |
18 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/library/src/main/res/values/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 | true
21 | true
22 | false
23 |
--------------------------------------------------------------------------------
/library/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
25 |
26 | #09000000
27 | #08000000
28 | #05000000
29 | #03000000
30 |
31 |
32 |
33 | #FFC2185B
34 | @color/cyanea_default_primary_light
35 | @color/cyanea_default_primary_dark
36 |
37 |
38 |
39 | #FF1976D2
40 | @color/cyanea_default_accent_light
41 | @color/cyanea_default_accent_dark
42 |
43 |
44 |
45 | #FF303030
46 | #FF1E1E1E
47 | #FF2D2D2D
48 | #FFFAFAFA
49 | #FFC0C0C0
50 | #FFF8F8F8
51 | @color/cyanea_background_dark
52 | @color/cyanea_background_light
53 |
54 |
55 |
56 | @color/cyanea_primary_reference
57 |
58 |
59 |
60 | #FFFFFFFF
61 | #DE000000
62 | #B3FFFFFF
63 | #8A000000
64 |
65 |
66 |
67 | #FF9E9E9E
68 |
69 |
70 |
71 | #FF757575
72 |
73 |
74 | #CC37474F
75 | #FF689F38
76 |
77 |
--------------------------------------------------------------------------------
/library/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 140dp
4 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Theme Picker
3 |
4 | Themes
5 | Select a pre-installed theme
6 |
7 | Primary color
8 | Displayed most frequently across your app.
9 |
10 | Accent color
11 | Accents select parts of the UI.
12 |
13 | Background color
14 | The underlying color of the app’s content.
15 | Appearance
16 |
17 | Navigation bar color
18 | Apply the primary color to the navigation bar
19 |
20 |
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
61 |
62 |
63 |
64 |
67 |
68 |
--------------------------------------------------------------------------------
/library/src/main/res/xml/pref_cyanea.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
14 |
15 |
22 |
23 |
30 |
31 |
40 |
41 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/library/src/test/java/com/jaredrummler/cyanea/CyaneaResourcesTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea
18 |
19 | import android.app.Application
20 | import android.content.res.Resources
21 | import android.graphics.drawable.ColorDrawable
22 | import androidx.annotation.ColorInt
23 | import com.jaredrummler.cyanea.utils.Reflection
24 | import com.nhaarman.mockitokotlin2.mock
25 | import com.nhaarman.mockitokotlin2.whenever
26 | import org.hamcrest.CoreMatchers.instanceOf
27 | import org.junit.Assert.assertEquals
28 | import org.junit.Assert.assertThat
29 | import org.junit.Before
30 | import org.junit.Test
31 | import org.junit.runner.RunWith
32 | import org.mockito.ArgumentMatchers.anyInt
33 | import org.mockito.ArgumentMatchers.anyString
34 | import org.mockito.Mock
35 | import org.mockito.junit.MockitoJUnitRunner
36 |
37 | @RunWith(MockitoJUnitRunner.Silent::class)
38 | class CyaneaResourcesTest {
39 |
40 | @Mock private lateinit var app: Application
41 | @Mock private lateinit var res: Resources
42 | private lateinit var cyanea: Cyanea
43 |
44 | @Before fun setUp() {
45 | whenever(app.getSharedPreferences(anyString(), anyInt()))
46 | .thenReturn(mock())
47 | Cyanea.init(app, res)
48 | cyanea = Cyanea.instance
49 | }
50 |
51 | @Test fun `should return color drawables for background colors`() {
52 | val resources = CyaneaResources(res)
53 |
54 | val drawableIds = arrayOf(
55 | R.drawable.cyanea_bg_dark,
56 | R.drawable.cyanea_bg_dark_lighter,
57 | R.drawable.cyanea_bg_dark_darker,
58 | R.drawable.cyanea_bg_light,
59 | R.drawable.cyanea_bg_light_lighter,
60 | R.drawable.cyanea_bg_light_darker
61 | )
62 |
63 | drawableIds.forEach { resid ->
64 | @Suppress("DEPRECATION")
65 | val drawable = resources.getDrawable(resid)
66 | assertThat(drawable, instanceOf(ColorDrawable::class.java))
67 | }
68 | }
69 |
70 | @Test fun `cyanea resources should return cyanea primary color`() {
71 | val resources = CyaneaResources(res)
72 |
73 | setCyaneaColor(0xFF0099CC.toInt(), "primary")
74 | @Suppress("DEPRECATION")
75 | val color = resources.getColor(R.color.cyanea_primary)
76 |
77 | assertEquals(cyanea.primary, color)
78 | }
79 |
80 | @Test fun `cyanea resources should return cyanea accent color`() {
81 | val resources = CyaneaResources(res)
82 |
83 | setCyaneaColor(0xFF0099CC.toInt(), "accent")
84 | @Suppress("DEPRECATION")
85 | val color = resources.getColor(R.color.cyanea_accent)
86 |
87 | assertEquals(cyanea.accent, color)
88 | }
89 |
90 | private fun setCyaneaColor(@ColorInt color: Int, name: String) {
91 | Reflection.getField(cyanea, name)?.let { field ->
92 | Reflection.setFieldValue(field, cyanea, color)
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/library/src/test/java/com/jaredrummler/cyanea/CyaneaTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea
18 |
19 | import android.app.Application
20 | import android.content.res.Resources
21 | import com.jaredrummler.cyanea.Cyanea.BaseTheme
22 | import com.nhaarman.mockitokotlin2.mock
23 | import com.nhaarman.mockitokotlin2.whenever
24 | import org.junit.Assert.assertEquals
25 | import org.junit.Assert.assertNotNull
26 | import org.junit.Before
27 | import org.junit.Test
28 | import org.junit.runner.RunWith
29 | import org.mockito.ArgumentMatchers.anyInt
30 | import org.mockito.ArgumentMatchers.anyString
31 | import org.mockito.Mock
32 | import org.mockito.junit.MockitoJUnitRunner
33 |
34 | @RunWith(MockitoJUnitRunner.Silent::class)
35 | class CyaneaTest {
36 |
37 | @Mock private lateinit var application: Application
38 | @Mock private lateinit var resources: Resources
39 |
40 | @Before fun setUp() {
41 | whenever(application.getSharedPreferences(anyString(), anyInt()))
42 | .thenReturn(mock())
43 |
44 | Cyanea.init(application, resources)
45 | }
46 |
47 | @Test fun `should return singleton instance`() {
48 | assertNotNull(Cyanea.instance)
49 | }
50 |
51 | @Test fun `should return dark background when base theme is dark`() {
52 | val cyanea = Cyanea.instance
53 | val expectedColor = 0xFF000000.toInt()
54 |
55 | cyanea.apply {
56 | baseTheme = BaseTheme.DARK
57 | backgroundDark = 0xFF000000.toInt()
58 | }
59 |
60 | assertEquals(expectedColor, cyanea.backgroundColor)
61 | }
62 |
63 | @Test fun `should return light background when base theme is light`() {
64 | val cyanea = Cyanea.instance
65 | val expectedColor = 0xFFFFFFFF.toInt()
66 |
67 | cyanea.apply {
68 | baseTheme = BaseTheme.LIGHT
69 | backgroundLight = 0xFFFFFFFF.toInt()
70 | }
71 |
72 | assertEquals(expectedColor, cyanea.backgroundColor)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/library/src/test/java/com/jaredrummler/cyanea/utils/ReflectionTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jaredrummler.cyanea.utils
18 |
19 | import com.jaredrummler.cyanea.utils.Reflection.Companion.getMethod
20 | import org.junit.Assert.assertEquals
21 | import org.junit.Assert.assertNotNull
22 | import org.junit.Test
23 | import kotlin.Int
24 | import kotlin.NullPointerException
25 | import kotlin.String
26 | import kotlin.arrayOf
27 |
28 | class ReflectionTest {
29 |
30 | @Test fun `should get method via reflection`() {
31 | val method = getMethod(StringBuilder(), "append", Int::class.java)
32 |
33 | val expectedName = "append"
34 | val expectedReturnType = StringBuilder::class.java
35 |
36 | assertEquals(expectedName, method?.name)
37 | assertEquals(expectedReturnType, method?.returnType)
38 | }
39 |
40 | @Test fun `should get field via reflection`() {
41 | val field = Reflection.getField(Class.forName("java.lang.Boolean"), "TRUE")
42 |
43 | val expectedType = "java.lang.Boolean"
44 | val expectedName = "TRUE"
45 |
46 | assertNotNull(field)
47 | assertEquals(expectedName, field?.name)
48 | assertEquals(expectedType, field?.type?.name)
49 | }
50 |
51 | @Test fun `should set field via reflection`() {
52 | val field = Reflection.getField(Class.forName("java.lang.Boolean"), "TRUE") ?: throw NullPointerException()
53 | Reflection.setFieldValue(field, null, java.lang.Boolean.FALSE)
54 | assertEquals(java.lang.Boolean.FALSE, java.lang.Boolean.TRUE)
55 | }
56 |
57 | @Test fun `should invoke method via reflection`() {
58 | val obj = "foo"
59 | val types = arrayOf>(CharSequence::class.java, CharSequence::class.java)
60 | val result = Reflection.invoke(obj, "replace", types, "foo", "bar")
61 | assertEquals("bar", result)
62 |
63 | val string = "baz"
64 | val length = Reflection.invoke(string, "length")
65 | assertEquals(string.length, length)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'Cyanea'
2 |
3 | include ':demo-main'
4 | include ':demo-simple-java'
5 | include ':library'
6 |
--------------------------------------------------------------------------------