├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── rmyhal
│ │ └── containertransform
│ │ ├── AddContentScreen.kt
│ │ ├── HomeScreen.kt
│ │ ├── HotTake.kt
│ │ ├── MainActivity.kt
│ │ └── ui
│ │ └── theme
│ │ ├── Color.kt
│ │ ├── Theme.kt
│ │ └── Type.kt
│ └── res
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── ic_launcher_foreground.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher_foreground.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher_foreground.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher_foreground.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher_foreground.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher_foreground.webp
│ └── ic_launcher_round.webp
│ ├── values
│ ├── ic_launcher_background.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | local.properties
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Container transfrom animation
2 |
3 |
4 |
5 | [Article](https://medium.com/proandroiddev/container-transform-animation-98e5e74a15c9)
6 |
7 | 
8 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.android.application)
3 | alias(libs.plugins.jetbrains.kotlin.android)
4 | }
5 |
6 | android {
7 | namespace = "com.rmyhal.containertransform"
8 | compileSdk = 34
9 |
10 | defaultConfig {
11 | applicationId = "com.rmyhal.containertransform"
12 | minSdk = 29
13 | targetSdk = 34
14 | versionCode = 1
15 | versionName = "1.0"
16 |
17 | vectorDrawables {
18 | useSupportLibrary = true
19 | }
20 | }
21 |
22 | buildTypes {
23 | release {
24 | isMinifyEnabled = false
25 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility = JavaVersion.VERSION_17
30 | targetCompatibility = JavaVersion.VERSION_17
31 | }
32 | kotlinOptions {
33 | jvmTarget = "17"
34 | }
35 | buildFeatures {
36 | compose = true
37 | }
38 | composeOptions {
39 | kotlinCompilerExtensionVersion = "1.5.1"
40 | }
41 | packaging {
42 | resources {
43 | excludes += "/META-INF/{AL2.0,LGPL2.1}"
44 | }
45 | }
46 | }
47 |
48 | dependencies {
49 | implementation(libs.androidx.core.ktx)
50 | implementation(libs.androidx.lifecycle.runtime.ktx)
51 | implementation(libs.androidx.activity.compose)
52 | implementation(platform(libs.androidx.compose.bom))
53 | implementation(libs.androidx.ui)
54 | implementation(libs.androidx.ui.graphics)
55 | implementation(libs.androidx.ui.tooling.preview)
56 | implementation(libs.androidx.material3)
57 | implementation(libs.contentment)
58 |
59 | debugImplementation(libs.androidx.ui.tooling)
60 | debugImplementation(libs.androidx.ui.test.manifest)
61 | }
--------------------------------------------------------------------------------
/app/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
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/AddContentScreen.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform
2 |
3 | import androidx.activity.compose.BackHandler
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.WindowInsets
6 | import androidx.compose.foundation.layout.fillMaxHeight
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.imePadding
9 | import androidx.compose.foundation.layout.padding
10 | import androidx.compose.material.icons.Icons
11 | import androidx.compose.material.icons.filled.ArrowBack
12 | import androidx.compose.material3.CenterAlignedTopAppBar
13 | import androidx.compose.material3.ExperimentalMaterial3Api
14 | import androidx.compose.material3.FilledTonalButton
15 | import androidx.compose.material3.FilledTonalIconButton
16 | import androidx.compose.material3.Icon
17 | import androidx.compose.material3.IconButtonDefaults
18 | import androidx.compose.material3.MaterialTheme
19 | import androidx.compose.material3.OutlinedTextField
20 | import androidx.compose.material3.OutlinedTextFieldDefaults
21 | import androidx.compose.material3.Text
22 | import androidx.compose.runtime.Composable
23 | import androidx.compose.runtime.getValue
24 | import androidx.compose.runtime.mutableStateOf
25 | import androidx.compose.runtime.remember
26 | import androidx.compose.runtime.setValue
27 | import androidx.compose.ui.Modifier
28 | import androidx.compose.ui.graphics.Color
29 | import androidx.compose.ui.tooling.preview.Preview
30 | import androidx.compose.ui.unit.dp
31 | import com.rmyhal.containertransform.ui.theme.ContainerTransformTheme
32 | import com.rmyhal.containertransform.ui.theme.Gray10
33 |
34 | @Composable
35 | fun AddContentScreen(
36 | modifier: Modifier = Modifier,
37 | onBack: () -> Unit,
38 | ) {
39 | BackHandler {
40 | onBack()
41 | }
42 | Column(
43 | modifier = modifier
44 | .padding(horizontal = 8.dp)
45 | ) {
46 | Toolbar(
47 | onBack = onBack,
48 | )
49 | TitleInputField()
50 | StoryInputField()
51 | }
52 | }
53 |
54 | @Composable
55 | @OptIn(ExperimentalMaterial3Api::class)
56 | private fun Toolbar(onBack: () -> Unit) {
57 | CenterAlignedTopAppBar(
58 | windowInsets = WindowInsets(0, 0, 0, 0),
59 | title = {},
60 | actions = {
61 | FilledTonalButton(
62 | modifier = Modifier.padding(end = 6.dp),
63 | onClick = onBack,
64 | ) {
65 | Text(text = "Save")
66 | }
67 | },
68 | navigationIcon = {
69 | FilledTonalIconButton(
70 | colors = IconButtonDefaults.filledTonalIconButtonColors(
71 | containerColor = MaterialTheme.colorScheme.background
72 | ),
73 | onClick = onBack,
74 | ) {
75 | Icon(
76 | imageVector = Icons.Filled.ArrowBack,
77 | contentDescription = null,
78 | )
79 | }
80 | }
81 | )
82 | }
83 |
84 | @Composable
85 | private fun TitleInputField() {
86 | var text by remember { mutableStateOf("") }
87 | OutlinedTextField(
88 | modifier = Modifier
89 | .fillMaxWidth(),
90 | value = text,
91 | onValueChange = { text = it },
92 | placeholder = {
93 | Text(
94 | text = "Title",
95 | color = Gray10,
96 | )
97 | },
98 | colors = OutlinedTextFieldDefaults.colors(
99 | focusedBorderColor = Color.Transparent,
100 | unfocusedBorderColor = Color.Transparent,
101 | )
102 | )
103 | }
104 |
105 | @Composable
106 | private fun StoryInputField() {
107 | var text by remember { mutableStateOf("") }
108 | OutlinedTextField(
109 | modifier = Modifier
110 | .fillMaxWidth()
111 | .fillMaxHeight()
112 | .imePadding(),
113 | value = text,
114 | onValueChange = { text = it },
115 | placeholder = {
116 | Text(
117 | text = "Fragmentation isn't necessarily a curse; it's a testament to Android's diversity...",
118 | color = Gray10,
119 | )
120 | },
121 | colors = OutlinedTextFieldDefaults.colors(
122 | focusedBorderColor = Color.Transparent,
123 | unfocusedBorderColor = Color.Transparent,
124 | ),
125 | )
126 | }
127 |
128 | @Preview(showBackground = true)
129 | @Composable
130 | private fun Preview() {
131 | ContainerTransformTheme {
132 | AddContentScreen {}
133 | }
134 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/HomeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform
2 |
3 | import androidx.compose.animation.AnimatedContent
4 | import androidx.compose.animation.SizeTransform
5 | import androidx.compose.animation.animateColor
6 | import androidx.compose.animation.core.EaseInCubic
7 | import androidx.compose.animation.core.EaseOutCubic
8 | import androidx.compose.animation.core.FastOutSlowInEasing
9 | import androidx.compose.animation.core.animateDp
10 | import androidx.compose.animation.core.tween
11 | import androidx.compose.animation.core.updateTransition
12 | import androidx.compose.animation.fadeIn
13 | import androidx.compose.animation.fadeOut
14 | import androidx.compose.animation.scaleIn
15 | import androidx.compose.animation.togetherWith
16 | import androidx.compose.foundation.clickable
17 | import androidx.compose.foundation.layout.Arrangement
18 | import androidx.compose.foundation.layout.Box
19 | import androidx.compose.foundation.layout.Column
20 | import androidx.compose.foundation.layout.defaultMinSize
21 | import androidx.compose.foundation.layout.fillMaxSize
22 | import androidx.compose.foundation.layout.fillMaxWidth
23 | import androidx.compose.foundation.layout.padding
24 | import androidx.compose.foundation.lazy.LazyColumn
25 | import androidx.compose.foundation.lazy.items
26 | import androidx.compose.foundation.shape.RoundedCornerShape
27 | import androidx.compose.material.icons.Icons
28 | import androidx.compose.material.icons.filled.Add
29 | import androidx.compose.material.icons.filled.Menu
30 | import androidx.compose.material3.Card
31 | import androidx.compose.material3.CircularProgressIndicator
32 | import androidx.compose.material3.Icon
33 | import androidx.compose.material3.MaterialTheme
34 | import androidx.compose.material3.OutlinedTextField
35 | import androidx.compose.material3.OutlinedTextFieldDefaults
36 | import androidx.compose.material3.Text
37 | import androidx.compose.runtime.Composable
38 | import androidx.compose.runtime.LaunchedEffect
39 | import androidx.compose.runtime.getValue
40 | import androidx.compose.runtime.mutableStateOf
41 | import androidx.compose.runtime.remember
42 | import androidx.compose.runtime.setValue
43 | import androidx.compose.ui.Alignment
44 | import androidx.compose.ui.Modifier
45 | import androidx.compose.ui.draw.drawBehind
46 | import androidx.compose.ui.draw.shadow
47 | import androidx.compose.ui.graphics.Color
48 | import androidx.compose.ui.graphics.vector.rememberVectorPainter
49 | import androidx.compose.ui.text.style.TextOverflow
50 | import androidx.compose.ui.tooling.preview.Preview
51 | import androidx.compose.ui.unit.dp
52 | import com.rmyhal.containertransform.ui.theme.ContainerTransformTheme
53 | import kotlinx.coroutines.delay
54 | import me.rmyhal.contentment.Contentment
55 |
56 | @Composable
57 | fun HomeScreen(modifier: Modifier = Modifier) {
58 | Box(
59 | modifier = modifier
60 | .fillMaxSize(),
61 | ) {
62 | HotContent()
63 | FabContainer(
64 | modifier = Modifier
65 | .align(Alignment.BottomEnd)
66 | )
67 | }
68 | }
69 |
70 | @Composable
71 | private fun FabContainer(
72 | modifier: Modifier = Modifier,
73 | ) {
74 | var containerState by remember { mutableStateOf(ContainerState.Fab) }
75 | val transition = updateTransition(containerState, label = "container transform")
76 | val animatedColor by transition.animateColor(
77 | label = "color",
78 | ) { state ->
79 | when (state) {
80 | ContainerState.Fab -> MaterialTheme.colorScheme.primaryContainer
81 | ContainerState.Fullscreen -> MaterialTheme.colorScheme.surface
82 | }
83 | }
84 |
85 | val cornerRadius by transition.animateDp(
86 | label = "corner radius",
87 | transitionSpec = {
88 | when (targetState) {
89 | ContainerState.Fab -> tween(
90 | durationMillis = 400,
91 | easing = EaseOutCubic,
92 | )
93 |
94 | ContainerState.Fullscreen -> tween(
95 | durationMillis = 200,
96 | easing = EaseInCubic,
97 | )
98 | }
99 | }
100 | ) { state ->
101 | when (state) {
102 | ContainerState.Fab -> 22.dp
103 | ContainerState.Fullscreen -> 0.dp
104 | }
105 | }
106 | val elevation by transition.animateDp(
107 | label = "elevation",
108 | transitionSpec = {
109 | when (targetState) {
110 | ContainerState.Fab -> tween(
111 | durationMillis = 400,
112 | easing = EaseOutCubic,
113 | )
114 |
115 | ContainerState.Fullscreen -> tween(
116 | durationMillis = 200,
117 | easing = EaseOutCubic,
118 | )
119 | }
120 | }
121 | ) { state ->
122 | when (state) {
123 | ContainerState.Fab -> 6.dp
124 | ContainerState.Fullscreen -> 0.dp
125 | }
126 | }
127 | val padding by transition.animateDp(
128 | label = "padding",
129 | ) { state ->
130 | when (state) {
131 | ContainerState.Fab -> 16.dp
132 | ContainerState.Fullscreen -> 0.dp
133 | }
134 | }
135 |
136 | transition.AnimatedContent(
137 | contentAlignment = Alignment.Center,
138 | modifier = modifier
139 | .padding(end = padding, bottom = padding)
140 | .shadow(
141 | elevation = elevation,
142 | shape = RoundedCornerShape(cornerRadius)
143 | )
144 | .drawBehind { drawRect(animatedColor) },
145 | transitionSpec = {
146 | (
147 | fadeIn(animationSpec = tween(220, delayMillis = 90)) +
148 | scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90))
149 | )
150 | .togetherWith(fadeOut(animationSpec = tween(90)))
151 | .using(SizeTransform(clip = false, sizeAnimationSpec = { _, _ ->
152 | tween(
153 | durationMillis = 500,
154 | easing = FastOutSlowInEasing
155 | )
156 | }))
157 | }
158 | ) { state ->
159 | when (state) {
160 | ContainerState.Fab -> {
161 | Fab(
162 | modifier = Modifier,
163 | onClick = { containerState = ContainerState.Fullscreen }
164 | )
165 | }
166 |
167 | ContainerState.Fullscreen -> {
168 | AddContentScreen(
169 | modifier = Modifier,
170 | onBack = { containerState = ContainerState.Fab }
171 | )
172 | }
173 | }
174 | }
175 | }
176 |
177 | @Composable
178 | private fun HotContent() {
179 | Column {
180 | SearchBar(
181 | modifier = Modifier
182 | .fillMaxWidth()
183 | .padding(horizontal = 12.dp, vertical = 6.dp)
184 | )
185 |
186 | var uiState by remember { mutableStateOf(UiState.Loading) }
187 | LaunchedEffect(Unit) {
188 | // fake loading
189 | delay(600)
190 | uiState = UiState.Loaded(hotTakes)
191 | }
192 | Box(
193 | modifier = Modifier.fillMaxSize(),
194 | ) {
195 | Contentment {
196 | when (uiState) {
197 | is UiState.Loading -> indicator {
198 | CircularProgressIndicator(
199 | modifier = Modifier.align(Alignment.Center)
200 | )
201 | }
202 |
203 | is UiState.Loaded -> content { HotTakes() }
204 | }
205 | }
206 | }
207 | }
208 | }
209 |
210 | @Composable
211 | private fun SearchBar(modifier: Modifier = Modifier) {
212 | OutlinedTextField(
213 | modifier = modifier,
214 | value = "",
215 | onValueChange = {},
216 | leadingIcon = {
217 | Icon(
218 | imageVector = Icons.Default.Menu,
219 | contentDescription = null,
220 | )
221 | },
222 | placeholder = {
223 | Text(
224 | text = "Search your hot takes"
225 | )
226 | },
227 | colors = OutlinedTextFieldDefaults.colors(
228 | focusedBorderColor = Color.Transparent,
229 | unfocusedBorderColor = Color.Transparent,
230 | unfocusedContainerColor = MaterialTheme.colorScheme.secondaryContainer,
231 | focusedContainerColor = MaterialTheme.colorScheme.secondaryContainer,
232 | ),
233 | shape = RoundedCornerShape(50)
234 | )
235 | }
236 |
237 | @Composable
238 | private fun HotTakes() {
239 | LazyColumn(
240 | modifier = Modifier
241 | .fillMaxWidth()
242 | .padding(top = 12.dp),
243 | verticalArrangement = Arrangement.spacedBy(12.dp)
244 | ) {
245 | items(hotTakes) { HotTake(hotTake = it) }
246 | }
247 | }
248 |
249 | @Composable
250 | private fun HotTake(hotTake: HotTake) {
251 | Card(
252 | modifier = Modifier
253 | .fillMaxWidth()
254 | .padding(horizontal = 16.dp),
255 | onClick = { },
256 | ) {
257 | Column(
258 | modifier = Modifier.padding(16.dp)
259 | ) {
260 | hotTake.title?.let {
261 | Text(
262 | text = hotTake.title,
263 | style = MaterialTheme.typography.titleMedium,
264 | )
265 | }
266 | Text(
267 | modifier = Modifier
268 | .padding(top = 6.dp),
269 | maxLines = 3,
270 | text = hotTake.take,
271 | overflow = TextOverflow.Ellipsis
272 | )
273 | }
274 | }
275 | }
276 |
277 | @Composable
278 | private fun Fab(
279 | modifier: Modifier = Modifier,
280 | onClick: () -> Unit
281 | ) {
282 | Box(
283 | modifier = modifier
284 | .defaultMinSize(
285 | minWidth = 76.dp,
286 | minHeight = 76.dp,
287 | )
288 | .clickable(
289 | onClick = onClick,
290 | ),
291 | contentAlignment = Alignment.Center,
292 | ) {
293 | Icon(
294 | painter = rememberVectorPainter(Icons.Filled.Add),
295 | contentDescription = null,
296 | )
297 | }
298 | }
299 |
300 | sealed interface UiState {
301 | data class Loaded(val list: List) : UiState
302 | data object Loading : UiState
303 | }
304 |
305 | enum class ContainerState {
306 | Fab,
307 | Fullscreen,
308 | }
309 |
310 | @Preview(showBackground = true)
311 | @Composable
312 | private fun Preview() {
313 | ContainerTransformTheme {
314 | HomeScreen()
315 | }
316 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/HotTake.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform
2 |
3 | import androidx.compose.runtime.Stable
4 |
5 | @Stable
6 | data class HotTake(
7 | val title: String?,
8 | val take: String,
9 | )
10 |
11 | val hotTakes = listOf(
12 | HotTake(
13 | title = null,
14 | take = "Artificial Intelligence isn't just a threat to jobs; it's a catalyst for redefining the workforce. Instead of fearing automation, we should focus on reskilling and upskilling workers to thrive in a future augmented by AI.",
15 | ),
16 | HotTake(
17 | title = "Security?",
18 | take = "Prioritizing user security over convenience should be non-negotiable in Android app development. While features like single sign-on and biometric authentication enhance user experience, they should not compromise security standards. Developers must strike a balance between user convenience and robust security measures to safeguard user data and trust."
19 | ),
20 | HotTake(
21 | title = "Compose or Collapse",
22 | take = "Jetpack Compose isn't just a toolkit; it's the litmus test for Android's future relevance. Embrace Compose's radical departure from XML layouts or risk irrelevance in a rapidly evolving mobile ecosystem.",
23 | )
24 | )
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.activity.enableEdgeToEdge
7 | import androidx.compose.foundation.layout.fillMaxSize
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.material3.Scaffold
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.tooling.preview.Preview
13 | import com.rmyhal.containertransform.ui.theme.ContainerTransformTheme
14 |
15 | class MainActivity : ComponentActivity() {
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | enableEdgeToEdge()
19 | setContent {
20 | ContainerTransformTheme {
21 | Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
22 | HomeScreen(
23 | modifier = Modifier
24 | .padding(innerPadding)
25 | )
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 | @Preview(showBackground = true)
33 | @Composable
34 | private fun Preview() {
35 | ContainerTransformTheme {
36 | HomeScreen()
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 |
9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)
12 |
13 | val Gray10 = Color(0xFF9898A0)
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform.ui.theme
2 |
3 | import android.os.Build
4 | import androidx.compose.foundation.isSystemInDarkTheme
5 | import androidx.compose.material3.MaterialTheme
6 | import androidx.compose.material3.darkColorScheme
7 | import androidx.compose.material3.dynamicDarkColorScheme
8 | import androidx.compose.material3.dynamicLightColorScheme
9 | import androidx.compose.material3.lightColorScheme
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.platform.LocalContext
12 |
13 | private val DarkColorScheme = darkColorScheme(
14 | primary = Purple80,
15 | secondary = PurpleGrey80,
16 | tertiary = Pink80
17 | )
18 |
19 | private val LightColorScheme = lightColorScheme(
20 | primary = Purple40,
21 | secondary = PurpleGrey40,
22 | tertiary = Pink40
23 | )
24 |
25 | @Composable
26 | fun ContainerTransformTheme(
27 | darkTheme: Boolean = isSystemInDarkTheme(),
28 | // Dynamic color is available on Android 12+
29 | dynamicColor: Boolean = true,
30 | content: @Composable () -> Unit
31 | ) {
32 | val colorScheme = when {
33 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
34 | val context = LocalContext.current
35 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
36 | }
37 |
38 | darkTheme -> DarkColorScheme
39 | else -> LightColorScheme
40 | }
41 |
42 | MaterialTheme(
43 | colorScheme = colorScheme,
44 | typography = Typography,
45 | content = content
46 | )
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/rmyhal/containertransform/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.rmyhal.containertransform.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // Set of Material typography styles to start with
10 | val Typography = Typography(
11 | bodyLarge = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp,
15 | lineHeight = 24.sp,
16 | letterSpacing = 0.5.sp
17 | )
18 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Hot
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 | alias(libs.plugins.jetbrains.kotlin.android) apply false
5 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.5.2"
3 | kotlin = "1.9.0"
4 | coreKtx = "1.13.1"
5 | lifecycleRuntimeKtx = "2.8.5"
6 | activityCompose = "1.9.2"
7 | composeBom = "2024.09.01"
8 | composeAnimation = "1.7.1"
9 |
10 | [libraries]
11 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
12 | androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
13 | androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
14 | androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
15 | androidx-ui = { group = "androidx.compose.ui", name = "ui" }
16 | androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
17 | androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
18 | androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
19 | androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
20 | androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
21 | contentment = { group = "me.rmyhal.contentment", name = "contentment", version = "2.0.1" }
22 |
23 | [plugins]
24 | android-application = { id = "com.android.application", version.ref = "agp" }
25 | jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
26 |
27 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rmyhal/container-transform-compose/a2071be3aad3e3ff5cfb6b059b77a1f05d57736e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Sep 14 20:09:40 PDT 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 | }
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.name = "ContainerTransform"
23 | include(":app")
24 |
--------------------------------------------------------------------------------