Skip to content

Commit

Permalink
Merge pull request #5 from chrisbanes/cb/sample
Browse files Browse the repository at this point in the history
Add MDC sample
  • Loading branch information
chrisbanes authored May 13, 2020
2 parents f77ce99 + 1083ddd commit 7d72bdc
Show file tree
Hide file tree
Showing 10 changed files with 460 additions and 33 deletions.
16 changes: 8 additions & 8 deletions mdc-theme/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ android {
compose true
}

packagingOptions {
def e = excludes
// AGP 4.1.0-alpha06 added an exclude which breaks Kotlin libraries. Remove the exclude
// until we upgrade to an AGP version with a fix
e.remove("/META-INF/*.kotlin_module")
excludes = e
}

composeOptions {
kotlinCompilerVersion Libs.AndroidX.UI.kotlinCompilerVersion
kotlinCompilerExtensionVersion Libs.AndroidX.UI.version
Expand All @@ -62,6 +54,14 @@ android {
it.generateBuildConfig.enabled = false
}

packagingOptions {
def e = excludes
// AGP 4.1.0-alpha06 added an exclude which breaks Kotlin libraries.
// TODO: Remove the exclude when we upgrade to an AGP version with a fix
e.remove("/META-INF/*.kotlin_module")
excludes = e
}

testOptions {
unitTests {
includeAndroidResources = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,20 +318,25 @@ private fun textStyleFromTextAppearance(

val density = DensityAmbient.current

// FYI, this only works with static font files in assets
val fontFamilyWeight = when {
a.hasValue(R.styleable.AccompanistMdcTextAppearance_android_fontFamily) -> {
a.getFontFamilyOrNull(R.styleable.AccompanistMdcTextAppearance_android_fontFamily)
}
a.hasValue(R.styleable.AccompanistMdcTextAppearance_fontFamily) -> {
a.getFontFamilyOrNull(R.styleable.AccompanistMdcTextAppearance_fontFamily)
}
else -> null
}

TextStyle(
color = if (useTextColor) {
a.getComposeColor(R.styleable.AccompanistMdcTextAppearance_android_textColor)
} else Color.Unset,
fontSize = a.getTextUnit(R.styleable.AccompanistMdcTextAppearance_android_textSize, density),
lineHeight = a.getTextUnit(R.styleable.AccompanistMdcTextAppearance_android_lineHeight, density),
fontFamily = when {
// FYI, this only works with static font files in assets
a.hasValue(R.styleable.AccompanistMdcTextAppearance_android_fontFamily) -> {
a.getFontFamilyOrNull(R.styleable.AccompanistMdcTextAppearance_android_fontFamily)
}
a.hasValue(R.styleable.AccompanistMdcTextAppearance_fontFamily) -> {
a.getFontFamilyOrNull(R.styleable.AccompanistMdcTextAppearance_fontFamily)
}
fontFamilyWeight != null -> fontFamilyWeight.fontFamily
// Values below are from frameworks/base attrs.xml
typeface == 1 -> FontFamily.SansSerif
typeface == 2 -> FontFamily.Serif
Expand All @@ -349,8 +354,10 @@ private fun textStyleFromTextAppearance(
textFontWeight in 650..749 -> FontWeight.W700
textFontWeight in 750..849 -> FontWeight.W800
textFontWeight in 850..999 -> FontWeight.W900
// else, check the text style
// Else, check the text style for bold
(textStyle and Typeface.BOLD) != 0 -> FontWeight.Bold
// Else, the font family might have an implicit weight (san-serif-light, etc)
fontFamilyWeight != null -> fontFamilyWeight.weight
else -> null
},
fontFeatureSettings = a.getString(R.styleable.AccompanistMdcTextAppearance_android_fontFeatureSettings),
Expand Down Expand Up @@ -449,42 +456,64 @@ private fun Typography.merge(

private val tempTypedValue = ThreadLocal<TypedValue>()

fun TypedArray.getComposeColor(
private fun TypedArray.getComposeColor(
index: Int,
fallbackColor: Color = Color.Unset
): Color = if (hasValue(index)) Color(getColorOrThrow(index)) else fallbackColor

/**
* Returns the given index as a [FontFamily], or [fallback] if the value can not be coerced to a [FontFamily].
* Returns the given index as a [FontFamily] and [FontWeight],
* or [fallback] if the value can not be coerced to a [FontFamily].
*
* @param index index of attribute to retrieve.
* @param fallback Value to return if the attribute is not defined or cannot be coerced to an [FontFamily].
*/
fun TypedArray.getFontFamily(index: Int, fallback: FontFamily): FontFamily {
return getFontFamilyOrNull(index) ?: fallback
private fun TypedArray.getFontFamily(index: Int, fallback: FontFamily): FontFamilyWeight {
return getFontFamilyOrNull(index) ?: FontFamilyWeight(fallback)
}

/**
* Returns the given index as a [FontFamily], or `null` if the value can not be coerced to a [FontFamily].
* Returns the given index as a [FontFamily] and [FontWeight],
* or `null` if the value can not be coerced to a [FontFamily].
*
* @param index index of attribute to retrieve.
*/
fun TypedArray.getFontFamilyOrNull(index: Int): FontFamily? {
private fun TypedArray.getFontFamilyOrNull(index: Int): FontFamilyWeight? {
val tv = tempTypedValue.getOrSet { TypedValue() }
if (getValue(index, tv) && tv.type == TypedValue.TYPE_STRING) {
return font(tv.resourceId).asFontFamily()
if (tv.resourceId != 0) {
// If there's a resource ID, it's probably a @font resource
return FontFamilyWeight(font(tv.resourceId).asFontFamily())
}
return when (tv.string) {
"san-serif" -> FontFamilyWeight(FontFamily.SansSerif)
"sans-serif-thin" -> FontFamilyWeight(FontFamily.SansSerif, FontWeight.Thin)
"san-serif-light" -> FontFamilyWeight(FontFamily.SansSerif, FontWeight.Light)
"sans-serif-medium" -> FontFamilyWeight(FontFamily.SansSerif, FontWeight.Medium)
"sans-serif-black" -> FontFamilyWeight(FontFamily.SansSerif, FontWeight.Black)
"serif" -> FontFamilyWeight(FontFamily.Serif)
"cursive" -> FontFamilyWeight(FontFamily.Cursive)
"monospace" -> FontFamilyWeight(FontFamily.Monospace)
// TODO: Compose does not expose a FontFamily for "sans-serif-condensed" yet
else -> null
}
}
return null
}

private data class FontFamilyWeight(
val fontFamily: FontFamily,
val weight: FontWeight = FontWeight.Normal
)

/**
* Returns the given index as a [TextUnit], or [fallback] if the value can not be coerced to a [TextUnit].
*
* @param index index of attribute to retrieve.
* @param density the current display density.
* @param fallback Value to return if the attribute is not defined or cannot be coerced to an [TextUnit].
*/
fun TypedArray.getTextUnit(
private fun TypedArray.getTextUnit(
index: Int,
density: Density,
fallback: TextUnit = TextUnit.Inherit
Expand All @@ -496,7 +525,7 @@ fun TypedArray.getTextUnit(
* @param index index of attribute to retrieve.
* @param density the current display density.
*/
fun TypedArray.getTextUnitOrNull(
private fun TypedArray.getTextUnitOrNull(
index: Int,
density: Density
): TextUnit? {
Expand All @@ -520,7 +549,7 @@ fun TypedArray.getTextUnitOrNull(
*
* @param index index of attribute to retrieve.
*/
fun TypedArray.getCornerSizeOrNull(index: Int): CornerSize? {
private fun TypedArray.getCornerSizeOrNull(index: Int): CornerSize? {
val tv = tempTypedValue.getOrSet { TypedValue() }
if (getValue(index, tv)) {
return when (tv.type) {
Expand All @@ -546,7 +575,7 @@ fun TypedArray.getCornerSizeOrNull(index: Int): CornerSize? {
* @param index index of attribute to retrieve.
* @param fallback Value to return if the attribute is not defined or cannot be coerced to an [CornerSize].
*/
fun TypedArray.getCornerSize(index: Int, fallback: CornerSize): CornerSize {
private fun TypedArray.getCornerSize(index: Int, fallback: CornerSize): CornerSize {
return getCornerSizeOrNull(index) ?: fallback
}

Expand Down
16 changes: 16 additions & 0 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,26 @@ android {

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildFeatures {
compose true
}

composeOptions {
kotlinCompilerVersion Libs.AndroidX.UI.kotlinCompilerVersion
kotlinCompilerExtensionVersion Libs.AndroidX.UI.version
}
}

dependencies {
implementation project(':mdc-theme')

implementation Libs.AndroidX.UI.composeRuntime
implementation Libs.AndroidX.UI.material
implementation Libs.AndroidX.UI.foundation
implementation Libs.AndroidX.UI.layout

implementation Libs.AndroidX.coreKtx
implementation Libs.mdc
implementation Libs.Kotlin.stdlib
}
22 changes: 21 additions & 1 deletion sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,27 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/Theme.AccompanistSample">

<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.Material.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name=".mdc.MdcSampleActivity"
android:label="@string/mdc_title"
android:theme="@style/Theme.AccompanistSample.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="dev.chrisbanes.accompanist.sample.SAMPLE_CODE" />
</intent-filter>
</activity>

</application>

Expand Down
140 changes: 140 additions & 0 deletions sample/src/main/java/dev/chrisbanes/accompanist/sample/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.chrisbanes.accompanist.sample

import android.R
import android.app.ListActivity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.ListView
import android.widget.SimpleAdapter
import java.text.Collator
import java.util.ArrayList
import java.util.Collections
import java.util.Comparator
import java.util.HashMap

/**
* A [ListActivity] which automatically populates the list of sample activities in this app
* with the category `dev.chrisbanes.accompanist.sample.SAMPLE_CODE`.
*/
class MainActivity : ListActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

listAdapter = SimpleAdapter(
this,
getData(intent.getStringExtra(EXTRA_PATH)),
R.layout.simple_list_item_1,
arrayOf("title"),
intArrayOf(R.id.text1)
)

listView.isTextFilterEnabled = true
}

private fun getData(prefix: String?): List<Map<String, Any>> {
val myData = ArrayList<Map<String, Any>>()

val mainIntent = Intent(Intent.ACTION_MAIN, null)
mainIntent.addCategory("dev.chrisbanes.accompanist.sample.SAMPLE_CODE")

val list = packageManager.queryIntentActivities(mainIntent, 0) ?: return myData

val prefixPath: Array<String>?
var prefixWithSlash = prefix

if (prefix.isNullOrEmpty()) {
prefixPath = null
} else {
prefixPath = prefix.split("/".toRegex()).toTypedArray()
prefixWithSlash = "$prefix/"
}

val entries = HashMap<String, Boolean>()

list.forEach { info ->
val labelSeq = info.loadLabel(packageManager)
val label = labelSeq?.toString() ?: info.activityInfo.name

if (prefixWithSlash.isNullOrEmpty() || label.startsWith(prefixWithSlash)) {
val labelPath = label.split("/".toRegex()).toTypedArray()
val nextLabel = if (prefixPath == null) labelPath[0] else labelPath[prefixPath.size]
if (prefixPath?.size ?: 0 == labelPath.size - 1) {
addItem(
myData, nextLabel, activityIntent(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name
)
)
} else {
if (entries[nextLabel] == null) {
addItem(
myData, nextLabel, browseIntent(
if (prefix == "") nextLabel else "$prefix/$nextLabel"
)
)
entries[nextLabel] = true
}
}
}
}

Collections.sort(myData, sDisplayNameComparator)

return myData
}

private fun activityIntent(pkg: String, componentName: String): Intent {
val result = Intent()
result.setClassName(pkg, componentName)
return result
}

private fun browseIntent(path: String): Intent {
val result = Intent()
result.setClass(this, MainActivity::class.java)
result.putExtra(EXTRA_PATH, path)
return result
}

private fun addItem(data: MutableList<Map<String, Any>>, name: String, intent: Intent) {
val temp = mutableMapOf<String, Any>()
temp["title"] = name
temp["intent"] = intent
data += temp
}

override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) {
val map = l.getItemAtPosition(position) as Map<*, *>
val intent = map["intent"] as Intent?
startActivity(intent)
}

companion object {
private const val EXTRA_PATH = "com.example.android.apis.Path"

private val sDisplayNameComparator = object : Comparator<Map<String, Any>> {
private val collator = Collator.getInstance()

override fun compare(map1: Map<String, Any>, map2: Map<String, Any>): Int {
return collator.compare(map1["title"], map2["title"])
}
}
}
}
Loading

0 comments on commit 7d72bdc

Please sign in to comment.