Skip to content

Commit 2aacfbf

Browse files
authored
Merge pull request material-components#23 from material-components/material_theme_builder
Move Material Theme Builder from MDC library repo to material-components-android-examples.
2 parents 374b9c8 + b8ae7de commit 2aacfbf

File tree

123 files changed

+5458
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

123 files changed

+5458
-0
lines changed

MaterialThemeBuilder/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## Build a Material Theme
2+
Build a Material Theme lets you create your own Material theme by customizing values for color, typography, and shape. See how these values appear when applied to Material Components and discover how to implement your custom theme in your own projects. Build a Material Theme is also available for the web as a remixable project on [Glitch](https://glitch.com/~material-theme-builder).
3+
4+
## Overview
5+
Material Components for Android supports Material Theming by exposing top level theme attributes for color, typography and shape. Customizing these attributes will apply your custom theme throughout your entire app.
6+
7+
This project shows how you can organize and use your theme and style resources to take advantage of the robust support for theming in Material Components for Android.
8+
9+
## Change values for typography, shape, and color
10+
By default, apps built with Material Components inherit our baseline theme values. To begin customizing, override properties in `color.xml`, `type.xml` and `shape.xml`. Each file includes detailed comments that illustrate how each subsystem can be customized.
11+
12+
### type.xml
13+
To change your theme’s typography, we recommend using [Google Fonts](https://fonts.google.com/) and choosing a font family that best reflects your style. Set TextApperances to use your custom font and additional type properties to apply a custom type scale globally. [Learn how to add fonts in Android Studio](https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts)
14+
15+
### shape.xml
16+
To systematically apply shape throughout your app, it helps to understand that components are grouped by size into categories of small, medium and large. The shape of each component size group can be themed by customizing its ShapeApperance style. We recommend using our [shape customization tool](https://material.io/design/shape/about-shape.html#shape-customization-tool) to help you pick your corner family and size values.
17+
18+
### color.xml
19+
To change your theme's color scheme, replace the existing HEX color values with your custom HEX values. This project has both light and dark themes, toggle between them within the app to see your changes. Use our [color palette generator](https://material.io/design/color/the-color-system.html#tools-for-picking-colors) to help come up with pairings and check your color contrast.
20+
21+
## Get Started
22+
Clone the material-components-android-examples repository
23+
24+
```
25+
git clone https://github.com/material-components/material-components-android-examples.git
26+
```
27+
28+
In Android Studio - Choose ‘Open an existing Android Studio Project’ and select ‘material-components-android-examples/MaterialThemeBuilder’
29+
30+
Sync, build and run the project. The project, by default, will be configured with the baseline Material theme.
31+
32+
Under the ‘res’ folder, open `color.xml`, `type.xml` and `shape.xml`. Each file has detailed comments describing the Material subsystem it controls. Try modifying each subsystem, re-running the app and seeing how changes are propagated throughout the app.
33+
34+
Once you build your Material theme, move the theme resources (`color.xml`, `type.xml`, `shape.xml`, `styles.xml`, `themes.xml` and `night/themes.xml`) over to your app to start using your Material theme in your own projects.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
apply plugin: 'com.android.application'
2+
apply plugin: 'kotlin-android'
3+
4+
android {
5+
compileSdkVersion 29
6+
defaultConfig {
7+
applicationId "io.material.materialthemebuilder"
8+
minSdkVersion 23
9+
targetSdkVersion 29
10+
versionCode 1
11+
versionName "1.0"
12+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13+
}
14+
buildTypes {
15+
release {
16+
minifyEnabled false
17+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18+
}
19+
}
20+
compileOptions {
21+
sourceCompatibility = 1.8
22+
targetCompatibility = 1.8
23+
}
24+
kotlinOptions {
25+
jvmTarget = "1.8"
26+
}
27+
}
28+
29+
dependencies {
30+
implementation fileTree(dir: 'libs', include: ['*.jar'])
31+
32+
// Kotlin
33+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
34+
35+
// AndroidX
36+
implementation 'androidx.appcompat:appcompat:1.1.0'
37+
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
38+
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
39+
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha01'
40+
implementation 'androidx.core:core-ktx:1.1.0'
41+
42+
//MDC
43+
implementation 'com.google.android.material:material:1.2.0-alpha03'
44+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright (C) 2019 The Android Open Source Project
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
19+
xmlns:tools="http://schemas.android.com/tools"
20+
package="io.material.materialthemebuilder">
21+
22+
<application
23+
android:name=".App"
24+
android:allowBackup="true"
25+
android:icon="@mipmap/ic_launcher"
26+
android:label="@string/app_name"
27+
android:roundIcon="@mipmap/ic_launcher_round"
28+
android:supportsRtl="true"
29+
android:theme="@style/Theme.MyApp"
30+
tools:ignore="GoogleAppIndexingWarning">
31+
<activity android:name=".ui.MainActivity"
32+
android:exported="true">
33+
<intent-filter>
34+
<action android:name="android.intent.action.MAIN"/>
35+
36+
<category android:name="android.intent.category.LAUNCHER"/>
37+
</intent-filter>
38+
</activity>
39+
<meta-data
40+
android:name="preloaded_fonts"
41+
android:resource="@array/preloaded_fonts" />
42+
</application>
43+
44+
</manifest>
42.2 KB
Loading
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2019 The Android Open Source Project
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 io.material.materialthemebuilder
18+
19+
import android.app.Application
20+
import android.content.Context
21+
import io.material.materialthemebuilder.data.PreferenceRepository
22+
23+
class App : Application() {
24+
25+
lateinit var preferenceRepository: PreferenceRepository
26+
27+
override fun onCreate() {
28+
super.onCreate()
29+
preferenceRepository = PreferenceRepository(
30+
getSharedPreferences(DEFAULT_PREFERENCES, Context.MODE_PRIVATE)
31+
)
32+
}
33+
34+
companion object {
35+
const val DEFAULT_PREFERENCES = "default_preferences"
36+
}
37+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2019 The Android Open Source Project
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 io.material.materialthemebuilder.data
18+
19+
import android.content.SharedPreferences
20+
import androidx.appcompat.app.AppCompatDelegate
21+
import androidx.lifecycle.LiveData
22+
import androidx.lifecycle.MutableLiveData
23+
24+
/**
25+
* A simple data repository for in-app settings.
26+
*/
27+
class PreferenceRepository(private val sharedPreferences: SharedPreferences) {
28+
29+
val nightMode: Int
30+
get() = sharedPreferences.getInt(PREFERENCE_NIGHT_MODE, PREFERENCE_NIGHT_MODE_DEF_VAL)
31+
32+
private val _nightModeLive: MutableLiveData<Int> = MutableLiveData()
33+
val nightModeLive: LiveData<Int>
34+
get() = _nightModeLive
35+
36+
var isDarkTheme: Boolean = false
37+
get() = nightMode == AppCompatDelegate.MODE_NIGHT_YES
38+
set(value) {
39+
sharedPreferences.edit().putInt(PREFERENCE_NIGHT_MODE, if (value) {
40+
AppCompatDelegate.MODE_NIGHT_YES
41+
} else {
42+
AppCompatDelegate.MODE_NIGHT_NO
43+
}).apply()
44+
field = value
45+
}
46+
47+
private val _isDarkThemeLive: MutableLiveData<Boolean> = MutableLiveData()
48+
val isDarkThemeLive: LiveData<Boolean>
49+
get() = _isDarkThemeLive
50+
51+
private val preferenceChangedListener =
52+
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
53+
when (key) {
54+
PREFERENCE_NIGHT_MODE -> {
55+
_nightModeLive.value = nightMode
56+
_isDarkThemeLive.value = isDarkTheme
57+
}
58+
}
59+
}
60+
61+
init {
62+
// Init preference LiveData objects.
63+
_nightModeLive.value = nightMode
64+
_isDarkThemeLive.value = isDarkTheme
65+
66+
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangedListener)
67+
}
68+
69+
companion object {
70+
private const val PREFERENCE_NIGHT_MODE = "preference_night_mode"
71+
private const val PREFERENCE_NIGHT_MODE_DEF_VAL = AppCompatDelegate.MODE_NIGHT_NO
72+
}
73+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2019 The Android Open Source Project
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 io.material.materialthemebuilder.ui
18+
19+
import androidx.appcompat.app.AppCompatActivity
20+
import android.os.Bundle
21+
import androidx.lifecycle.Observer
22+
import com.google.android.material.tabs.TabLayout
23+
import androidx.viewpager.widget.ViewPager
24+
import io.material.materialthemebuilder.R
25+
import io.material.materialthemebuilder.App
26+
import io.material.materialthemebuilder.ui.instruction.InstructionsFragment
27+
import io.material.materialthemebuilder.ui.themesummary.ThemeSummaryFragment
28+
import io.material.materialthemebuilder.ui.component.ComponentFragment
29+
30+
/**
31+
* Single activity which contains the [MainViewPagerAdapter] that shows the [InstructionsFragment],
32+
* [ThemeSummaryFragment] and [ComponentFragment].
33+
*/
34+
class MainActivity : AppCompatActivity() {
35+
36+
private lateinit var viewPager: ViewPager
37+
private lateinit var tabLayout: TabLayout
38+
39+
override fun onCreate(savedInstanceState: Bundle?) {
40+
super.onCreate(savedInstanceState)
41+
setContentView(R.layout.activity_main)
42+
viewPager = findViewById(R.id.view_pager)
43+
tabLayout = findViewById(R.id.tab_layout)
44+
45+
tabLayout.setupWithViewPager(viewPager)
46+
val adapter = MainViewPagerAdapter(this, supportFragmentManager)
47+
viewPager.adapter = adapter
48+
49+
(application as App).preferenceRepository
50+
.nightModeLive.observe(this, Observer { nightMode ->
51+
nightMode?.let { delegate.localNightMode = it }
52+
}
53+
)
54+
}
55+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2019 The Android Open Source Project
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 io.material.materialthemebuilder.ui
18+
19+
import android.content.Context
20+
import androidx.fragment.app.Fragment
21+
import androidx.fragment.app.FragmentManager
22+
import androidx.fragment.app.FragmentStatePagerAdapter
23+
import io.material.materialthemebuilder.R
24+
import io.material.materialthemebuilder.ui.component.ComponentFragment
25+
import io.material.materialthemebuilder.ui.instruction.InstructionsFragment
26+
import io.material.materialthemebuilder.ui.themesummary.ThemeSummaryFragment
27+
28+
/**
29+
* View pager to show all tabbed destinations - Instructions, Theme Summary and Components.
30+
*/
31+
class MainViewPagerAdapter(
32+
private val context: Context,
33+
fragmentManager: FragmentManager
34+
) : FragmentStatePagerAdapter(fragmentManager) {
35+
36+
enum class MainFragments(val titleRes: Int) {
37+
INSTRUCTIONS(R.string.tab_title_instructions),
38+
THEME_SUMMARY(R.string.tab_title_theme_summary),
39+
COMPONENTS(R.string.tab_title_components)
40+
}
41+
42+
override fun getCount(): Int = MainFragments.values().size
43+
44+
private fun getItemType(position: Int): MainFragments {
45+
return MainFragments.values()[position]
46+
}
47+
48+
override fun getPageTitle(position: Int): CharSequence? {
49+
return context.getString(getItemType(position).titleRes)
50+
}
51+
52+
override fun getItem(position: Int): Fragment {
53+
return when (getItemType(position)) {
54+
MainFragments.INSTRUCTIONS -> InstructionsFragment()
55+
MainFragments.THEME_SUMMARY -> ThemeSummaryFragment()
56+
MainFragments.COMPONENTS -> ComponentFragment()
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)