diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1bdc8e679..2d738377c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,19 +7,19 @@ ## 완료한 코드랩 완료한 코드랩을 체크 해주세요. 16개의 코드랩 중 12개 이상 완주하셔야 Compose Camp가 준비한 트래킹 완주 기념품을 배송해 드립니다. -- [ ] Unit1/Pathway3/BirthdayCard -- [ ] Unit1/Pathway3/ComposeArticle -- [ ] Unit1/Pathway3/ComposeQuadrant -- [ ] Unit1/Pathway3/TaskCompleted -- [ ] Unit2/Pathway2/DiceRoller -- [ ] Unit2/Pathway2/Lemonade -- [ ] Unit2/Pathway3/TipTime -- [ ] Unit2/Pathway3/ArtSpace -- [ ] Unit3/Pathway2/AffirmationsCodelab -- [ ] Unit3/Pathway3/WoofCodelab -- [ ] Unit4/Pathway1/DessertClicker -- [ ] Unit4/Pathway1/Unscamble -- [ ] Unit4/Pathway2/CupCake +- [O] Unit1/Pathway3/BirthdayCard +- [O] Unit1/Pathway3/ComposeArticle +- [O] Unit1/Pathway3/ComposeQuadrant +- [O] Unit1/Pathway3/TaskCompleted +- [O] Unit2/Pathway2/DiceRoller +- [O] Unit2/Pathway2/Lemonade +- [O] Unit2/Pathway3/TipTime +- [O] Unit2/Pathway3/ArtSpace +- [O] Unit3/Pathway2/AffirmationsCodelab +- [O] Unit3/Pathway3/WoofCodelab +- [O] Unit4/Pathway1/DessertClicker +- [O] Unit4/Pathway1/Unscamble +- [O] Unit4/Pathway2/CupCake - [ ] Unit4/Pathway2/LaunchTray - [ ] Unit4/Pathway3/ReplyApp - [ ] Unit4/Pathway3/TrainingSports diff --git a/Unit1/Pathway3/BirthdayCard/app/src/main/java/com/example/happybirthday/MainActivity.kt b/Unit1/Pathway3/BirthdayCard/app/src/main/java/com/example/happybirthday/MainActivity.kt index 8fe0316fb..d041cd475 100644 --- a/Unit1/Pathway3/BirthdayCard/app/src/main/java/com/example/happybirthday/MainActivity.kt +++ b/Unit1/Pathway3/BirthdayCard/app/src/main/java/com/example/happybirthday/MainActivity.kt @@ -20,6 +20,7 @@ import android.text.Layout import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface @@ -38,7 +39,15 @@ import com.example.happybirthday.ui.theme.HappyBirthdayTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContent { } + setContent { + HappyBirthdayTheme { + // A surface container using the 'background' color from the theme + Surface(color = MaterialTheme.colors.background) { + BirthdayGreetingWithImage(message = getString(R.string.happy_birthday_text), from = getString( + R.string.signature_text)) + } + } + } } } @@ -46,15 +55,56 @@ class MainActivity : ComponentActivity() { @Composable fun BirthdayGreetingWithText(message: String, from: String) { // Create a column so that texts don't overlap - Column { } + Column { + Text( + text = message, + fontSize = 36.sp, + modifier = Modifier + .fillMaxWidth() +// .wrapContentWidth(Alignment.Start) + .wrapContentWidth(Alignment.CenterHorizontally) + .padding(start = 16.dp, top = 16.dp) + ) + Text( + text = from, + fontSize = 24.sp, + modifier = Modifier + .fillMaxWidth() +// .wrapContentWidth(Alignment.End) + .wrapContentWidth(Alignment.CenterHorizontally) + .padding(start = 16.dp, end = 16.dp) + ) + } } // 5. Box 레이아웃 추 @Composable -fun BirthdayGreetingWithImage(message: String, from: String) { } +fun BirthdayGreetingWithImage(message: String, from: String) { + val image = painterResource(R.drawable.androidparty) + Box { + Image( + painter = image, + contentDescription = null, + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(), + contentScale = ContentScale.Crop + + ) + BirthdayGreetingWithText(message = message, from = from) + } + + +} // 4. 이미지 컴포저블 추가 -@Preview(showBackground = false) +@Preview(showBackground = true) @Composable -private fun BirthdayCardPreview() { } +private fun BirthdayCardPreview() { + HappyBirthdayTheme() { + BirthdayGreetingWithImage(message = stringResource(R.string.preview_happy_birthday_text), from = stringResource( + R.string.preview_signature_text) ) + } + +} diff --git a/Unit1/Pathway3/BirthdayCard/app/src/main/res/drawable-nodpi/androidparty.png b/Unit1/Pathway3/BirthdayCard/app/src/main/res/drawable-nodpi/androidparty.png new file mode 100644 index 000000000..87124d659 Binary files /dev/null and b/Unit1/Pathway3/BirthdayCard/app/src/main/res/drawable-nodpi/androidparty.png differ diff --git a/Unit1/Pathway3/BirthdayCard/app/src/main/res/values/strings.xml b/Unit1/Pathway3/BirthdayCard/app/src/main/res/values/strings.xml index 3a180adfa..9db28cfbc 100644 --- a/Unit1/Pathway3/BirthdayCard/app/src/main/res/values/strings.xml +++ b/Unit1/Pathway3/BirthdayCard/app/src/main/res/values/strings.xml @@ -16,4 +16,8 @@ --> Happy Birthday + Happy Birthday DE! + - Harim + Happy Birthday Sam! + - from Emma \ No newline at end of file diff --git a/Unit1/Pathway3/ComposeArticle/app/src/main/java/com/example/composearticle/MainActivity.kt b/Unit1/Pathway3/ComposeArticle/app/src/main/java/com/example/composearticle/MainActivity.kt index da2245997..a4c0c28a6 100644 --- a/Unit1/Pathway3/ComposeArticle/app/src/main/java/com/example/composearticle/MainActivity.kt +++ b/Unit1/Pathway3/ComposeArticle/app/src/main/java/com/example/composearticle/MainActivity.kt @@ -4,15 +4,14 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -24,12 +23,24 @@ import com.example.composearticle.ui.theme.ComposeArticleTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContent { } + setContent { + androidx.compose.material.Surface(color = MaterialTheme.colors.background) { + ComposeArticleApp() + } + } } } @Composable -fun ComposeArticleApp() { } +fun ComposeArticleApp() { + ArticleCard(title = stringResource(R.string.title_jetpack_compose_tutorial), + shortDescription = stringResource(R.string.compose_short_desc), + longDescription = stringResource(R.string.compose_long_desc), + imagePainter = painterResource(id = R.drawable.bg_compose_background), + modifier = Modifier + ) + +} @Composable private fun ArticleCard( @@ -39,10 +50,52 @@ private fun ArticleCard( imagePainter: Painter, modifier: Modifier = Modifier, ) { - Column() { } + Column() { + Image(painter = imagePainter, + contentDescription = null, + contentScale = ContentScale.FillWidth + ) + Text( + text = title, + fontSize = 24.sp, + modifier = modifier + .padding(start = 16.dp, end = 16.dp, bottom = 16.dp, top = 16.dp) + ) + Text( + text = shortDescription, + textAlign = TextAlign.Justify, + modifier = modifier + .padding(start = 16.dp, end = 16.dp) + ) + Text( + text = longDescription, + textAlign = TextAlign.Justify, + modifier = modifier + .padding(start = 16.dp, end = 16.dp, bottom = 16.dp, top = 16.dp) + ) + } + } @Preview(showBackground = true) @Composable -fun DefaultPreview() { } \ No newline at end of file +fun DefaultPreview() { + ComposeArticleTheme() { + Surface { + ComposeArticleApp() + } + } +} + + + + + + + + + + + + diff --git a/Unit1/Pathway3/ComposeQuadrant/app/src/main/java/com/example/composequadrant/MainActivity.kt b/Unit1/Pathway3/ComposeQuadrant/app/src/main/java/com/example/composequadrant/MainActivity.kt index 61b87324c..0c59c57fd 100644 --- a/Unit1/Pathway3/ComposeQuadrant/app/src/main/java/com/example/composequadrant/MainActivity.kt +++ b/Unit1/Pathway3/ComposeQuadrant/app/src/main/java/com/example/composequadrant/MainActivity.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -22,15 +23,56 @@ import com.example.composequadrant.ui.theme.ComposeQuadrantTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContent { } + setContent { + ComposeQuadrantTheme() { + Surface{ + ComposeQuadrantApp() + } + } + } } } @Composable fun ComposeQuadrantApp() { - Column() { - Row() { } - Row() { } + Column(modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + ) { + Row( + modifier = Modifier + .weight(1f) + ) { + ComposableInfoCard( + title = stringResource(id = R.string.first_title), + description = stringResource(id = R.string.first_description), + backgroundColor = Color.Green, + modifier = Modifier.weight(1f) + ) + ComposableInfoCard( + title = stringResource(id = R.string.second_title), + description = stringResource(id = R.string.second_description), + backgroundColor = Color.Yellow, + modifier = Modifier.weight(1f) + ) + } + Row( + modifier = Modifier + .weight(1f) + ) { + ComposableInfoCard( + title = stringResource(id = R.string.third_title), + description = stringResource(id = R.string.third_description), + backgroundColor = Color.Cyan, + modifier = Modifier.weight(1f) + ) + ComposableInfoCard( + title = stringResource(id = R.string.fourth_title), + description = stringResource(id = R.string.fourth_description), + backgroundColor = Color.LightGray, + modifier = Modifier.weight(1f) + ) + } } } @@ -41,10 +83,47 @@ private fun ComposableInfoCard( backgroundColor: Color, modifier: Modifier = Modifier ) { - Column( ) { } + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = modifier + .fillMaxWidth() + .fillMaxHeight() + .background(backgroundColor) + .padding(16.dp) + ) { + Text( + text = title, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(bottom = 16.dp) + ) + Text( + text = description, + textAlign = TextAlign.Justify + ) + } } @Preview(showBackground = true) @Composable -fun DefaultPreview() { } \ No newline at end of file +fun DefaultPreview() { + ComposeQuadrantTheme() { + Surface{ + ComposeQuadrantApp() + } + } +} + + + + + + + + + + + + + diff --git a/Unit1/Pathway3/TaskCompleted/app/src/main/java/com/example/taskcompleted/MainActivity.kt b/Unit1/Pathway3/TaskCompleted/app/src/main/java/com/example/taskcompleted/MainActivity.kt index 840cfd96c..85a613869 100644 --- a/Unit1/Pathway3/TaskCompleted/app/src/main/java/com/example/taskcompleted/MainActivity.kt +++ b/Unit1/Pathway3/TaskCompleted/app/src/main/java/com/example/taskcompleted/MainActivity.kt @@ -10,7 +10,10 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.CenterHorizontally +import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier +import androidx.compose.ui.modifier.modifierLocalOf import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -22,15 +25,50 @@ import com.example.taskcompleted.ui.theme.TaskCompletedTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContent { } + setContent { + TaskCompletedTheme() { + TaskCompletedScreen() + } + } } } @Composable fun TaskCompletedScreen() { - Column( ) { } + Column( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + horizontalAlignment = CenterHorizontally, + verticalArrangement = Arrangement.Center + + ) { + Image( + painter = painterResource(id = R.drawable.ic_task_completed), + contentDescription = null + ) + Text( + text = stringResource(id = R.string.all_task_completed), + fontSize = 24.sp, + modifier = Modifier + .padding(top = 24.dp, bottom = 8.dp) + ) + Text( + text = stringResource(id = R.string.nice_work), + fontSize = 16.sp + ) + + } } @Preview(showBackground = true) @Composable -fun DefaultPreview() { } \ No newline at end of file +fun DefaultPreview() { + TaskCompletedTheme() { + Surface { + TaskCompletedScreen() + } + + } + +} \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/.gitignore b/Unit2/Pathway2/DiceRoller/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/build.gradle b/Unit2/Pathway2/DiceRoller/app/build.gradle new file mode 100644 index 000000000..d7123fd83 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/build.gradle @@ -0,0 +1,65 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.example.diceroller' + compileSdk 32 + + defaultConfig { + applicationId "com.example.diceroller" + minSdk 21 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.activity:activity-compose:1.4.0' + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation 'androidx.activity:activity-compose:1.4.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + +} \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/proguard-rules.pro b/Unit2/Pathway2/DiceRoller/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/androidTest/java/com/example/diceroller/ExampleInstrumentedTest.kt b/Unit2/Pathway2/DiceRoller/app/src/androidTest/java/com/example/diceroller/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..56697a23d --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/androidTest/java/com/example/diceroller/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.diceroller + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.diceroller", appContext.packageName) + } +} \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/AndroidManifest.xml b/Unit2/Pathway2/DiceRoller/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..6f64e271f --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/MainActivity.kt b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/MainActivity.kt new file mode 100644 index 000000000..b358e9ebc --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/MainActivity.kt @@ -0,0 +1,70 @@ +package com.example.diceroller + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.example.diceroller.ui.theme.DiceRollerTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + DiceRollerTheme { + DiceRollerApp() + } + } + } +} + +@Composable +fun DiceWithButtonAndImage(modifier: Modifier = Modifier) { + var result by remember { mutableStateOf(1) } + val imageResource = when(result) { + 1 -> R.drawable.dice_1 + 2 -> R.drawable.dice_2 + 3 -> R.drawable.dice_3 + 4 -> R.drawable.dice_4 + 5 -> R.drawable.dice_5 + else -> R.drawable.dice_6 + } + + Column ( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Image( + painter = painterResource(id = imageResource), + contentDescription = result.toString() + ) + Spacer(modifier = Modifier.height(16.dp)) + Button( + onClick = { + result = (1..6).random() + } + ) { + Text( + text = stringResource(id = R.string.roll) + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun DiceRollerApp() { + DiceWithButtonAndImage(modifier = Modifier + .fillMaxSize() + .wrapContentSize(Alignment.Center) + ) +} \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Color.kt b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Color.kt new file mode 100644 index 000000000..a15709145 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.example.diceroller.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFBB86FC) +val Purple500 = Color(0xFF6200EE) +val Purple700 = Color(0xFF3700B3) +val Teal200 = Color(0xFF03DAC5) \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Shape.kt b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Shape.kt new file mode 100644 index 000000000..fc2b35df7 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.example.diceroller.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Theme.kt b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Theme.kt new file mode 100644 index 000000000..69e7a8021 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Theme.kt @@ -0,0 +1,44 @@ +package com.example.diceroller.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun DiceRollerTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Type.kt b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Type.kt new file mode 100644 index 000000000..9719bbc73 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/java/com/example/diceroller/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.example.diceroller.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_1.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_1.xml new file mode 100644 index 000000000..2bd436bb6 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_1.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_2.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_2.xml new file mode 100644 index 000000000..30fb235c0 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_2.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_3.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_3.xml new file mode 100644 index 000000000..20bf47221 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_3.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_4.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_4.xml new file mode 100644 index 000000000..772737d9c --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_4.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_5.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_5.xml new file mode 100644 index 000000000..b1e6afe83 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_5.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_6.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_6.xml new file mode 100644 index 000000000..484f92e8a --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/dice_6.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable/ic_launcher_background.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable/ic_launcher_background.xml rename to Unit2/Pathway2/DiceRoller/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-hdpi/ic_launcher.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-hdpi/ic_launcher.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-hdpi/ic_launcher.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-mdpi/ic_launcher.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-mdpi/ic_launcher.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-mdpi/ic_launcher.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xhdpi/ic_launcher.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xhdpi/ic_launcher.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xhdpi/ic_launcher.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp similarity index 100% rename from Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp rename to Unit2/Pathway2/DiceRoller/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/values/colors.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/values/strings.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..51b1bfd90 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + Dice Roller + + Roll + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/values/themes.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..1d1b2f6c1 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/xml/backup_rules.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 000000000..fa0f996d2 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/main/res/xml/data_extraction_rules.xml b/Unit2/Pathway2/DiceRoller/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 000000000..9ee9997b0 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/DiceRoller/app/src/test/java/com/example/diceroller/ExampleUnitTest.kt b/Unit2/Pathway2/DiceRoller/app/src/test/java/com/example/diceroller/ExampleUnitTest.kt new file mode 100644 index 000000000..9136b8558 --- /dev/null +++ b/Unit2/Pathway2/DiceRoller/app/src/test/java/com/example/diceroller/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.diceroller + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/.gitignore b/Unit2/Pathway2/Lemonade/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/Unit2/Pathway2/Lemonade/app/.gitignore b/Unit2/Pathway2/Lemonade/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/build.gradle b/Unit2/Pathway2/Lemonade/app/build.gradle new file mode 100644 index 000000000..e36798909 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.example.lemonade' + compileSdk 32 + + defaultConfig { + applicationId "com.example.lemonade" + minSdk 21 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion '1.1.1' + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' + implementation 'androidx.activity:activity-compose:1.3.1' + implementation "androidx.compose.ui:ui:$compose_ui_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version" + implementation 'androidx.compose.material:material:1.1.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version" +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/proguard-rules.pro b/Unit2/Pathway2/Lemonade/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/androidTest/java/com/example/lemonade/ExampleInstrumentedTest.kt b/Unit2/Pathway2/Lemonade/app/src/androidTest/java/com/example/lemonade/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..d1cc255b1 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/androidTest/java/com/example/lemonade/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.lemonade + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.lemonade", appContext.packageName) + } +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/AndroidManifest.xml b/Unit2/Pathway2/Lemonade/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..2f14b6ee8 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/MainActivity.kt b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/MainActivity.kt new file mode 100644 index 000000000..b0a877036 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/MainActivity.kt @@ -0,0 +1,133 @@ +package com.example.lemonade + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.lemonade.ui.theme.LemonadeTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + LemonadeTheme { + // A surface container using the 'background' color from the theme + Surface { + MakeLemonade() + } + } + } + } +} + +@Composable +fun MakeLemonade(){ + var step by remember { mutableStateOf(1) } + var lemonTapCount by remember { mutableStateOf(0) } + + when(step){ + 1 -> { + showEachStep( + painter = painterResource(id = R.drawable.lemon_tree), + title = stringResource(id = R.string.step1_title), + contentDesc = stringResource(id = R.string.step1_content_description), + onClickListener = { + step = 2 + lemonTapCount = (2..4).random() + } + ) + } + 2 -> { + showEachStep( + painter = painterResource(id = R.drawable.lemon_squeeze), + title = stringResource(id = R.string.step2_title), + contentDesc = stringResource(id = R.string.step2_content_description), + onClickListener = { + lemonTapCount -- + if(lemonTapCount == 0) { + step = 3 + } + } + ) + } + 3 -> { + showEachStep( + painter = painterResource(id = R.drawable.lemon_drink), + title = stringResource(id = R.string.step3_title), + contentDesc = stringResource(id = R.string.step3_content_description), + onClickListener = { + step = 4 + } + ) + } + else -> { + showEachStep( + painter = painterResource(id = R.drawable.lemon_restart), + title = stringResource(id = R.string.step4_title), + contentDesc = stringResource(id = R.string.step4_content_description), + onClickListener = { + step = 1 + } + ) + } + } +} + +@Composable +fun showEachStep( + painter : Painter, + title : String, + contentDesc : String, + onClickListener : () -> Unit +){ + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxSize() + ) { + Text( + text = title, + fontSize = 18.sp + ) + Spacer(modifier = Modifier.height(16.dp)) + Image( + painter = painter, + contentDescription = contentDesc, + modifier = Modifier + .wrapContentSize() + .border( + BorderStroke(1.dp, Color(105, 205, 216)), + shape = RoundedCornerShape(25.dp) + ) + .padding(16.dp) + .clickable( + onClick = onClickListener + ) + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DefaultPreview() { + LemonadeTheme { + MakeLemonade() + } +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Color.kt b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Color.kt new file mode 100644 index 000000000..7d85d84f9 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.example.lemonade.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFBB86FC) +val Purple500 = Color(0xFF6200EE) +val Purple700 = Color(0xFF3700B3) +val Teal200 = Color(0xFF03DAC5) \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Shape.kt b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Shape.kt new file mode 100644 index 000000000..7493aa03f --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.example.lemonade.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Theme.kt b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Theme.kt new file mode 100644 index 000000000..3cbd0358d --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Theme.kt @@ -0,0 +1,44 @@ +package com.example.lemonade.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun LemonadeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Type.kt b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Type.kt new file mode 100644 index 000000000..7481002c8 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/java/com/example/lemonade/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.example.lemonade.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/ic_launcher_background.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_drink.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_drink.xml new file mode 100644 index 000000000..1675978b2 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_drink.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_restart.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_restart.xml new file mode 100644 index 000000000..c5f5379bf --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_restart.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_squeeze.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_squeeze.xml new file mode 100644 index 000000000..cc90a9324 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_squeeze.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_tree.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_tree.xml new file mode 100644 index 000000000..a307871cd --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/drawable/lemon_tree.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/Unit2/Pathway2/Lemonade/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/values/colors.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/values/strings.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..57293f239 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/values/strings.xml @@ -0,0 +1,13 @@ + + Lemonade + + Tap the lemon tree to select a lemon + Keep tapping the lemon to squeeze it + Tap the lemonade to drink it + Tap the empty glass to start again + + Lemon tree + Lemon + Glass of lemonade + Empty glass + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/values/themes.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..92e729eed --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/xml/backup_rules.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 000000000..fa0f996d2 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/main/res/xml/data_extraction_rules.xml b/Unit2/Pathway2/Lemonade/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 000000000..9ee9997b0 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/app/src/test/java/com/example/lemonade/ExampleUnitTest.kt b/Unit2/Pathway2/Lemonade/app/src/test/java/com/example/lemonade/ExampleUnitTest.kt new file mode 100644 index 000000000..1569bcbe4 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/app/src/test/java/com/example/lemonade/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.lemonade + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/build.gradle b/Unit2/Pathway2/Lemonade/build.gradle new file mode 100644 index 000000000..15dff9ef8 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/build.gradle @@ -0,0 +1,10 @@ +buildscript { + ext { + compose_ui_version = '1.1.1' + } +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.3.1' apply false + id 'com.android.library' version '7.3.1' apply false + id 'org.jetbrains.kotlin.android' version '1.6.10' apply false +} \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/gradle.properties b/Unit2/Pathway2/Lemonade/gradle.properties new file mode 100644 index 000000000..3c5031eb7 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/Unit2/Pathway2/Lemonade/gradle/wrapper/gradle-wrapper.jar b/Unit2/Pathway2/Lemonade/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..e708b1c02 Binary files /dev/null and b/Unit2/Pathway2/Lemonade/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Unit2/Pathway2/Lemonade/gradle/wrapper/gradle-wrapper.properties b/Unit2/Pathway2/Lemonade/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a81395f13 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Dec 08 00:32:19 KST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/Unit2/Pathway2/Lemonade/gradlew b/Unit2/Pathway2/Lemonade/gradlew new file mode 100644 index 000000000..4f906e0c8 --- /dev/null +++ b/Unit2/Pathway2/Lemonade/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/Unit2/Pathway2/Lemonade/gradlew.bat b/Unit2/Pathway2/Lemonade/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/Unit2/Pathway2/Lemonade/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Unit2/Pathway2/Lemonade/settings.gradle b/Unit2/Pathway2/Lemonade/settings.gradle new file mode 100644 index 000000000..64e1f070d --- /dev/null +++ b/Unit2/Pathway2/Lemonade/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Lemonade" +include ':app' diff --git a/Unit2/Pathway3/ArtSpace/.gitignore b/Unit2/Pathway3/ArtSpace/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/Unit2/Pathway3/ArtSpace/app/.gitignore b/Unit2/Pathway3/ArtSpace/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/build.gradle b/Unit2/Pathway3/ArtSpace/app/build.gradle new file mode 100644 index 000000000..7a7b53133 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.example.artspace' + compileSdk 32 + + defaultConfig { + applicationId "com.example.artspace" + minSdk 21 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion '1.1.1' + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' + implementation 'androidx.activity:activity-compose:1.3.1' + implementation "androidx.compose.ui:ui:$compose_ui_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version" + implementation 'androidx.compose.material:material:1.1.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version" +} \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/proguard-rules.pro b/Unit2/Pathway3/ArtSpace/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/androidTest/java/com/example/artspace/ExampleInstrumentedTest.kt b/Unit2/Pathway3/ArtSpace/app/src/androidTest/java/com/example/artspace/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..d778e2354 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/androidTest/java/com/example/artspace/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.artspace + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.artspace", appContext.packageName) + } +} \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/AndroidManifest.xml b/Unit2/Pathway3/ArtSpace/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..1769642f7 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/MainActivity.kt b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/MainActivity.kt new file mode 100644 index 000000000..e2da64531 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/MainActivity.kt @@ -0,0 +1,205 @@ +package com.example.artspace + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.artspace.ui.theme.ArtSpaceTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ArtSpaceTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + InitArtSpace() + } + } + } + } +} + +@Composable +fun InitArtSpace() { + + var page by remember { + mutableStateOf(1) + } + + when(page){ + 1 -> { + ShowArtSpace( + R.drawable.picture_1, + R.string.picture_1_title, + R.string.picture_1_artist, + R.string.picture_1_content_description, + previousOnClickListener = { + page = 3 + }, + nextOnClickListener = { + page = 2 + } + ) + } + 2 -> { + ShowArtSpace( + R.drawable.picture_2, + R.string.picture_2_title, + R.string.picture_2_artist, + R.string.picture_2_content_description, + previousOnClickListener = { + page = 1 + }, + nextOnClickListener = { + page = 3 + } + ) + } + else -> { + ShowArtSpace( + R.drawable.picture_3, + R.string.picture_3_title, + R.string.picture_3_artist, + R.string.picture_3_content_description, + previousOnClickListener = { + page = 2 + }, + nextOnClickListener = { + page = 1 + } + ) + } + } +} + +@Composable +fun ShowArtSpace( + imageId : Int, + titleId : Int, + artistId : Int, + contentDescId : Int, + previousOnClickListener: () -> Unit, + nextOnClickListener: () -> Unit +){ + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ){ + Surface( + elevation = 5.dp, + border = BorderStroke(1.dp, Color.Gray), + modifier = Modifier.wrapContentSize() + ) { + Image( + painter = painterResource(id = imageId), + contentDescription = stringResource(id = contentDescId), + modifier = Modifier.padding(20.dp), + contentScale = ContentScale.Inside + ) + } + Spacer(modifier = Modifier.height(30.dp)) + + Surface( + elevation = 5.dp, + border = BorderStroke(1.dp, Color.Gray), + modifier = Modifier.wrapContentSize() + ){ + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .wrapContentSize() + .padding(top = 5.dp, bottom = 5.dp, start = 10.dp, end = 10.dp) + ) { + Text( + text = stringResource(id = titleId), + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(10.dp)) + + Text( + text = stringResource(id = artistId), + textAlign = TextAlign.Center + ) + } + } + + Spacer(modifier = Modifier.height(30.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceAround + ) { + Text( + text = "Previous", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + modifier = Modifier + .weight(1f) + .background(color = Color.Cyan, shape = RoundedCornerShape(5.dp)) + .border( + BorderStroke(1.dp, color = Color.Black), + shape = RoundedCornerShape(5.dp) + ) + .padding(top = 5.dp, bottom = 5.dp, start = 10.dp, end = 10.dp) + .clickable( + onClick = previousOnClickListener + ) + ) + + Spacer(modifier = Modifier.weight(0.5f)) + Text( + text = "Next", + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + modifier = Modifier + .weight(1f) + .background(color = Color.Cyan, shape = RoundedCornerShape(5.dp)) + .border( + BorderStroke(1.dp, color = Color.Black), + shape = RoundedCornerShape(5.dp) + ) + .padding(top = 5.dp, bottom = 5.dp, start = 10.dp, end = 10.dp) + .clickable( + onClick = nextOnClickListener + ) + ) + } + + } +} + +@Preview(showBackground = true) +@Composable +fun DefaultPreview() { + ArtSpaceTheme { + InitArtSpace() + } +} \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Color.kt b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Color.kt new file mode 100644 index 000000000..51a27509f --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.example.artspace.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFBB86FC) +val Purple500 = Color(0xFF6200EE) +val Purple700 = Color(0xFF3700B3) +val Teal200 = Color(0xFF03DAC5) \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Shape.kt b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Shape.kt new file mode 100644 index 000000000..95b14b077 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.example.artspace.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Theme.kt b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Theme.kt new file mode 100644 index 000000000..0d48ce512 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Theme.kt @@ -0,0 +1,44 @@ +package com.example.artspace.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun ArtSpaceTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Type.kt b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Type.kt new file mode 100644 index 000000000..1ada8704e --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/java/com/example/artspace/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.example.artspace.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/ic_launcher_background.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_1.jpg b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_1.jpg new file mode 100644 index 000000000..c4b4e319c Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_1.jpg differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_2.jpg b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_2.jpg new file mode 100644 index 000000000..e16796a2a Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_2.jpg differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_3.jpg b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_3.jpg new file mode 100644 index 000000000..a39ec48af Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/drawable/picture_3.jpg differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/values/colors.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/values/strings.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..a4a76729f --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/values/strings.xml @@ -0,0 +1,15 @@ + + Art Space + + Grilling Beef + DE Hahn(2022.11) + Grilling Beef + + Bottles Of Wine + DE Hahn(2022.11) + Bottles Of Wine + + Fireworks + DE Hahn(2022.10) + Fireworks + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/values/themes.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..23a10bedd --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/xml/backup_rules.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 000000000..fa0f996d2 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/main/res/xml/data_extraction_rules.xml b/Unit2/Pathway3/ArtSpace/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 000000000..9ee9997b0 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/app/src/test/java/com/example/artspace/ExampleUnitTest.kt b/Unit2/Pathway3/ArtSpace/app/src/test/java/com/example/artspace/ExampleUnitTest.kt new file mode 100644 index 000000000..fde12fe0b --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/app/src/test/java/com/example/artspace/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.artspace + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/build.gradle b/Unit2/Pathway3/ArtSpace/build.gradle new file mode 100644 index 000000000..15dff9ef8 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/build.gradle @@ -0,0 +1,10 @@ +buildscript { + ext { + compose_ui_version = '1.1.1' + } +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.3.1' apply false + id 'com.android.library' version '7.3.1' apply false + id 'org.jetbrains.kotlin.android' version '1.6.10' apply false +} \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/gradle.properties b/Unit2/Pathway3/ArtSpace/gradle.properties new file mode 100644 index 000000000..3c5031eb7 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/Unit2/Pathway3/ArtSpace/gradle/wrapper/gradle-wrapper.jar b/Unit2/Pathway3/ArtSpace/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..e708b1c02 Binary files /dev/null and b/Unit2/Pathway3/ArtSpace/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Unit2/Pathway3/ArtSpace/gradle/wrapper/gradle-wrapper.properties b/Unit2/Pathway3/ArtSpace/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..4c0553fe4 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Dec 09 00:05:58 KST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/Unit2/Pathway3/ArtSpace/gradlew b/Unit2/Pathway3/ArtSpace/gradlew new file mode 100644 index 000000000..4f906e0c8 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/Unit2/Pathway3/ArtSpace/gradlew.bat b/Unit2/Pathway3/ArtSpace/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Unit2/Pathway3/ArtSpace/settings.gradle b/Unit2/Pathway3/ArtSpace/settings.gradle new file mode 100644 index 000000000..a7ef376e9 --- /dev/null +++ b/Unit2/Pathway3/ArtSpace/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Art Space" +include ':app' diff --git a/Unit2/Pathway3/TipTime/.gitignore b/Unit2/Pathway3/TipTime/.gitignore new file mode 100644 index 000000000..aa724b770 --- /dev/null +++ b/Unit2/Pathway3/TipTime/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/Unit2/Pathway3/TipTime/app/.gitignore b/Unit2/Pathway3/TipTime/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/build.gradle b/Unit2/Pathway3/TipTime/app/build.gradle new file mode 100644 index 000000000..8bf1e4563 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.example.tiptime' + compileSdk 32 + + defaultConfig { + applicationId "com.example.tiptime" + minSdk 21 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion '1.2.0' + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' + implementation 'androidx.activity:activity-compose:1.5.1' + implementation "androidx.compose.ui:ui:$compose_ui_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version" + implementation "androidx.compose.material:material:$compose_ui_version" + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version" +} \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/proguard-rules.pro b/Unit2/Pathway3/TipTime/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/androidTest/java/com/example/tiptime/ExampleInstrumentedTest.kt b/Unit2/Pathway3/TipTime/app/src/androidTest/java/com/example/tiptime/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..f21106b85 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/androidTest/java/com/example/tiptime/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.tiptime + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.tiptime", appContext.packageName) + } +} \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/AndroidManifest.xml b/Unit2/Pathway3/TipTime/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..66c593744 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/MainActivity.kt b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/MainActivity.kt new file mode 100644 index 000000000..793446f90 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/MainActivity.kt @@ -0,0 +1,99 @@ +package com.example.tiptime + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.modifier.modifierLocalConsumer +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.content.pm.ShortcutInfoCompat.Surface +import com.example.tiptime.ui.theme.TipTimeTheme +import java.text.NumberFormat + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + TipTimeTheme { + // A surface container using the 'background' color from the theme + TipTimeScreen() + } + } + } +} + +@Composable +fun TipTimeScreen() { + var amountInput by remember { + mutableStateOf("") + } + val amount = amountInput.toDoubleOrNull() ?: 0.0 + val tip = calculateTip(amount) + + Column( + modifier = Modifier.padding(32.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = stringResource(R.string.calculate_tip), + fontSize = 24.sp, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + Spacer(Modifier.height(16.dp)) + EditNumberField( + value = amountInput, + onValueChange = {amountInput = it} + ) + Spacer(Modifier.height(24.dp)) + Text( + text = stringResource(R.string.tip_amount, tip), + textAlign = TextAlign.Center, + fontSize = 20.sp, + fontWeight = FontWeight.Bold + ) + + } +} + +@Composable +fun EditNumberField( + value : String, + onValueChange : (String) -> Unit +) { + TextField( + value = value, + onValueChange = onValueChange, + label = { Text(stringResource(R.string.cost_of_service)) }, + modifier = Modifier.fillMaxWidth(), + singleLine = true, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) + ) +} + +private fun calculateTip( + amount: Double, + tipPercent: Double = 15.0 +) : String { + val tip = tipPercent / 100 * amount + return NumberFormat.getCurrencyInstance().format(tip) +} + +@Preview(showBackground = true) +@Composable +fun DefaultPreview() { + TipTimeTheme { + TipTimeScreen() + } +} \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Color.kt b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Color.kt new file mode 100644 index 000000000..d5aa49053 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.example.tiptime.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFBB86FC) +val Purple500 = Color(0xFF6200EE) +val Purple700 = Color(0xFF3700B3) +val Teal200 = Color(0xFF03DAC5) \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Shape.kt b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Shape.kt new file mode 100644 index 000000000..764529ae6 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.example.tiptime.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Theme.kt b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Theme.kt new file mode 100644 index 000000000..27d8d98c8 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Theme.kt @@ -0,0 +1,44 @@ +package com.example.tiptime.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun TipTimeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Type.kt b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Type.kt new file mode 100644 index 000000000..c3259af69 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/java/com/example/tiptime/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.example.tiptime.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Unit2/Pathway3/TipTime/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/drawable/ic_launcher_background.xml b/Unit2/Pathway3/TipTime/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/Unit2/Pathway3/TipTime/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/values/colors.xml b/Unit2/Pathway3/TipTime/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/values/strings.xml b/Unit2/Pathway3/TipTime/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..f0decabbc --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + Tip Time + Calculate Tip + Cost of Service + Tip amount: %s + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/values/themes.xml b/Unit2/Pathway3/TipTime/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..941c637ec --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/xml/backup_rules.xml b/Unit2/Pathway3/TipTime/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 000000000..fa0f996d2 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/main/res/xml/data_extraction_rules.xml b/Unit2/Pathway3/TipTime/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 000000000..9ee9997b0 --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/app/src/test/java/com/example/tiptime/ExampleUnitTest.kt b/Unit2/Pathway3/TipTime/app/src/test/java/com/example/tiptime/ExampleUnitTest.kt new file mode 100644 index 000000000..f3c5af88d --- /dev/null +++ b/Unit2/Pathway3/TipTime/app/src/test/java/com/example/tiptime/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.tiptime + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/build.gradle b/Unit2/Pathway3/TipTime/build.gradle new file mode 100644 index 000000000..c7cf3d983 --- /dev/null +++ b/Unit2/Pathway3/TipTime/build.gradle @@ -0,0 +1,10 @@ +buildscript { + ext { + compose_ui_version = '1.2.0' + } +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.3.1' apply false + id 'com.android.library' version '7.3.1' apply false + id 'org.jetbrains.kotlin.android' version '1.7.0' apply false +} \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/gradle.properties b/Unit2/Pathway3/TipTime/gradle.properties new file mode 100644 index 000000000..3c5031eb7 --- /dev/null +++ b/Unit2/Pathway3/TipTime/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/Unit2/Pathway3/TipTime/gradle/wrapper/gradle-wrapper.jar b/Unit2/Pathway3/TipTime/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..e708b1c02 Binary files /dev/null and b/Unit2/Pathway3/TipTime/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Unit2/Pathway3/TipTime/gradle/wrapper/gradle-wrapper.properties b/Unit2/Pathway3/TipTime/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..0e3fd8ce4 --- /dev/null +++ b/Unit2/Pathway3/TipTime/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Dec 08 01:59:06 KST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/Unit2/Pathway3/TipTime/gradlew b/Unit2/Pathway3/TipTime/gradlew new file mode 100644 index 000000000..4f906e0c8 --- /dev/null +++ b/Unit2/Pathway3/TipTime/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/Unit2/Pathway3/TipTime/gradlew.bat b/Unit2/Pathway3/TipTime/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/Unit2/Pathway3/TipTime/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Unit2/Pathway3/TipTime/settings.gradle b/Unit2/Pathway3/TipTime/settings.gradle new file mode 100644 index 000000000..09edcfc33 --- /dev/null +++ b/Unit2/Pathway3/TipTime/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Tip Time" +include ':app' diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/ic_launcher-playstore.png b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/ic_launcher-playstore.png new file mode 100644 index 000000000..6b5b3a213 Binary files /dev/null and b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/ic_launcher-playstore.png differ diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/MainActivity.kt b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/MainActivity.kt index dc2023b3b..7ce972bfb 100644 --- a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/MainActivity.kt +++ b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/MainActivity.kt @@ -17,8 +17,25 @@ package com.example.affirmationscodelab import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.material.Scaffold +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Card +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.example.affirmationscodelab.data.Datasource +import com.example.affirmationscodelab.model.Affirmation import com.example.affirmationscodelab.ui.theme.AffirmationsTheme class MainActivity : ComponentActivity() { @@ -33,5 +50,73 @@ class MainActivity : ComponentActivity() { @Composable fun AffirmationApp() { AffirmationsTheme { + AffirmationList(affirmationList = Datasource().loadAffirmations()) } } + +@Composable +fun AffirmationCard( + affirmation: Affirmation, + modifier: Modifier = Modifier +){ + Card( + modifier = modifier.padding(8.dp), + elevation = 4.dp + ) { + Column() { + Image( + painter = painterResource(id = affirmation.imageResourceId), + contentDescription = stringResource(id = affirmation.stringResourceId), + modifier = Modifier + .fillMaxWidth() + .height(194.dp), + contentScale = ContentScale.Crop + ) + Text( + text = stringResource(affirmation.stringResourceId), + modifier = Modifier.padding(16.dp), + style = MaterialTheme.typography.h6 + ) + } + } + +} + +@Composable +private fun AffirmationList( + affirmationList: List, + modifier: Modifier = Modifier) { + LazyColumn { + items(affirmationList){ + item: Affirmation -> AffirmationCard(affirmation = item) + } + } +} + + + +@Preview +@Composable +private fun AffirmationCardPreview(){ + AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1)) +} + + + + + + + + + + + + + + + + + + + + diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/data/Datasource.kt b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/data/Datasource.kt index 7d99d4916..932017066 100644 --- a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/data/Datasource.kt +++ b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/data/Datasource.kt @@ -15,12 +15,13 @@ */ package com.example.affirmationscodelab.data import com.example.affirmationscodelab.R +import com.example.affirmationscodelab.model.Affirmation /** * [Datasource] generates a list of [Affirmation] */ class Datasource() { - /*fun loadAffirmations(): List { + fun loadAffirmations(): List { return listOf( Affirmation(R.string.affirmation1, R.drawable.image1), Affirmation(R.string.affirmation2, R.drawable.image2), @@ -32,5 +33,5 @@ class Datasource() { Affirmation(R.string.affirmation8, R.drawable.image8), Affirmation(R.string.affirmation9, R.drawable.image9), Affirmation(R.string.affirmation10, R.drawable.image10)) - }*/ + } } diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/model/Affirmation.kt b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/model/Affirmation.kt new file mode 100644 index 000000000..8d02936cc --- /dev/null +++ b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/java/com/example/affirmationscodelab/model/Affirmation.kt @@ -0,0 +1,9 @@ +package com.example.affirmationscodelab.model + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes + +data class Affirmation( + @StringRes val stringResourceId: Int, + @DrawableRes val imageResourceId: Int +) diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_background.xml b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_background.xml index 88a65b4b7..ddbaedc2d 100644 --- a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_background.xml +++ b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_background.xml @@ -21,18 +21,23 @@ android:height="108dp" android:viewportWidth="108" android:viewportHeight="108"> - - - - - - - - + + + + + + + + + + diff --git a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_foreground.xml index 2b068d114..7f6440ef3 100644 --- a/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ b/Unit3/Pathway2/AffirmationsCodelab/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -1,30 +1,14 @@ - - - - - - - - + + android:pathData="M38.19,65.92L69.32,65.92a1.2,1.2 0,0 0,1.2 -1.2,0.89 0.89,0 0,0 0,-0.23 17,17 0,0 0,-33.25 0,1.18 1.18,0 0,0 0.9,1.42ZM74.53,69.05a0.85,0.85 0,0 0,-0.78 -0.84L34,68.21a0.85,0.85 0,0 0,-0.77 0.84v2.82a0.84,0.84 0,0 0,0.77 0.86L73.78,72.73a0.85,0.85 0,0 0,0.77 -0.86L74.55,70.65C74.55,70.24 74.56,69.58 74.53,69.05ZM52.08,49h3.59a1.86,1.86 0,0 0,0 -3.72L52.08,45.28a1.86,1.86 0,0 0,0 3.72ZM53.87,39.81a1.19,1.19 0,0 0,1.19 -1.19L55.06,32.87a1.19,1.19 0,0 0,-2.38 0v5.71a1.19,1.19 0,0 0,1.19 1.19h0ZM61.69,41l4.62,-3.35a1.19,1.19 0,1 0,-1.4 -1.93L60.29,39A1.2,1.2 0,0 0,60 40.67a1.18,1.18 0,0 0,1.66 0.26ZM41.69,37.65L46.31,41a1.2,1.2 0,0 0,1.35 -2L43,35.66a1.19,1.19 0,0 0,-1.66 0.26,1.2 1.2,0 0,0 0.3,1.67Z" + android:fillColor="#FFFFFF"/> + \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/build.gradle b/Unit3/Pathway3/WoofCodelab/app/build.gradle index 854a8f86b..4d0e207cc 100644 --- a/Unit3/Pathway3/WoofCodelab/app/build.gradle +++ b/Unit3/Pathway3/WoofCodelab/app/build.gradle @@ -71,4 +71,6 @@ dependencies { implementation "androidx.compose.material:material:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + + implementation "androidx.compose.material:material-icons-extended:$compose_version" } \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/MainActivity.kt b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/MainActivity.kt index 26d4256d7..237f49958 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/MainActivity.kt +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/MainActivity.kt @@ -20,23 +20,32 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.animateContentSize +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.Text -import androidx.compose.runtime.Composable +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ExpandLess +import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.example.woofcodelab.data.Dog import com.example.woofcodelab.data.dogs +import com.example.woofcodelab.ui.theme.Green100 import com.example.woofcodelab.ui.theme.WoofTheme class MainActivity : ComponentActivity() { @@ -55,13 +64,41 @@ class MainActivity : ComponentActivity() { */ @Composable fun WoofApp() { - LazyColumn { - items(dogs) { - DogItem(dog = it) + Scaffold( + topBar = { + WoofTopAppBar() + } + ) { + LazyColumn(modifier = Modifier.background(MaterialTheme.colors.background)) { + items(dogs) { + DogItem(dog = it) + } } } } +@Composable +fun WoofTopAppBar(modifier: Modifier = Modifier) { + Row(modifier = modifier + .fillMaxWidth() + .background(color = MaterialTheme.colors.primary), + verticalAlignment = Alignment.CenterVertically + + ) { + Image( + modifier = Modifier + .size(64.dp) + .padding(8.dp), + painter = painterResource(R.drawable.ic_woof_logo), + contentDescription = null + ) + Text( + text = stringResource(R.string.app_name), + style = MaterialTheme.typography.h1 + ) + } +} + /** * Composable that displays a list item containing a dog icon and their information. * @@ -70,13 +107,43 @@ fun WoofApp() { */ @Composable fun DogItem(dog: Dog, modifier: Modifier = Modifier) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(8.dp) + var expanded by remember { mutableStateOf(false) } + + val color by animateColorAsState( + targetValue = if(expanded) Green100 else MaterialTheme.colors.surface + ) + + Card( + modifier = modifier.padding(8.dp), + elevation = 4.dp ) { - DogIcon(dog.imageResourceId) - DogInformation(dog.name, dog.age) + Column( + modifier = Modifier + .animateContentSize( + animationSpec = spring( + dampingRatio = Spring.DampingRatioMediumBouncy, + stiffness = Spring.StiffnessLow + ) + ) + .background(color = color) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp) + ) { + DogIcon(dog.imageResourceId) + DogInformation(dog.name, dog.age) + Spacer(Modifier.weight(1f)) + DogItemButton( + expanded = expanded, + onClick = { expanded = !expanded } + ) + } + if(expanded){ + DogHobby(dogHobby = dog.hobbies) + } + } } } @@ -91,7 +158,9 @@ fun DogIcon(@DrawableRes dogIcon: Int, modifier: Modifier = Modifier) { Image( modifier = modifier .size(64.dp) - .padding(8.dp), + .padding(8.dp) + .clip(RoundedCornerShape(50.dp)), + contentScale = ContentScale.Crop, painter = painterResource(dogIcon), /* * Content Description is not needed here - image is decorative, and setting a null content @@ -113,10 +182,51 @@ fun DogInformation(@StringRes dogName: Int, dogAge: Int, modifier: Modifier = Mo Column { Text( text = stringResource(dogName), + style = MaterialTheme.typography.h2, modifier = modifier.padding(top = 8.dp) ) Text( - text = stringResource(R.string.years_old, dogAge) + text = stringResource(R.string.years_old, dogAge), + style = MaterialTheme.typography.body1, + + ) + } +} + +@Composable +private fun DogItemButton( + expanded: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + IconButton(onClick = onClick) { + Icon( + imageVector = if(expanded) Icons.Filled.ExpandLess + else Icons.Filled.ExpandMore, + tint = MaterialTheme.colors.secondary, + contentDescription = stringResource(R.string.expand_button_content_description) + ) + } +} + + +@Composable +fun DogHobby(@StringRes dogHobby: Int, modifier: Modifier = Modifier) { + Column( + modifier = modifier.padding( + start = 16.dp, + top = 8.dp, + bottom = 16.dp, + end = 16.dp + ) + ) { + Text( + text = stringResource(R.string.about), + style = MaterialTheme.typography.h3, + ) + Text( + text = stringResource(dogHobby), + style = MaterialTheme.typography.body1, ) } } @@ -131,3 +241,11 @@ fun WoofPreview() { WoofApp() } } + +@Preview +@Composable +fun DarkThemePreview() { + WoofTheme(darkTheme = true) { + WoofApp() + } +} \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Color.kt b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Color.kt index 2bb986719..7ae56f734 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Color.kt +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Color.kt @@ -21,3 +21,16 @@ val Purple200 = Color(0xFFBB86FC) val Purple500 = Color(0xFF6200EE) val Purple700 = Color(0xFF3700B3) val Teal200 = Color(0xFF03DAC5) + +//Light Theme +val Grey50 = Color(0xFFF8F9FA) +val Grey900 = Color(0xFF202124) +val Grey700 = Color(0xFF5F6368) +val Green50 = Color(0xFFE6F4EA) +val Green100 = Color(0xFFCEEAD6) + +//Dark Theme +val White = Color(0xFFFFFFFF) +val Grey100 = Color(0xFFF1F3F4) +val Cyan900 = Color(0xFF007B83) +val Cyan700 = Color(0xFF129EAF) \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Shape.kt b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Shape.kt index a04343591..63168dd29 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Shape.kt +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Shape.kt @@ -21,6 +21,6 @@ import androidx.compose.ui.unit.dp val Shapes = Shapes( small = RoundedCornerShape(4.dp), - medium = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(16.dp), large = RoundedCornerShape(0.dp) -) +) \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Theme.kt b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Theme.kt index dd94c3134..30fcc55ba 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Theme.kt +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Theme.kt @@ -22,24 +22,21 @@ import androidx.compose.material.lightColors import androidx.compose.runtime.Composable private val DarkColorPalette = darkColors( - primary = Purple200, - primaryVariant = Purple700, - secondary = Teal200 + background = Cyan900, + surface = Cyan700, + onSurface = White, + primary = Grey900, + onPrimary = White, + secondary = Grey100 ) private val LightColorPalette = lightColors( - primary = Purple500, - primaryVariant = Purple700, - secondary = Teal200 - - /* Other default colors to override - background = Color.White, - surface = Color.White, - onPrimary = Color.White, - onSecondary = Color.Black, - onBackground = Color.Black, - onSurface = Color.Black, - */ + background = Green100, + surface = Green50, + onSurface = Grey900, + primary = Grey50, + onPrimary = Grey900, + secondary = Grey700 ) @Composable diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Type.kt b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Type.kt index 4ad3e60c2..5eba39b36 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Type.kt +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/java/com/example/woofcodelab/ui/theme/Type.kt @@ -17,27 +17,43 @@ package com.example.woofcodelab.ui.theme import androidx.compose.material.Typography import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp +import com.example.woofcodelab.R // Set of Material typography styles to start with + +val AbrilFatface = FontFamily( + Font(R.font.abril_fatface_regular) +) + +val Montserrat = FontFamily( + Font(R.font.montserrat_regular), + Font(R.font.montserrat_bold, FontWeight.Bold) +) + val Typography = Typography( - body1 = TextStyle( - fontFamily = FontFamily.Default, + h1 = TextStyle( + fontFamily = AbrilFatface, fontWeight = FontWeight.Normal, - fontSize = 16.sp - ) - /* Other default text styles to override - button = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.W500, + fontSize = 30.sp + ), + h2 = TextStyle( + fontFamily = Montserrat, + fontWeight = FontWeight.Bold, + fontSize = 20.sp + ), + h3 = TextStyle( + fontFamily = Montserrat, + fontWeight = FontWeight.Bold, fontSize = 14.sp ), - caption = TextStyle( - fontFamily = FontFamily.Default, + body1 = TextStyle( + fontFamily = Montserrat, fontWeight = FontWeight.Normal, - fontSize = 12.sp + fontSize = 14.sp ) - */ ) + diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/abril_fatface_regular.ttf b/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/abril_fatface_regular.ttf new file mode 100644 index 000000000..a29171148 Binary files /dev/null and b/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/abril_fatface_regular.ttf differ diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/montserrat_bold.ttf b/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/montserrat_bold.ttf new file mode 100644 index 000000000..efddc8341 Binary files /dev/null and b/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/montserrat_bold.ttf differ diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/montserrat_regular.ttf b/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/montserrat_regular.ttf new file mode 100644 index 000000000..aa9033a80 Binary files /dev/null and b/Unit3/Pathway3/WoofCodelab/app/src/main/res/font/montserrat_regular.ttf differ diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/res/values-night/themes.xml b/Unit3/Pathway3/WoofCodelab/app/src/main/res/values-night/themes.xml new file mode 100644 index 000000000..09d184553 --- /dev/null +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/res/values-night/themes.xml @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/colors.xml b/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/colors.xml index de3366f83..0f5357354 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/colors.xml +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/colors.xml @@ -22,4 +22,7 @@ #FF018786 #FF000000 #FFFFFFFF + + #FFF8F9FA + #FF202124 \ No newline at end of file diff --git a/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/themes.xml b/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/themes.xml index 4ef11abc2..6c84eb06e 100644 --- a/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/themes.xml +++ b/Unit3/Pathway3/WoofCodelab/app/src/main/res/values/themes.xml @@ -17,6 +17,7 @@ \ No newline at end of file diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/build.gradle b/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/build.gradle index 8feecee4a..90ed6bd00 100644 --- a/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/build.gradle +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/build.gradle @@ -47,6 +47,8 @@ android { dependencies { + implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" implementation 'androidx.activity:activity-compose:1.5.1' diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/src/main/java/com/example/dessertclicker/MainActivity.kt b/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/src/main/java/com/example/dessertclicker/MainActivity.kt index e267a3264..7b741c5e7 100644 --- a/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/src/main/java/com/example/dessertclicker/MainActivity.kt +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/app/src/main/java/com/example/dessertclicker/MainActivity.kt @@ -19,6 +19,7 @@ import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.os.Bundle +import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -26,26 +27,15 @@ import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.material.Scaffold -import androidx.compose.material.Text -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.MaterialTheme +import androidx.compose.foundation.layout.* +import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -58,19 +48,51 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat.startActivity import com.example.dessertclicker.data.Datasource.dessertList -import com.example.dessertclicker.ui.theme.DessertClickerTheme import com.example.dessertclicker.model.Dessert +import com.example.dessertclicker.ui.theme.DessertClickerTheme -class MainActivity : ComponentActivity() { +private const val TAG = "MainActivity" +class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Log.d(TAG, "onCreate Called") setContent { DessertClickerTheme { DessertClickerApp(desserts = dessertList) } } } + + override fun onStart() { + super.onStart() + Log.d(TAG, "onStart Called") + } + + override fun onResume() { + super.onResume() + Log.d(TAG, "onResume Called") + } + + override fun onRestart() { + super.onRestart() + Log.d(TAG, "onRestart Called") + } + + override fun onPause() { + super.onPause() + Log.d(TAG, "onPause Called") + } + + override fun onStop() { + super.onStop() + Log.d(TAG, "onStop Called") + } + + override fun onDestroy() { + super.onDestroy() + Log.d(TAG, "onDestroy Called") + } } /** @@ -127,15 +149,15 @@ private fun DessertClickerApp( desserts: List ) { - var revenue by remember { mutableStateOf(0) } - var dessertsSold by remember { mutableStateOf(0) } + var revenue by rememberSaveable { mutableStateOf(0) } + var dessertsSold by rememberSaveable { mutableStateOf(0) } - val currentDessertIndex by remember { mutableStateOf(0) } + val currentDessertIndex by rememberSaveable { mutableStateOf(0) } - var currentDessertPrice by remember { + var currentDessertPrice by rememberSaveable { mutableStateOf(desserts[currentDessertIndex].price) } - var currentDessertImageId by remember { + var currentDessertImageId by rememberSaveable { mutableStateOf(desserts[currentDessertIndex].imageId) } diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/build.gradle b/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/build.gradle index 1deeec4e4..17e03dbcb 100644 --- a/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/build.gradle +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-dessert-clicker/build.gradle @@ -2,6 +2,7 @@ buildscript { ext { compose_version = '1.2.0' compose_compiler_version = '1.2.0' + lifecycle_version = '2.5.1' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/build.gradle b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/build.gradle index 5079735d4..b11f26b78 100644 --- a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/build.gradle +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/build.gradle @@ -63,6 +63,8 @@ android { dependencies { + implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1" + implementation 'androidx.activity:activity-compose:1.5.1' implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.material:material:$compose_version" diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameScreen.kt b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameScreen.kt index 0e14ff1ee..81b387907 100644 --- a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameScreen.kt +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameScreen.kt @@ -34,6 +34,8 @@ import androidx.compose.material.OutlinedTextField import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -42,12 +44,17 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel import com.example.android.unscramble.R import com.example.android.unscramble.ui.theme.UnscrambleTheme @Composable -fun GameScreen(modifier: Modifier = Modifier) { +fun GameScreen( + gameViewModel: GameViewModel = viewModel(), + modifier: Modifier = Modifier +) { + val gameUiState by gameViewModel.uiState.collectAsState() Column( modifier = modifier .verticalScroll(rememberScrollState()) @@ -55,8 +62,18 @@ fun GameScreen(modifier: Modifier = Modifier) { verticalArrangement = Arrangement.spacedBy(8.dp) ) { - GameStatus() - GameLayout() + GameStatus( + wordCount = gameUiState.currentWordCount, + score = gameUiState.score + ) + GameLayout( + currentScrambledWord = gameUiState.currentScrambledWord, + isGuessWrong = gameUiState.isGuessedWordWrong, + userGuess = gameViewModel.userGuess, + onUserGuessChanged = { gameViewModel.updateUserGuess(it) }, + onKeyboardDone = { gameViewModel.checkUserGuess() }, + ) + Row( modifier = modifier .fillMaxWidth() @@ -64,7 +81,7 @@ fun GameScreen(modifier: Modifier = Modifier) { horizontalArrangement = Arrangement.SpaceAround ) { OutlinedButton( - onClick = { }, + onClick = { gameViewModel.skipWord() }, modifier = Modifier .weight(1f) .padding(end = 8.dp) @@ -77,16 +94,26 @@ fun GameScreen(modifier: Modifier = Modifier) { .fillMaxWidth() .weight(1f) .padding(start = 8.dp), - onClick = { } + onClick = { gameViewModel.checkUserGuess() } ) { Text(stringResource(R.string.submit)) } } + if (gameUiState.isGameOver) { + FinalScoreDialog( + score = gameUiState.score, + onPlayAgain = { gameViewModel.resetGame() } + ) + } } } @Composable -fun GameStatus(modifier: Modifier = Modifier) { +fun GameStatus( + wordCount: Int, + score: Int, + modifier: Modifier = Modifier +) { Row( modifier = modifier .fillMaxWidth() @@ -94,27 +121,34 @@ fun GameStatus(modifier: Modifier = Modifier) { .size(48.dp), ) { Text( - text = stringResource(R.string.word_count, 0), + text = stringResource(R.string.word_count, wordCount), fontSize = 18.sp, ) Text( modifier = Modifier .fillMaxWidth() .wrapContentWidth(Alignment.End), - text = stringResource(R.string.score, 0), + text = stringResource(R.string.score, score), fontSize = 18.sp, ) } } + @Composable -fun GameLayout(modifier: Modifier = Modifier) { +fun GameLayout( + currentScrambledWord: String, + isGuessWrong: Boolean, + userGuess: String, + onUserGuessChanged: (String) -> Unit, + onKeyboardDone: () -> Unit, + modifier: Modifier = Modifier) { Column( verticalArrangement = Arrangement.spacedBy(24.dp), ) { Text( - text = "scrambleun", + text = currentScrambledWord, fontSize = 45.sp, modifier = modifier.align(Alignment.CenterHorizontally) ) @@ -124,17 +158,23 @@ fun GameLayout(modifier: Modifier = Modifier) { modifier = Modifier.align(Alignment.CenterHorizontally) ) OutlinedTextField( - value = "", + value = userGuess, singleLine = true, modifier = Modifier.fillMaxWidth(), - onValueChange = { }, - label = { Text(stringResource(R.string.enter_your_word)) }, - isError = false, + onValueChange = onUserGuessChanged, + label = { + if (isGuessWrong) { + Text(stringResource(R.string.wrong_guess)) + } else { + Text(stringResource(R.string.enter_your_word)) + } + }, + isError = isGuessWrong, keyboardOptions = KeyboardOptions.Default.copy( imeAction = ImeAction.Done ), keyboardActions = KeyboardActions( - onDone = { } + onDone = { onKeyboardDone() } ), ) } @@ -145,6 +185,7 @@ fun GameLayout(modifier: Modifier = Modifier) { */ @Composable private fun FinalScoreDialog( + score: Int, onPlayAgain: () -> Unit, modifier: Modifier = Modifier ) { @@ -157,7 +198,7 @@ private fun FinalScoreDialog( // onCloseRequest. }, title = { Text(stringResource(R.string.congratulations)) }, - text = { Text(stringResource(R.string.you_scored, 0)) }, + text = { Text(stringResource(R.string.you_scored, score)) }, modifier = modifier, dismissButton = { TextButton( diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameUiState.kt b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameUiState.kt new file mode 100644 index 000000000..998627ff8 --- /dev/null +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameUiState.kt @@ -0,0 +1,9 @@ +package com.example.android.unscramble.ui + +data class GameUiState( + val currentScrambledWord: String = "", + val currentWordCount: Int = 1, + val score: Int = 0, + val isGuessedWordWrong: Boolean = false, + val isGameOver: Boolean = false +) \ No newline at end of file diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameViewModel.kt b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameViewModel.kt new file mode 100644 index 000000000..ae9c3b044 --- /dev/null +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/main/java/com/example/android/unscramble/ui/GameViewModel.kt @@ -0,0 +1,110 @@ +package com.example.android.unscramble.ui + +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import com.example.android.unscramble.data.MAX_NO_OF_WORDS +import com.example.android.unscramble.data.SCORE_INCREASE +import com.example.android.unscramble.data.allWords +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update + +class GameViewModel : ViewModel() { + + // Game UI state + private val _uiState = MutableStateFlow(GameUiState()) + // Backing property to avoid state updates from other classes + val uiState: StateFlow = _uiState.asStateFlow() + + private lateinit var currentWord: String + + // Set of words used in the game + private var usedWords: MutableSet = mutableSetOf() + + var userGuess by mutableStateOf("") + + init { + resetGame() + } + + private fun pickRandomWordAndShuffle(): String { + // Continue picking up a new random word until you get one that hasn't been used before + currentWord = allWords.random() + if (usedWords.contains(currentWord)) { + return pickRandomWordAndShuffle() + } else { + usedWords.add(currentWord) + return shuffleCurrentWord(currentWord) + } + } + + private fun shuffleCurrentWord(word: String): String { + val tempWord = word.toCharArray() + // Scramble the word + tempWord.shuffle() + while (String(tempWord).equals(word)) { + tempWord.shuffle() + } + return String(tempWord) + } + + fun resetGame() { + usedWords.clear() + _uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle()) + } + + + fun updateUserGuess(guessedWord: String){ + userGuess = guessedWord + } + + + fun checkUserGuess() { + if (userGuess.equals(currentWord, ignoreCase = true)) { + // User's guess is correct, increase the score + // and call updateGameState() to prepare the game for next round + val updatedScore = _uiState.value.score.plus(SCORE_INCREASE) + updateGameState(updatedScore) + updateUserGuess("") + } else { + // User's guess is wrong, show an error + _uiState.update { currentState -> + currentState.copy(isGuessedWordWrong = true) + } + } + } + + private fun updateGameState(updatedScore: Int) { + + if (usedWords.size == MAX_NO_OF_WORDS){ + //Last round in the game, update isGameOver to true, don't pick a new word + _uiState.update { currentState -> + currentState.copy( + isGuessedWordWrong = false, + score = updatedScore, + currentWordCount = currentState.currentWordCount, + isGameOver = true + ) + } + } else { + // Normal round in the game + _uiState.update { currentState -> + currentState.copy( + isGuessedWordWrong = false, + currentWordCount = currentState.currentWordCount.inc(), + currentScrambledWord = pickRandomWordAndShuffle(), + score = updatedScore + ) + } + } + } + + fun skipWord() { + updateGameState(_uiState.value.score) + // Reset user guess + updateUserGuess("") + } +} diff --git a/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/test/java/com/example/android/unscramble/ui/test/GameViewModelTest.kt b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/test/java/com/example/android/unscramble/ui/test/GameViewModelTest.kt new file mode 100644 index 000000000..417846157 --- /dev/null +++ b/Unit4/Pathway1/basic-android-kotlin-compose-training-unscramble/app/src/test/java/com/example/android/unscramble/ui/test/GameViewModelTest.kt @@ -0,0 +1,111 @@ +package com.example.android.unscramble.ui.test + +import com.example.android.unscramble.data.MAX_NO_OF_WORDS +import com.example.android.unscramble.data.SCORE_INCREASE +import com.example.android.unscramble.data.getUnscrambledWord +import com.example.android.unscramble.ui.GameViewModel +import junit.framework.TestCase.* +import org.junit.Assert.assertNotEquals +import org.junit.Test + +class GameViewModelTest { + + private val viewModel = GameViewModel() + + + /* + 참고: thingUnderTest_TriggerOfTest_ResultOfTest 형식을 사용하여 테스트 함수 이름을 지정합니다. + thingUnderTest = gameViewModel + TriggerOfTest = CorrectWordGuessed + ResultOfTest = ScoreUpdatedAndErrorFlagUnset + */ + @Test + fun gameViewModel_CorrectWordGuessed_ScoreUpdatedAndErrorFlagUnset(){ + var currentGameUiState = viewModel.uiState.value + val correctPlayerWord = getUnscrambledWord(currentGameUiState.currentScrambledWord) + + viewModel.updateUserGuess(correctPlayerWord) + viewModel.checkUserGuess() + + currentGameUiState = viewModel.uiState.value + + assertFalse(currentGameUiState.isGuessedWordWrong) + assertEquals(SCORE_AFTER_FIRST_CORRECT_ANSWER, currentGameUiState.score) + } + + companion object { + private const val SCORE_AFTER_FIRST_CORRECT_ANSWER = SCORE_INCREASE + + } + + + @Test + fun gameViewModel_IncorrectGuess_ErrorFlagSet() { + // Given an incorrect word as input + val incorrectPlayerWord = "and" + + viewModel.updateUserGuess(incorrectPlayerWord) + viewModel.checkUserGuess() + + val currentGameUiState = viewModel.uiState.value + // Assert that score is unchanged + assertEquals(0, currentGameUiState.score) + // Assert that checkUserGuess() method updates isGuessedWordWrong correctly + assertTrue(currentGameUiState.isGuessedWordWrong) + } + + + @Test + fun gameViewModel_Initialization_FirstWordLoaded() { + val gameUiState = viewModel.uiState.value + val unScrambledWord = getUnscrambledWord(gameUiState.currentScrambledWord) + + // Assert that current word is scrambled. + assertNotEquals(unScrambledWord, gameUiState.currentScrambledWord) + // Assert that current word count is set to 1. + assertTrue(gameUiState.currentWordCount == 1) + // Assert that initially the score is 0. + assertTrue(gameUiState.score == 0) + // Assert that the wrong word guessed is false. + assertFalse(gameUiState.isGuessedWordWrong) + // Assert that game is not over. + assertFalse(gameUiState.isGameOver) + } + + @Test + fun gameViewModel_AllWordsGuessed_UiStateUpdatedCorrectly() { + var expectedScore = 0 + var currentGameUiState = viewModel.uiState.value + var correctPlayerWord = getUnscrambledWord(currentGameUiState.currentScrambledWord) + repeat(MAX_NO_OF_WORDS){ + expectedScore += SCORE_INCREASE + viewModel.updateUserGuess(correctPlayerWord) + viewModel.checkUserGuess() + currentGameUiState = viewModel.uiState.value + correctPlayerWord = getUnscrambledWord(currentGameUiState.currentScrambledWord) + // Assert that after each correct answer, score is updated correctly. + assertEquals(expectedScore, currentGameUiState.score) + } + // Assert that after all questions are answered, the current word count is up-to-date. + assertEquals(MAX_NO_OF_WORDS, currentGameUiState.currentWordCount) + // Assert that after 10 questions are answered, the game is over. + assertTrue(currentGameUiState.isGameOver) + } + + @Test + fun gameViewModel_WordSkipped_ScoreUnchangedAndWordCountIncreased() { + var currentGameUiState = viewModel.uiState.value + val correctPlayerWord = getUnscrambledWord(currentGameUiState.currentScrambledWord) + viewModel.updateUserGuess(correctPlayerWord) + viewModel.checkUserGuess() + + currentGameUiState = viewModel.uiState.value + val lastWordCount = currentGameUiState.currentWordCount + viewModel.skipWord() + currentGameUiState = viewModel.uiState.value + // Assert that score remains unchanged after word is skipped. + assertEquals(SCORE_AFTER_FIRST_CORRECT_ANSWER, currentGameUiState.score) + // Assert that word count is increased by 1 after word is skipped. + assertEquals(lastWordCount + 1, currentGameUiState.currentWordCount) + } +} \ No newline at end of file diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/build.gradle b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/build.gradle index 170740623..0b8d4c0ef 100644 --- a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/build.gradle +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/build.gradle @@ -59,9 +59,11 @@ dependencies { implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1' implementation "androidx.navigation:navigation-compose:2.5.0" + implementation 'androidx.navigation:navigation-testing:2.5.3' testImplementation 'junit:junit:4.13.2' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" androidTestImplementation 'androidx.test.ext:junit:1.1.3' debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.0' } diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/ComposeRuleExtensions.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/ComposeRuleExtensions.kt new file mode 100644 index 000000000..0c8441fda --- /dev/null +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/ComposeRuleExtensions.kt @@ -0,0 +1,12 @@ +package com.example.cupcake.test + +import androidx.activity.ComponentActivity +import androidx.annotation.StringRes +import androidx.compose.ui.test.SemanticsNodeInteraction +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.rules.ActivityScenarioRule + +fun AndroidComposeTestRule, A>.onNodeWithStringId( + @StringRes id: Int +): SemanticsNodeInteraction = onNodeWithText(activity.getString(id)) diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/CupcakeOrderScreenTest.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/CupcakeOrderScreenTest.kt new file mode 100644 index 000000000..296b0370d --- /dev/null +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/CupcakeOrderScreenTest.kt @@ -0,0 +1,106 @@ +package com.example.cupcake.test + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsEnabled +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.example.cupcake.R +import com.example.cupcake.data.DataSource +import com.example.cupcake.data.OrderUiState +import com.example.cupcake.ui.OrderSummaryScreen +import com.example.cupcake.ui.SelectOptionScreen +import com.example.cupcake.ui.StartOrderScreen +import org.junit.Rule +import org.junit.Test + +class CupcakeOrderScreenTest { + + @get:Rule + val composeTestRule = createAndroidComposeRule() + + private val fakeOrderUiState = OrderUiState( + quantity = 6, + flavor = "Vanilla", + date = "Wed Jul 21", + price = "$100", + pickupOptions = listOf() + ) + + @Test + fun startOrderScreen_verifyContent() { + + composeTestRule.setContent { + StartOrderScreen( + quantityOptions = DataSource.quantityOptions, + onNextButtonClicked = {} + ) + } + + DataSource.quantityOptions.forEach { + composeTestRule.onNodeWithStringId(it.first).assertIsDisplayed() + } + } + + + @Test + fun selectOptionScreen_verifyContent() { + val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango") + val subTotal = "$100" + + composeTestRule.setContent { + SelectOptionScreen(subtotal = subTotal, options = flavours) + } + + flavours.forEach { flavour -> + composeTestRule.onNodeWithText(flavour).assertIsDisplayed() + } + + composeTestRule.onNodeWithText( + composeTestRule.activity.getString( + R.string.subtotal_price, + subTotal + ) + ).assertIsDisplayed() + + composeTestRule.onNodeWithStringId(R.string.next).assertIsNotEnabled() + } + + + @Test + fun selectOptionScreen_optionSelected_NextButtonEnabled() { + val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango") + val subTotal = "$100" + + composeTestRule.setContent { + SelectOptionScreen(subtotal = subTotal, options = flavours) + } + + composeTestRule.onNodeWithText("Vanilla").performClick() + composeTestRule.onNodeWithStringId(R.string.next).assertIsEnabled() + } + + + @Test + fun summaryScreen_verifyContentDisplay() { + // When Summary Screen is loaded + composeTestRule.setContent { + OrderSummaryScreen( + orderUiState = fakeOrderUiState, + onCancelButtonClicked = {}, + onSendButtonClicked = { _, _ -> }, + ) + } + + composeTestRule.onNodeWithText(fakeOrderUiState.flavor).assertIsDisplayed() + composeTestRule.onNodeWithText(fakeOrderUiState.date).assertIsDisplayed() + composeTestRule.onNodeWithText( + composeTestRule.activity.getString( + R.string.subtotal_price, + fakeOrderUiState.price + ) + ) + } +} \ No newline at end of file diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/CupcakeScreenNavigationTest.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/CupcakeScreenNavigationTest.kt new file mode 100644 index 000000000..a9542ddc1 --- /dev/null +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/CupcakeScreenNavigationTest.kt @@ -0,0 +1,144 @@ +package com.example.cupcake.test + +import android.icu.util.Calendar +import androidx.activity.ComponentActivity +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.navigation.compose.ComposeNavigator +import androidx.navigation.testing.TestNavHostController +import com.example.cupcake.CupcakeApp +import com.example.cupcake.CupcakeScreen +import com.example.cupcake.R +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import java.text.SimpleDateFormat +import java.util.Locale + +class CupcakeScreenNavigationTest { + + @get:Rule + val composeTestRule = createAndroidComposeRule() + + private lateinit var navController: TestNavHostController + + @Before + fun setupCupcakeNavHost() { + composeTestRule.setContent { + navController = TestNavHostController(LocalContext.current).apply { + navigatorProvider.addNavigator(ComposeNavigator()) + } + CupcakeApp(navController = navController) + } + } + + @Test + fun cupcakeNavHost_verifyStartDestination() { + navController.assertCurrentRouteName(CupcakeScreen.Start.name) + } + + @Test + fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() { + val backText = composeTestRule.activity.getString(R.string.back_button) + composeTestRule.onNodeWithContentDescription(backText).assertDoesNotExist() + } + + @Test + fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() { + composeTestRule.onNodeWithStringId(R.string.one_cupcake) + .performClick() + navController.assertCurrentRouteName(CupcakeScreen.Flavor.name) + } + + @Test + fun cupcakeNavHost_clickNextOnFlavorScreen_navigatesToPickupScreen() { + navigateToFlavorScreen() + composeTestRule.onNodeWithStringId(R.string.next) + .performClick() + navController.assertCurrentRouteName(CupcakeScreen.Pickup.name) + } + + @Test + fun cupcakeNavHost_clickBackOnFlavorScreen_navigatesToStartOrderScreen() { + navigateToFlavorScreen() + performNavigateUp() + navController.assertCurrentRouteName(CupcakeScreen.Start.name) + } + + @Test + fun cupcakeNavHost_clickCancelOnFlavorScreen_navigatesToStartOrderScreen() { + navigateToFlavorScreen() + composeTestRule.onNodeWithStringId(R.string.cancel) + .performClick() + navController.assertCurrentRouteName(CupcakeScreen.Start.name) + } + + @Test + fun cupcakeNavHost_clickNextOnPickupScreen_navigatesToSummaryScreen() { + navigateToPickupScreen() + composeTestRule.onNodeWithText(getFormattedDate()) + .performClick() + composeTestRule.onNodeWithStringId(R.string.next) + .performClick() + navController.assertCurrentRouteName(CupcakeScreen.Summary.name) + } + + @Test + fun cupcakeNavHost_clickBackOnPickupScreen_navigatesToFlavorScreen() { + navigateToPickupScreen() + performNavigateUp() + navController.assertCurrentRouteName(CupcakeScreen.Flavor.name) + } + + @Test + fun cupcakeNavHost_clickCancelOnPickupScreen_navigatesToStartOrderScreen() { + navigateToPickupScreen() + composeTestRule.onNodeWithStringId(R.string.cancel) + .performClick() + navController.assertCurrentRouteName(CupcakeScreen.Start.name) + } + + @Test + fun cupcakeNavHost_clickCancelOnSummaryScreen_navigatesToStartOrderScreen() { + navigateToSummaryScreen() + composeTestRule.onNodeWithStringId(R.string.cancel) + .performClick() + navController.assertCurrentRouteName(CupcakeScreen.Start.name) + } + + private fun navigateToFlavorScreen() { + composeTestRule.onNodeWithStringId(R.string.one_cupcake) + .performClick() + composeTestRule.onNodeWithStringId(R.string.chocolate) + .performClick() + } + + private fun navigateToPickupScreen() { + navigateToFlavorScreen() + composeTestRule.onNodeWithStringId(R.string.next) + .performClick() + } + + private fun navigateToSummaryScreen() { + navigateToPickupScreen() + composeTestRule.onNodeWithText(getFormattedDate()) + .performClick() + composeTestRule.onNodeWithStringId(R.string.next) + .performClick() + } + + private fun performNavigateUp() { + val backText = composeTestRule.activity.getString(R.string.back_button) + composeTestRule.onNodeWithContentDescription(backText).performClick() + } + + private fun getFormattedDate(): String { + val calendar = Calendar.getInstance() + calendar.add(java.util.Calendar.DATE, 1) + val formatter = SimpleDateFormat("E MMM d", Locale.getDefault()) + return formatter.format(calendar.time) + } +} \ No newline at end of file diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/ScreenAssertions.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/ScreenAssertions.kt new file mode 100644 index 000000000..701b5bd2e --- /dev/null +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/androidTest/java/com/example/cupcake/test/ScreenAssertions.kt @@ -0,0 +1,8 @@ +package com.example.cupcake.test + +import androidx.navigation.NavController +import org.junit.Assert + +fun NavController.assertCurrentRouteName(expectedRouteName: String) { + Assert.assertEquals(expectedRouteName, currentBackStackEntry?.destination?.route) +} \ No newline at end of file diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/CupcakeScreen.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/CupcakeScreen.kt index 89dd4e885..110603de0 100644 --- a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/CupcakeScreen.kt +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/CupcakeScreen.kt @@ -15,6 +15,10 @@ */ package com.example.cupcake +import android.content.Context +import android.content.Intent +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.padding import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.Scaffold @@ -26,21 +30,38 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.lifecycle.viewmodel.compose.viewModel -import com.example.cupcake.ui.OrderViewModel +import androidx.navigation.NavController +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import com.example.cupcake.data.DataSource.flavors +import com.example.cupcake.data.DataSource.quantityOptions +import com.example.cupcake.ui.* + +enum class CupcakeScreen(@StringRes val title: Int){ + Start(title = R.string.app_name), + Flavor(title = R.string.choose_flavor), + Pickup(title = R.string.choose_pickup_date), + Summary(title = R.string.order_summary) +} /** * Composable that displays the topBar and displays back button if back navigation is possible. */ @Composable fun CupcakeAppBar( + currentScreen: CupcakeScreen, canNavigateBack: Boolean, navigateUp: () -> Unit, modifier: Modifier = Modifier ) { TopAppBar( - title = { Text(stringResource(id = R.string.app_name)) }, + title = { Text(stringResource(id = currentScreen.title)) }, modifier = modifier, navigationIcon = { if (canNavigateBack) { @@ -56,24 +77,125 @@ fun CupcakeAppBar( } @Composable -fun CupcakeApp(modifier: Modifier = Modifier, viewModel: OrderViewModel = viewModel()){ - // TODO: Create NavController - - // TODO: Get current back stack entry +fun CupcakeApp( + modifier: Modifier = Modifier, + viewModel: OrderViewModel = viewModel(), + navController: NavHostController = rememberNavController() +){ +// val navController = rememberNavController() - // TODO: Get the name of the current screen + val backStackEntry by navController.currentBackStackEntryAsState() + val currentScreen = CupcakeScreen.valueOf( + backStackEntry?.destination?.route ?: CupcakeScreen.Start.name + ) Scaffold( topBar = { CupcakeAppBar( - canNavigateBack = false, - navigateUp = { /* TODO: implement back navigation */ } + currentScreen = currentScreen, + canNavigateBack = navController.previousBackStackEntry != null, + navigateUp = { navController.navigateUp() } ) } ) { innerPadding -> val uiState by viewModel.uiState.collectAsState() + NavHost( + navController = navController, + startDestination = CupcakeScreen.Start.name, + modifier = modifier.padding(innerPadding) + ){ + composable(route = CupcakeScreen.Start.name){ + StartOrderScreen( + quantityOptions = quantityOptions, + onNextButtonClicked = { + viewModel.setQuantity(it) + navController.navigate(CupcakeScreen.Flavor.name) + } + ) + } + composable(route = CupcakeScreen.Flavor.name){ + val context = LocalContext.current + SelectOptionScreen( + subtotal = uiState.price, + onNextButtonClicked = { + navController.navigate(CupcakeScreen.Pickup.name) + }, + onCancelButtonClicked = { + cancelOrderAndNavigateToStart(viewModel, navController) + }, + options = flavors.map { id -> stringResource(id = id)}, + onSelectionChanged = { viewModel.setFlavor(it) } + ) + } + composable(route = CupcakeScreen.Pickup.name){ + SelectOptionScreen( + subtotal = uiState.price, + onNextButtonClicked = { + navController.navigate(CupcakeScreen.Summary.name) + }, + onCancelButtonClicked = { + cancelOrderAndNavigateToStart(viewModel, navController) + }, + options = uiState.pickupOptions, + onSelectionChanged = { viewModel.setDate(it) } + ) + } + composable(route = CupcakeScreen.Summary.name){ + val context = LocalContext.current + OrderSummaryScreen( + orderUiState = uiState, + onCancelButtonClicked = { + cancelOrderAndNavigateToStart(viewModel, navController) + }, + onSendButtonClicked = { subject: String, summary: String -> + shareOrder(context = context, subject = subject, summary = summary) + } + ) + } + + } + } +} - // TODO: add NavHost + +private fun cancelOrderAndNavigateToStart( + viewModel: OrderViewModel, + navController: NavController +) { + viewModel.resetOrder() + navController.popBackStack(CupcakeScreen.Start.name, inclusive = false) +} + + +private fun shareOrder(context: Context, subject: String, summary: String) { + val intent = Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_SUBJECT, subject) + putExtra(Intent.EXTRA_TEXT, summary) } + + context.startActivity( + Intent.createChooser( + intent, + context.getString(R.string.new_cupcake_order) + ) + ) + } + + + + + + + + + + + + + + + + diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt index 16e7eea89..6ee786408 100644 --- a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt @@ -50,8 +50,8 @@ fun SelectOptionScreen( subtotal: String, options: List, onSelectionChanged: (String) -> Unit = {}, - // TODO: add onCancelButtonClicked - // TODO: add onNextButtonClicked + onCancelButtonClicked: () -> Unit = {}, + onNextButtonClicked: () -> Unit = {}, modifier: Modifier = Modifier ){ var selectedValue by rememberSaveable { mutableStateOf("") } @@ -89,14 +89,14 @@ fun SelectOptionScreen( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp) ){ - OutlinedButton(modifier = Modifier.weight(1f), onClick = { /* TODO: handle cancel button */ }) { + OutlinedButton(modifier = Modifier.weight(1f), onClick = onCancelButtonClicked) { Text(stringResource(R.string.cancel)) } Button( modifier = Modifier.weight(1f), // the button is enabled when the user makes a selection enabled = selectedValue.isNotEmpty(), - onClick = { /* TODO: handle next button */ } + onClick = onNextButtonClicked ) { Text(stringResource(R.string.next)) } diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt index 0f41e7925..c7ee7e2a4 100644 --- a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt @@ -45,7 +45,7 @@ import com.example.cupcake.data.DataSource.quantityOptions @Composable fun StartOrderScreen( quantityOptions: List>, - // TODO: add onNextButtonClicked + onNextButtonClicked: (Int) -> Unit, modifier: Modifier = Modifier ){ Column( @@ -65,7 +65,7 @@ fun StartOrderScreen( quantityOptions.forEach { item -> SelectQuantityButton( labelResourceId = item.first, - onClick = { /* TODO: handle next button */ } + onClick = { onNextButtonClicked(item.second) } ) } } @@ -92,5 +92,8 @@ fun SelectQuantityButton( @Preview @Composable fun StartOrderPreview(){ - StartOrderScreen(quantityOptions = quantityOptions) + StartOrderScreen( + quantityOptions = quantityOptions, + onNextButtonClicked = {} + ) } diff --git a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt index ff63a972e..5d4c07342 100644 --- a/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt +++ b/Unit4/Pathway2/basic-android-kotlin-compose-training-cupcake/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt @@ -44,8 +44,8 @@ import com.example.cupcake.ui.components.FormattedPriceLabel @Composable fun OrderSummaryScreen( orderUiState: OrderUiState, - // TODO: add onCancelButtonClicked - // TODO: add onSendButtonClicked + onCancelButtonClicked: () -> Unit, + onSendButtonClicked: (String, String) -> Unit, modifier: Modifier = Modifier ){ val resources = LocalContext.current.resources @@ -90,13 +90,13 @@ fun OrderSummaryScreen( ) Button( modifier = Modifier.fillMaxWidth(), - onClick = { /* TODO: handle send button */ } + onClick = { onSendButtonClicked(newOrder, orderSummary) } ) { Text(stringResource(R.string.send)) } OutlinedButton( modifier = Modifier.fillMaxWidth(), - onClick = { /* TODO: handle cancel button */ } + onClick = onCancelButtonClicked ) { Text(stringResource(R.string.cancel)) } @@ -108,5 +108,9 @@ fun OrderSummaryScreen( fun OrderSummaryPreview(){ OrderSummaryScreen( orderUiState = OrderUiState(0, "Test", "Test", "$300.00"), + onCancelButtonClicked = {}, + onSendButtonClicked = { subject: String, summary: String -> + + } ) }