1 /*
<lambda>null2 * Copyright (C) 2023 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 com.android.compose.animation.scene.demo
18
19 import android.os.Bundle
20 import android.view.WindowInsets
21 import androidx.activity.ComponentActivity
22 import androidx.activity.compose.ReportDrawn
23 import androidx.activity.compose.setContent
24 import androidx.compose.foundation.IndicationNodeFactory
25 import androidx.compose.foundation.LocalIndication
26 import androidx.compose.foundation.interaction.InteractionSource
27 import androidx.compose.foundation.isSystemInDarkTheme
28 import androidx.compose.foundation.layout.safeDrawingPadding
29 import androidx.compose.material3.MaterialTheme
30 import androidx.compose.material3.Typography
31 import androidx.compose.material3.dynamicDarkColorScheme
32 import androidx.compose.material3.dynamicLightColorScheme
33 import androidx.compose.runtime.Composable
34 import androidx.compose.runtime.CompositionLocalProvider
35 import androidx.compose.runtime.SideEffect
36 import androidx.compose.runtime.getValue
37 import androidx.compose.runtime.mutableStateOf
38 import androidx.compose.runtime.remember
39 import androidx.compose.runtime.saveable.rememberSaveable
40 import androidx.compose.runtime.setValue
41 import androidx.compose.ui.Modifier
42 import androidx.compose.ui.graphics.drawscope.ContentDrawScope
43 import androidx.compose.ui.node.DelegatableNode
44 import androidx.compose.ui.node.DrawModifierNode
45 import androidx.compose.ui.platform.LocalContext
46 import androidx.compose.ui.text.font.DeviceFontFamilyName
47 import androidx.compose.ui.text.font.Font
48 import androidx.compose.ui.text.font.FontFamily
49 import androidx.compose.ui.text.font.FontWeight
50 import com.android.compose.modifiers.thenIf
51
52 class DemoActivity : ComponentActivity() {
53 private companion object {
54 const val INITIAL_SCENE_EXTRA = "initial_scene"
55 const val FULLSCREEN_EXTRA = "fullscreen"
56 const val DISABLE_RIPPLE_EXTRA = "disable_ripple"
57 }
58
59 override fun onCreate(savedInstanceState: Bundle?) {
60 super.onCreate(savedInstanceState)
61 window.setDecorFitsSystemWindows(false)
62
63 val initialScene =
64 intent.extras?.getString(INITIAL_SCENE_EXTRA)?.let { scene ->
65 Scenes.AllScenes[scene] ?: error("Scene $scene does not exist")
66 }
67
68 val isFullscreen = intent.extras?.getBoolean(FULLSCREEN_EXTRA) ?: false
69 val disableRipple = intent.extras?.getBoolean(DISABLE_RIPPLE_EXTRA) ?: false
70
71 setContent {
72 DemoTheme {
73 var configuration by
74 rememberSaveable(stateSaver = DemoConfiguration.Saver) {
75 mutableStateOf(DemoConfiguration(isFullscreen = isFullscreen))
76 }
77
78 SideEffect {
79 if (configuration.isFullscreen) {
80 window.insetsController?.hide(WindowInsets.Type.statusBars())
81 } else {
82 window.insetsController?.show(WindowInsets.Type.statusBars())
83 }
84 }
85
86 val indication = if (disableRipple) NoIndication else LocalIndication.current
87 CompositionLocalProvider(LocalIndication provides indication) {
88 SystemUi(
89 configuration,
90 { configuration = it },
91 Modifier.thenIf(!configuration.isFullscreen) {
92 Modifier.safeDrawingPadding()
93 },
94 initialScene = initialScene,
95 )
96 }
97
98 ReportDrawn()
99 }
100 }
101 }
102 }
103
104 @Composable
DemoThemenull105 private fun DemoTheme(content: @Composable () -> Unit) {
106 val context = LocalContext.current
107 val colorScheme =
108 if (isSystemInDarkTheme()) dynamicDarkColorScheme(context)
109 else dynamicLightColorScheme(context)
110 val typography = MaterialTheme.typography
111 val typographyWithGoogleSans = remember(typography) { typography.withGoogleSans() }
112
113 MaterialTheme(
114 colorScheme = colorScheme,
115 typography = typographyWithGoogleSans,
116 content = content,
117 )
118 }
119
withGoogleSansnull120 private fun Typography.withGoogleSans(): Typography {
121 val brandFont = DeviceFontFamilyName("google-sans-text")
122 val plainFont = DeviceFontFamilyName("google-sans")
123
124 val brand =
125 FontFamily(
126 Font(brandFont, weight = FontWeight.Medium),
127 Font(brandFont, weight = FontWeight.Normal),
128 )
129
130 val plain =
131 FontFamily(
132 Font(plainFont, weight = FontWeight.Medium),
133 Font(plainFont, weight = FontWeight.Normal),
134 )
135
136 return this.copy(
137 displayLarge = this.displayLarge.copy(fontFamily = brand),
138 displayMedium = this.displayMedium.copy(fontFamily = brand),
139 displaySmall = this.displaySmall.copy(fontFamily = brand),
140 headlineLarge = this.headlineLarge.copy(fontFamily = brand),
141 headlineMedium = this.headlineMedium.copy(fontFamily = brand),
142 headlineSmall = this.headlineSmall.copy(fontFamily = brand),
143 titleLarge = this.titleLarge.copy(fontFamily = brand),
144 titleMedium = this.titleMedium.copy(fontFamily = plain),
145 titleSmall = this.titleSmall.copy(fontFamily = plain),
146 bodyLarge = this.bodyLarge.copy(fontFamily = plain),
147 bodyMedium = this.bodyMedium.copy(fontFamily = plain),
148 bodySmall = this.bodySmall.copy(fontFamily = plain),
149 labelLarge = this.labelLarge.copy(fontFamily = plain),
150 labelMedium = this.labelMedium.copy(fontFamily = plain),
151 labelSmall = this.labelSmall.copy(fontFamily = plain),
152 )
153 }
154
155 private data object NoIndication : IndicationNodeFactory {
createnull156 override fun create(interactionSource: InteractionSource): DelegatableNode = NoIndicationNode()
157 }
158
159 private class NoIndicationNode : Modifier.Node(), DrawModifierNode {
160 override fun ContentDrawScope.draw() {
161 drawContent()
162 }
163 }
164