diff --git a/imagesource01/Vector.svg b/imagesource01/Vector.svg new file mode 100644 index 0000000..dab8b02 --- /dev/null +++ b/imagesource01/Vector.svg @@ -0,0 +1,3 @@ + + + diff --git a/imagesource01/angry.svg b/imagesource01/angry.svg new file mode 100644 index 0000000..45ef4e5 --- /dev/null +++ b/imagesource01/angry.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/imagesource01/happy.svg b/imagesource01/happy.svg new file mode 100644 index 0000000..915d24f --- /dev/null +++ b/imagesource01/happy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/imagesource01/idle.svg b/imagesource01/idle.svg new file mode 100644 index 0000000..b987bad --- /dev/null +++ b/imagesource01/idle.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/imagesource01/sad.svg b/imagesource01/sad.svg new file mode 100644 index 0000000..b65626a --- /dev/null +++ b/imagesource01/sad.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/imagesource01/soso.svg b/imagesource01/soso.svg new file mode 100644 index 0000000..84ee0c6 --- /dev/null +++ b/imagesource01/soso.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/imagesource02/BagCircle.svg b/imagesource02/BagCircle.svg new file mode 100644 index 0000000..290621d --- /dev/null +++ b/imagesource02/BagCircle.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/imagesource02/BagSimple.svg b/imagesource02/BagSimple.svg new file mode 100644 index 0000000..5d727dd --- /dev/null +++ b/imagesource02/BagSimple.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/imagesource02/HeartStraight.svg b/imagesource02/HeartStraight.svg new file mode 100644 index 0000000..57f8307 --- /dev/null +++ b/imagesource02/HeartStraight.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/imagesource02/HouseSimple.svg b/imagesource02/HouseSimple.svg new file mode 100644 index 0000000..607f831 --- /dev/null +++ b/imagesource02/HouseSimple.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/imagesource02/ListMagnifyingGlass.svg b/imagesource02/ListMagnifyingGlass.svg new file mode 100644 index 0000000..2f022a9 --- /dev/null +++ b/imagesource02/ListMagnifyingGlass.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/imagesource02/User.svg b/imagesource02/User.svg new file mode 100644 index 0000000..00ee1d1 --- /dev/null +++ b/imagesource02/User.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/imagesource02/banner.png b/imagesource02/banner.png new file mode 100644 index 0000000..c42645a Binary files /dev/null and b/imagesource02/banner.png differ diff --git a/imagesource02/blackman.png b/imagesource02/blackman.png new file mode 100644 index 0000000..4063f05 Binary files /dev/null and b/imagesource02/blackman.png differ diff --git a/imagesource02/shoes.png b/imagesource02/shoes.png new file mode 100644 index 0000000..d03c7b2 Binary files /dev/null and b/imagesource02/shoes.png differ diff --git a/imagesource02/skrrr.png b/imagesource02/skrrr.png new file mode 100644 index 0000000..08e17ff Binary files /dev/null and b/imagesource02/skrrr.png differ diff --git a/imagesource02/sujin.png b/imagesource02/sujin.png new file mode 100644 index 0000000..fc8e353 Binary files /dev/null and b/imagesource02/sujin.png differ diff --git a/imgsource/btm_color_selector.xml b/imgsource/btm_color_selector.xml new file mode 100644 index 0000000..3ecf8a7 --- /dev/null +++ b/imgsource/btm_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/week00/first.py b/week00/first.py new file mode 100644 index 0000000..0a2cbac --- /dev/null +++ b/week00/first.py @@ -0,0 +1 @@ +print("Hello UMC") \ No newline at end of file diff --git a/week01/.gitignore b/week01/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/week01/.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/week01/.idea/.gitignore b/week01/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/week01/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/week01/.idea/.name b/week01/.idea/.name new file mode 100644 index 0000000..b3405b3 --- /dev/null +++ b/week01/.idea/.name @@ -0,0 +1 @@ +My Application \ No newline at end of file diff --git a/week01/.idea/AndroidProjectSystem.xml b/week01/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/week01/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/week01/.idea/compiler.xml b/week01/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/week01/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week01/.idea/deploymentTargetSelector.xml b/week01/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/week01/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/week01/.idea/deviceManager.xml b/week01/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/week01/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week01/.idea/gradle.xml b/week01/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/week01/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week01/.idea/inspectionProfiles/Project_Default.xml b/week01/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/week01/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/week01/.idea/migrations.xml b/week01/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/week01/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/week01/.idea/misc.xml b/week01/.idea/misc.xml new file mode 100644 index 0000000..74dd639 --- /dev/null +++ b/week01/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/week01/.idea/runConfigurations.xml b/week01/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/week01/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week01/.idea/vcs.xml b/week01/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/week01/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week01/app/.gitignore b/week01/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/week01/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/week01/app/build.gradle.kts b/week01/app/build.gradle.kts new file mode 100644 index 0000000..9d5aed4 --- /dev/null +++ b/week01/app/build.gradle.kts @@ -0,0 +1,61 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "com.example.myapplication" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.myapplication" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.appcompat) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) +} \ No newline at end of file diff --git a/week01/app/proguard-rules.pro b/week01/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/week01/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/week01/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt b/week01/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..e9283cf --- /dev/null +++ b/week01/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.myapplication + +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.myapplication", appContext.packageName) + } +} \ No newline at end of file diff --git a/week01/app/src/main/AndroidManifest.xml b/week01/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9451a84 --- /dev/null +++ b/week01/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week01/app/src/main/java/com/example/myapplication/MainActivity.kt b/week01/app/src/main/java/com/example/myapplication/MainActivity.kt new file mode 100644 index 0000000..03b79c9 --- /dev/null +++ b/week01/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -0,0 +1,74 @@ +package com.example.myapplication + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import com.example.myapplication.ui.theme.MyApplicationTheme +import android.widget.TextView +import android.widget.ImageView +import android.widget.Toast +import android.graphics.Color +import androidx.appcompat.app.AppCompatActivity +import kotlin.collections.MutableMap + + +class MainActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContentView(R.layout.simple) + + // 메세지 문자열 배열 + var texts = arrayOf( + "좋은 일 있었어?", + "뭔데 그리 들뜬건지 궁금하네~", + "오늘 수업만 듣고 온 거야?", + "그럴 땐 그냥 자는게 나아. 자장가 불러줄까?", + "누가 화나게 했어? 내가 혼내줄게") + + // MutableMap 선언 + val imagetextMap = mutableMapOf() + + val idleImage = findViewById(R.id.idleImage) + val happyImage = findViewById(R.id.happyImage) + val sosoImage = findViewById(R.id.sosoImage) + val sadImage = findViewById(R.id.sadImage) + val angryImage = findViewById(R.id.angryImage) + + // 매핑 + imagetextMap[idleImage] = findViewById(R.id.idleText) + imagetextMap[happyImage] = findViewById(R.id.happyText) + imagetextMap[sosoImage] = findViewById(R.id.sosoText) + imagetextMap[sadImage] = findViewById(R.id.sadText) + imagetextMap[angryImage] = findViewById(R.id.angryText) + + //클릭 메서드 + for ((imageView, textView) in imagetextMap) { + imageView.setOnClickListener { + // 모든 텍스트 색상 초기화 + imagetextMap.values.forEach { it.setTextColor(getColor(R.color.black)) } + + when (imageView) { //switch-case + idleImage -> {textView.setTextColor(Color.YELLOW) + Toast.makeText(this, texts[0], Toast.LENGTH_SHORT).show()} + happyImage -> {textView.setTextColor(Color.CYAN) + Toast.makeText(this, texts[1], Toast.LENGTH_SHORT).show()} + sosoImage -> {textView.setTextColor(Color.BLUE) + Toast.makeText(this, texts[2], Toast.LENGTH_SHORT).show()} + sadImage -> {textView.setTextColor(Color.GREEN) + Toast.makeText(this, texts[3], Toast.LENGTH_SHORT).show()} + angryImage -> {textView.setTextColor(Color.RED) + Toast.makeText(this, texts[4], Toast.LENGTH_SHORT).show()} + } + } + + + } + + } +} +//뷰 바인딩 \ No newline at end of file diff --git a/week01/app/src/main/java/com/example/myapplication/ui/theme/Color.kt b/week01/app/src/main/java/com/example/myapplication/ui/theme/Color.kt new file mode 100644 index 0000000..1ce3e5d --- /dev/null +++ b/week01/app/src/main/java/com/example/myapplication/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.myapplication.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/week01/app/src/main/java/com/example/myapplication/ui/theme/Theme.kt b/week01/app/src/main/java/com/example/myapplication/ui/theme/Theme.kt new file mode 100644 index 0000000..174f73f --- /dev/null +++ b/week01/app/src/main/java/com/example/myapplication/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.myapplication.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun MyApplicationTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/week01/app/src/main/java/com/example/myapplication/ui/theme/Type.kt b/week01/app/src/main/java/com/example/myapplication/ui/theme/Type.kt new file mode 100644 index 0000000..64846a0 --- /dev/null +++ b/week01/app/src/main/java/com/example/myapplication/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.myapplication.ui.theme + +import androidx.compose.material3.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( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/week01/app/src/main/res/drawable/angry.xml b/week01/app/src/main/res/drawable/angry.xml new file mode 100644 index 0000000..c6b43a2 --- /dev/null +++ b/week01/app/src/main/res/drawable/angry.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/week01/app/src/main/res/drawable/happy.xml b/week01/app/src/main/res/drawable/happy.xml new file mode 100644 index 0000000..5c4b19d --- /dev/null +++ b/week01/app/src/main/res/drawable/happy.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/week01/app/src/main/res/drawable/ic_launcher_background.xml b/week01/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/week01/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week01/app/src/main/res/drawable/ic_launcher_foreground.xml b/week01/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/week01/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/week01/app/src/main/res/drawable/idle.xml b/week01/app/src/main/res/drawable/idle.xml new file mode 100644 index 0000000..72176da --- /dev/null +++ b/week01/app/src/main/res/drawable/idle.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/week01/app/src/main/res/drawable/sad.xml b/week01/app/src/main/res/drawable/sad.xml new file mode 100644 index 0000000..fe91f33 --- /dev/null +++ b/week01/app/src/main/res/drawable/sad.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/week01/app/src/main/res/drawable/soso.xml b/week01/app/src/main/res/drawable/soso.xml new file mode 100644 index 0000000..9b02528 --- /dev/null +++ b/week01/app/src/main/res/drawable/soso.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/week01/app/src/main/res/drawable/vector.xml b/week01/app/src/main/res/drawable/vector.xml new file mode 100644 index 0000000..af62026 --- /dev/null +++ b/week01/app/src/main/res/drawable/vector.xml @@ -0,0 +1,9 @@ + + + diff --git a/week01/app/src/main/res/layout/simple.xml b/week01/app/src/main/res/layout/simple.xml new file mode 100644 index 0000000..ceafdbc --- /dev/null +++ b/week01/app/src/main/res/layout/simple.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week01/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week01/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/week01/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/week01/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week01/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/week01/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/week01/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week01/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/week01/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/week01/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week01/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/week01/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/week01/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week01/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/week01/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/week01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/week01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/week01/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week01/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/week01/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/week01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/week01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/week01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/week01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/week01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/week01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/week01/app/src/main/res/values/colors.xml b/week01/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/week01/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/week01/app/src/main/res/values/margins.xml b/week01/app/src/main/res/values/margins.xml new file mode 100644 index 0000000..921eb23 --- /dev/null +++ b/week01/app/src/main/res/values/margins.xml @@ -0,0 +1,6 @@ + + + 5dp + 20dp + 30dp + \ No newline at end of file diff --git a/week01/app/src/main/res/values/strings.xml b/week01/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..3de1a39 --- /dev/null +++ b/week01/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + My Application + \ No newline at end of file diff --git a/week01/app/src/main/res/values/themes.xml b/week01/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e48770a --- /dev/null +++ b/week01/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + + + + + \ No newline at end of file diff --git a/week02copy/app/src/main/res/xml/backup_rules.xml b/week02copy/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..4df9255 --- /dev/null +++ b/week02copy/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/week02copy/app/src/main/res/xml/data_extraction_rules.xml b/week02copy/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/week02copy/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week02copy/app/src/test/java/com/example/yourapplication/ExampleUnitTest.kt b/week02copy/app/src/test/java/com/example/yourapplication/ExampleUnitTest.kt new file mode 100644 index 0000000..996540d --- /dev/null +++ b/week02copy/app/src/test/java/com/example/yourapplication/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.yourapplication + +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/week02copy/build.gradle.kts b/week02copy/build.gradle.kts new file mode 100644 index 0000000..ebd2403 --- /dev/null +++ b/week02copy/build.gradle.kts @@ -0,0 +1,12 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} + +buildscript { + dependencies { + classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.9.4") + } +} diff --git a/week02copy/gradle.properties b/week02copy/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/week02copy/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. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-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/week02copy/gradle/libs.versions.toml b/week02copy/gradle/libs.versions.toml new file mode 100644 index 0000000..5332b17 --- /dev/null +++ b/week02copy/gradle/libs.versions.toml @@ -0,0 +1,34 @@ +[versions] +agp = "8.13.0" +kotlin = "2.0.21" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2024.09.00" +constraintlayout = "2.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } + diff --git a/week02copy/gradle/wrapper/gradle-wrapper.jar b/week02copy/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/week02copy/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week02copy/gradle/wrapper/gradle-wrapper.properties b/week02copy/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..62d4f33 --- /dev/null +++ b/week02copy/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Sep 25 03:26:39 KST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week02copy/gradlew b/week02copy/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/week02copy/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/week02copy/gradlew.bat b/week02copy/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/week02copy/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/week02copy/settings.gradle.kts b/week02copy/settings.gradle.kts new file mode 100644 index 0000000..646f39c --- /dev/null +++ b/week02copy/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "Your Application" +include(":app") + \ No newline at end of file diff --git a/week03/.gitignore b/week03/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/week03/.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/week03/.idea/.name b/week03/.idea/.name new file mode 100644 index 0000000..997352e --- /dev/null +++ b/week03/.idea/.name @@ -0,0 +1 @@ +FLO \ No newline at end of file diff --git a/week03/.idea/AndroidProjectSystem.xml b/week03/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/week03/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/week03/.idea/compiler.xml b/week03/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/week03/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week03/.idea/deploymentTargetSelector.xml b/week03/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/week03/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/week03/.idea/deviceManager.xml b/week03/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/week03/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week03/.idea/gradle.xml b/week03/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/week03/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week03/.idea/inspectionProfiles/Project_Default.xml b/week03/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/week03/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/week03/.idea/migrations.xml b/week03/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/week03/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/week03/.idea/misc.xml b/week03/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/week03/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/week03/.idea/runConfigurations.xml b/week03/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/week03/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week03/.idea/vcs.xml b/week03/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/week03/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week03/app/.gitignore b/week03/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/week03/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/week03/app/build.gradle.kts b/week03/app/build.gradle.kts new file mode 100644 index 0000000..890ced2 --- /dev/null +++ b/week03/app/build.gradle.kts @@ -0,0 +1,67 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "com.example.flo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.flo" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("androidx.fragment:fragment:1.8.9") + implementation("com.google.android.material:material:1.13.0") + implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("com.tbuonomo:dotsindicator:5.1.0") + +} \ No newline at end of file diff --git a/week03/app/proguard-rules.pro b/week03/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/week03/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/week03/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt b/week03/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..6dfac89 --- /dev/null +++ b/week03/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.flo + +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.flo", appContext.packageName) + } +} \ No newline at end of file diff --git a/week03/app/src/main/AndroidManifest.xml b/week03/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e215dad --- /dev/null +++ b/week03/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/AlbumFragment.kt b/week03/app/src/main/java/com/example/flo/AlbumFragment.kt new file mode 100644 index 0000000..2093dc7 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/AlbumFragment.kt @@ -0,0 +1,61 @@ +package com.example.flo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.flo.databinding.FragmentAlbumBinding +import com.google.android.material.tabs.TabLayoutMediator + + +class AlbumFragment : Fragment() { + lateinit var binding: FragmentAlbumBinding + + private val information = arrayListOf("수록곡", "상세정보", "영상") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentAlbumBinding.inflate(inflater, container, false) + + //홈프래그먼트에서 번들로 전달한 값을 받음 + val albumName = arguments?.getString("album") + val singerName = arguments?.getString("singer") + binding.albumMusicTitleTv.text = albumName + binding.albumSingerNameTv.text = singerName + + //홈프래그먼트로의 화면전환 + binding.albumBackIv.setOnClickListener { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commitAllowingStateLoss() + } + + //디테일 프래그먼트로의 데이터 전달(왜안되는거야 왜 로그캣에 널이 뜨는데) + val detailFragment = DetailFragment() + + val bundle = Bundle().apply { + putString("singerName", binding.albumSingerNameTv.toString()) + putString("albumTitle", binding.albumMusicTitleTv.toString()) + } + detailFragment.arguments = bundle + + val albumAdapter = AlbumVPAdapter(this) + binding.albumContentVp.adapter = albumAdapter + TabLayoutMediator(binding.albumContentTb, binding.albumContentVp) { + tap, position -> + tap.text = information[position] + + }.attach() + + return binding.root + + + } + + + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/AlbumVPAdapter.kt b/week03/app/src/main/java/com/example/flo/AlbumVPAdapter.kt new file mode 100644 index 0000000..dd1d45f --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/AlbumVPAdapter.kt @@ -0,0 +1,23 @@ +package com.example.flo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class AlbumVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment){ + + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + return when(position) { + 0 -> SongFragment() + 1 -> { + DetailFragment() + } + else -> VideoFragment() + } + + } + + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/BannerFragment.kt b/week03/app/src/main/java/com/example/flo/BannerFragment.kt new file mode 100644 index 0000000..4e4d79c --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/BannerFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentBannerBinding + +//인자를 넣어서 새로운 배너 프래그먼트 추가 +class BannerFragment(val imgRes : Int) : Fragment() { + lateinit var binding : FragmentBannerBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBannerBinding.inflate(inflater, container, false) + + binding.bannerImageIv.setImageResource(imgRes) + + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/BannerVPAdapter.kt b/week03/app/src/main/java/com/example/flo/BannerVPAdapter.kt new file mode 100644 index 0000000..7bc9fce --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/BannerVPAdapter.kt @@ -0,0 +1,23 @@ +package com.example.flo + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class BannerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + + private val fragmentlist : ArrayList = ArrayList() + + override fun getItemCount(): Int { // 데이터를 몇개를 전달할 것이냐 + return fragmentlist.size + } + + override fun createFragment(position: Int): Fragment = fragmentlist[position] + + //리스트에 추가하는 함수 + fun addFragment(fragment: Fragment) { + fragmentlist.add(fragment) + notifyItemInserted(fragmentlist.size - 1) //뷰페이저에게 새로운 값이 추가가 됐다고 알림 + } + + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/DetailFragment.kt b/week03/app/src/main/java/com/example/flo/DetailFragment.kt new file mode 100644 index 0000000..ef5f123 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/DetailFragment.kt @@ -0,0 +1,38 @@ +package com.example.flo + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentDetailBinding +import android.util.Log + + +class DetailFragment : Fragment() { + lateinit var binding : FragmentDetailBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailBinding.inflate(inflater, container, false) + + //앨범프래그먼트에서 전달한 데이터를 받음 + val singerName = arguments?.getString("singerName") + val albumTitle = arguments?.getString("albumTitle") + + Log.d("DetailFragment", "받은 가수 이름: $singerName") + Log.d("DetailFragment", "받은 앨범 제목: $albumTitle") + + + binding.singerNameTv.text = singerName + binding.albumNameTv.text = albumTitle + + + return binding.root + } + + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/HomeFragment.kt b/week03/app/src/main/java/com/example/flo/HomeFragment.kt new file mode 100644 index 0000000..0b70a02 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/HomeFragment.kt @@ -0,0 +1,54 @@ +package com.example.flo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.viewpager2.widget.ViewPager2 +import com.example.flo.databinding.FragmentHomeBinding + + +class HomeFragment : Fragment() { + lateinit var binding: FragmentHomeBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentHomeBinding.inflate(inflater, container, false) + + binding.homeAlbumImgIv1.setOnClickListener { + //앨범 프래그먼트로 데이터 전달 + val bundle = Bundle() + bundle.putString("album", binding.lilac.text.toString()) + bundle.putString("singer", binding.iu.text.toString()) + + val albumFragment = AlbumFragment() + albumFragment.arguments = bundle + + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, albumFragment) + .commitAllowingStateLoss() + + + } + + val bannerAdapter = BannerVPAdapter(this) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + binding.homeBannerVp.adapter = bannerAdapter + + //뷰 페이지가 좌우로 스크롤 될수 있도록 지정 + binding.homeBannerVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + return binding.root + } + + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/LockerFragment.kt b/week03/app/src/main/java/com/example/flo/LockerFragment.kt new file mode 100644 index 0000000..1885156 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/LockerFragment.kt @@ -0,0 +1,35 @@ +package com.example.flo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.flo.databinding.FragmentLockerBinding +import com.google.android.material.tabs.TabLayoutMediator +import com.example.flo.SavedsongFragment +import com.example.flo.SongfileFragment +import com.example.flo.SavedalbumFragment + +class LockerFragment : Fragment() { + lateinit var binding: FragmentLockerBinding + + private val information = arrayListOf("저장한 곡", "음악피일", "저장앨범") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLockerBinding.inflate(inflater, container, false) + + val lockerAdapter = LockerVPAdapter(this) + binding.lockerContentVp.adapter = lockerAdapter + TabLayoutMediator(binding.lockerContentTb, binding.lockerContentVp) { + tap, position -> + tap.text = information[position] + + }.attach() + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/LockerVPAdapter.kt b/week03/app/src/main/java/com/example/flo/LockerVPAdapter.kt new file mode 100644 index 0000000..0379cd4 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/LockerVPAdapter.kt @@ -0,0 +1,29 @@ +package com.example.flo + +import android.util.Log +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.example.flo.SavedsongFragment +import com.example.flo.SongfileFragment +import com.example.flo.SavedalbumFragment + + +class LockerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + Log.d("FragmentCheck2", "createfrag") + return when(position) { + 0 -> { + SavedsongFragment() + } + 1 -> { + SongfileFragment() + } + else -> {SavedalbumFragment()} + } + + } + + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/LookFragment.kt b/week03/app/src/main/java/com/example/flo/LookFragment.kt new file mode 100644 index 0000000..27f8d29 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/LookFragment.kt @@ -0,0 +1,22 @@ +package com.example.flo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.flo.databinding.FragmentLookBinding + + +class LookFragment : Fragment() { + lateinit var binding: FragmentLookBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLookBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/MainActivity.kt b/week03/app/src/main/java/com/example/flo/MainActivity.kt new file mode 100644 index 0000000..b34b066 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/MainActivity.kt @@ -0,0 +1,88 @@ +package com.example.flo + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.example.flo.ui.theme.FLOTheme +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.databinding.ActivityMainBinding +import android.widget.Toast +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + val song = Song(binding.mainMiniplayerTitleTv.text.toString(), + binding.mainMiniplayerSingerTv.text.toString()) + + + binding.mainPlayerCl.setOnClickListener { + //finish() //현재 액티비티 종료 + val intent = Intent(this, SongActivity::class.java) + intent.putExtra("title", song.title) + intent.putExtra("singer", song.singer) + startActivity(intent) + //finish() //현재 액티비티 종료 + } + + if (intent.hasExtra("albumname")) { + Toast.makeText(this, intent.getStringExtra("albumname"), Toast.LENGTH_SHORT).show() + } + + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + + //BottomNavigationView를 눌렀을 때 Fragment 변경하기 + binding.mainBnv.setOnItemSelectedListener { item -> + when (item.itemId) { + + //매인 화면 + R.id.homeFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + true + } + + //둘러보기 화면 + R.id.lookFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LookFragment()) + .commit() + true + } + + //검색 화면 + R.id.searchFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, SearchFragment()) + .commit() + true + } + + //보관함 화면 + R.id.lockerFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LockerFragment()) + .commit() + true + } + else -> false + } + } + } +} diff --git a/week03/app/src/main/java/com/example/flo/SavedalbumFragment.kt b/week03/app/src/main/java/com/example/flo/SavedalbumFragment.kt new file mode 100644 index 0000000..613ad84 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/SavedalbumFragment.kt @@ -0,0 +1,26 @@ +package com.example.flo +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSavedalbumBinding +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.util.Log + +class SavedalbumFragment : Fragment() { + + lateinit var binding : FragmentSavedalbumBinding + + override fun onCreateView( + + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedalbumBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SavedAlbumFragment onCreateView") + + return binding.root + } + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/SavedsongFragment.kt b/week03/app/src/main/java/com/example/flo/SavedsongFragment.kt new file mode 100644 index 0000000..be8caa4 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/SavedsongFragment.kt @@ -0,0 +1,27 @@ +package com.example.flo + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSavedalbumBinding +import com.example.flo.databinding.FragmentSavedsongBinding +import android.util.Log + +class SavedsongFragment : Fragment() { + + lateinit var binding : FragmentSavedsongBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedsongBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SavedsongFragment onCreateView") + + + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/SearchFragment.kt b/week03/app/src/main/java/com/example/flo/SearchFragment.kt new file mode 100644 index 0000000..f708caa --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/SearchFragment.kt @@ -0,0 +1,22 @@ +package com.example.flo + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.flo.databinding.FragmentSearchBinding + + +class SearchFragment : Fragment() { + lateinit var binding: FragmentSearchBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSearchBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/Song.kt b/week03/app/src/main/java/com/example/flo/Song.kt new file mode 100644 index 0000000..b47a99c --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/Song.kt @@ -0,0 +1,8 @@ +package com.example.flo + +import android.R + +data class Song( + val title: String = "", + val singer: String = "" +) diff --git a/week03/app/src/main/java/com/example/flo/SongActivity.kt b/week03/app/src/main/java/com/example/flo/SongActivity.kt new file mode 100644 index 0000000..f2313e7 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/SongActivity.kt @@ -0,0 +1,81 @@ +package com.example.flo + +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.databinding.ActivityMainBinding +import com.example.flo.databinding.ActivitySongBinding +import android.content.Intent +import android.widget.ImageView +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.PorterDuff + + +class SongActivity : AppCompatActivity() { + private lateinit var binding: ActivitySongBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySongBinding.inflate(layoutInflater) + + //재생, 일시정지 + var isPlay = false + binding.songMiniplayerIv.setOnClickListener { + if (!isPlay) { + binding.songMiniplayerIv.setImageResource(R.drawable.btn_miniplay_pause) + isPlay = true + } else { + binding.songMiniplayerIv.setImageResource(R.drawable.btn_miniplayer_play) + isPlay = false + } + + } + + //반복재생 + var isRoop = false + binding.songRepeatIv.setOnClickListener { + if (!isRoop) { + binding.songRepeatIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + isRoop = true + } else { + binding.songRepeatIv.clearColorFilter() + isRoop = false + } + } + + //전체재생(랜덤재생인듯?) + var willPlayAll = false + + binding.songRandomIv.setOnClickListener { + if (!willPlayAll) { + binding.songRandomIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + willPlayAll = true + } else { + binding.songRandomIv.clearColorFilter() + willPlayAll = false + } + } + + setContentView(binding.root) + + if (intent.hasExtra("title") && intent.hasExtra("singer")) { + binding.songMusicTitleTv.text = intent.getStringExtra("title") + binding.songSingerNameTv.text = intent.getStringExtra("singer") + } + + val bundle = Bundle() + bundle.putString("albumname", binding.songMusicTitleTv.text.toString()) + + binding.songDownIb.setOnClickListener { + //finish() + val intent = Intent(this, MainActivity::class.java) + intent.putExtras(bundle) + startActivity(intent) + finish() + + } + + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/SongFragment.kt b/week03/app/src/main/java/com/example/flo/SongFragment.kt new file mode 100644 index 0000000..a29178d --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/SongFragment.kt @@ -0,0 +1,39 @@ +package com.example.flo + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSongBinding +import android.widget.ImageView + + +class SongFragment : Fragment() { + lateinit var binding : FragmentSongBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongBinding.inflate(inflater, container, false) + + + //내 취향 믹스 미션 + var isON = false + + binding.songMixoffTg.setOnClickListener { + if (!isON) { + binding.songMixoffTg.setImageResource(R.drawable.btn_toggle_on) + isON = true + } else { + binding.songMixoffTg.setImageResource(R.drawable.btn_toggle_off) + isON = false + } + + } + + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/SongfileFragment.kt b/week03/app/src/main/java/com/example/flo/SongfileFragment.kt new file mode 100644 index 0000000..29f34ed --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/SongfileFragment.kt @@ -0,0 +1,26 @@ +package com.example.flo +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSavedsongBinding +import com.example.flo.databinding.FragmentSongfileBinding +import android.util.Log + + +class SongfileFragment : Fragment() { + + lateinit var binding : FragmentSongfileBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongfileBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SongfileFragment onCreateView") + + return binding.root + } +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/VideoFragment.kt b/week03/app/src/main/java/com/example/flo/VideoFragment.kt new file mode 100644 index 0000000..2b25210 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/VideoFragment.kt @@ -0,0 +1,23 @@ +package com.example.flo +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentVideoBinding + + +class VideoFragment : Fragment() { + lateinit var binding : FragmentVideoBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentVideoBinding.inflate(inflater, container, false) + + return binding.root + } + +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/ui/theme/Color.kt b/week03/app/src/main/java/com/example/flo/ui/theme/Color.kt new file mode 100644 index 0000000..6b31678 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.flo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/ui/theme/Theme.kt b/week03/app/src/main/java/com/example/flo/ui/theme/Theme.kt new file mode 100644 index 0000000..cc69550 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.flo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FLOTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/week03/app/src/main/java/com/example/flo/ui/theme/Type.kt b/week03/app/src/main/java/com/example/flo/ui/theme/Type.kt new file mode 100644 index 0000000..9a198f8 --- /dev/null +++ b/week03/app/src/main/java/com/example/flo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.flo.ui.theme + +import androidx.compose.material3.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( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/week03/app/src/main/res/drawable/btn_actionbar_instagram.png b/week03/app/src/main/res/drawable/btn_actionbar_instagram.png new file mode 100644 index 0000000..90bc027 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_actionbar_instagram.png differ diff --git a/week03/app/src/main/res/drawable/btn_arrow_black.png b/week03/app/src/main/res/drawable/btn_arrow_black.png new file mode 100644 index 0000000..cc38ca8 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_arrow_black.png differ diff --git a/week03/app/src/main/res/drawable/btn_color_selector.xml b/week03/app/src/main/res/drawable/btn_color_selector.xml new file mode 100644 index 0000000..3ecf8a7 --- /dev/null +++ b/week03/app/src/main/res/drawable/btn_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/drawable/btn_main_arrow_more.png b/week03/app/src/main/res/drawable/btn_main_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_main_arrow_more.png differ diff --git a/week03/app/src/main/res/drawable/btn_main_mike.png b/week03/app/src/main/res/drawable/btn_main_mike.png new file mode 100644 index 0000000..9bddec6 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_main_mike.png differ diff --git a/week03/app/src/main/res/drawable/btn_main_setting.png b/week03/app/src/main/res/drawable/btn_main_setting.png new file mode 100644 index 0000000..7a8d5d6 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_main_setting.png differ diff --git a/week03/app/src/main/res/drawable/btn_main_ticket.png b/week03/app/src/main/res/drawable/btn_main_ticket.png new file mode 100644 index 0000000..52b6d64 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_main_ticket.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplay_mvpause.png b/week03/app/src/main/res/drawable/btn_miniplay_mvpause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplay_mvpause.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplay_mvplay.png b/week03/app/src/main/res/drawable/btn_miniplay_mvplay.png new file mode 100644 index 0000000..d118677 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplay_mvplay.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplay_pause.png b/week03/app/src/main/res/drawable/btn_miniplay_pause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplay_pause.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplayer_go_list.png b/week03/app/src/main/res/drawable/btn_miniplayer_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplayer_go_list.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplayer_next.png b/week03/app/src/main/res/drawable/btn_miniplayer_next.png new file mode 100644 index 0000000..3aedba3 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplayer_next.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplayer_play.png b/week03/app/src/main/res/drawable/btn_miniplayer_play.png new file mode 100644 index 0000000..f619072 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplayer_play.png differ diff --git a/week03/app/src/main/res/drawable/btn_miniplayer_previous.png b/week03/app/src/main/res/drawable/btn_miniplayer_previous.png new file mode 100644 index 0000000..d0bf1f6 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_miniplayer_previous.png differ diff --git a/week03/app/src/main/res/drawable/btn_panel_play_large.png b/week03/app/src/main/res/drawable/btn_panel_play_large.png new file mode 100644 index 0000000..4ac7103 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_panel_play_large.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_eq_off.png b/week03/app/src/main/res/drawable/btn_player_eq_off.png new file mode 100644 index 0000000..f23d9c6 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_eq_off.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_go_list.png b/week03/app/src/main/res/drawable/btn_player_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_go_list.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_more.png b/week03/app/src/main/res/drawable/btn_player_more.png new file mode 100644 index 0000000..a8ad9e6 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_more.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_play.png b/week03/app/src/main/res/drawable/btn_player_play.png new file mode 100644 index 0000000..f6c3201 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_play.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_related.png b/week03/app/src/main/res/drawable/btn_player_related.png new file mode 100644 index 0000000..9026fe5 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_related.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_setting.png b/week03/app/src/main/res/drawable/btn_player_setting.png new file mode 100644 index 0000000..0df8f69 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_setting.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_unlike_off.png b/week03/app/src/main/res/drawable/btn_player_unlike_off.png new file mode 100644 index 0000000..b539504 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_unlike_off.png differ diff --git a/week03/app/src/main/res/drawable/btn_player_unlike_on.png b/week03/app/src/main/res/drawable/btn_player_unlike_on.png new file mode 100644 index 0000000..45a43ca Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_player_unlike_on.png differ diff --git a/week03/app/src/main/res/drawable/btn_playlist_select_off.png b/week03/app/src/main/res/drawable/btn_playlist_select_off.png new file mode 100644 index 0000000..62ef45c Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_playlist_select_off.png differ diff --git a/week03/app/src/main/res/drawable/btn_playlist_select_on.png b/week03/app/src/main/res/drawable/btn_playlist_select_on.png new file mode 100644 index 0000000..2d3b6af Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_playlist_select_on.png differ diff --git a/week03/app/src/main/res/drawable/btn_toggle_off.png b/week03/app/src/main/res/drawable/btn_toggle_off.png new file mode 100644 index 0000000..983360d Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_toggle_off.png differ diff --git a/week03/app/src/main/res/drawable/btn_toggle_on.png b/week03/app/src/main/res/drawable/btn_toggle_on.png new file mode 100644 index 0000000..fb609f4 Binary files /dev/null and b/week03/app/src/main/res/drawable/btn_toggle_on.png differ diff --git a/week03/app/src/main/res/drawable/discovery_banner_aos.jpg b/week03/app/src/main/res/drawable/discovery_banner_aos.jpg new file mode 100644 index 0000000..c905515 Binary files /dev/null and b/week03/app/src/main/res/drawable/discovery_banner_aos.jpg differ diff --git a/week03/app/src/main/res/drawable/ic_bottom_home_no_select.png b/week03/app/src/main/res/drawable/ic_bottom_home_no_select.png new file mode 100644 index 0000000..69a8ab6 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_bottom_home_no_select.png differ diff --git a/week03/app/src/main/res/drawable/ic_bottom_locker_no_select.png b/week03/app/src/main/res/drawable/ic_bottom_locker_no_select.png new file mode 100644 index 0000000..a67dec3 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_bottom_locker_no_select.png differ diff --git a/week03/app/src/main/res/drawable/ic_bottom_look_no_select.png b/week03/app/src/main/res/drawable/ic_bottom_look_no_select.png new file mode 100644 index 0000000..6c2f4f0 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_bottom_look_no_select.png differ diff --git a/week03/app/src/main/res/drawable/ic_bottom_search_no_select.png b/week03/app/src/main/res/drawable/ic_bottom_search_no_select.png new file mode 100644 index 0000000..a77b8c5 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_bottom_search_no_select.png differ diff --git a/week03/app/src/main/res/drawable/ic_launcher_background.xml b/week03/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/week03/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week03/app/src/main/res/drawable/ic_launcher_foreground.xml b/week03/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/week03/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/drawable/ic_main_facebook.png b/week03/app/src/main/res/drawable/ic_main_facebook.png new file mode 100644 index 0000000..83e9732 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_main_facebook.png differ diff --git a/week03/app/src/main/res/drawable/ic_main_instagram.png b/week03/app/src/main/res/drawable/ic_main_instagram.png new file mode 100644 index 0000000..398ce61 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_main_instagram.png differ diff --git a/week03/app/src/main/res/drawable/ic_main_twitter.png b/week03/app/src/main/res/drawable/ic_main_twitter.png new file mode 100644 index 0000000..6ddc68e Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_main_twitter.png differ diff --git a/week03/app/src/main/res/drawable/ic_main_youtube.png b/week03/app/src/main/res/drawable/ic_main_youtube.png new file mode 100644 index 0000000..0c4ec93 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_main_youtube.png differ diff --git a/week03/app/src/main/res/drawable/ic_my_like_off.png b/week03/app/src/main/res/drawable/ic_my_like_off.png new file mode 100644 index 0000000..c06e139 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_my_like_off.png differ diff --git a/week03/app/src/main/res/drawable/ic_my_like_on.png b/week03/app/src/main/res/drawable/ic_my_like_on.png new file mode 100644 index 0000000..22577c0 Binary files /dev/null and b/week03/app/src/main/res/drawable/ic_my_like_on.png differ diff --git a/week03/app/src/main/res/drawable/icon_browse_arrow_right.png b/week03/app/src/main/res/drawable/icon_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week03/app/src/main/res/drawable/icon_browse_arrow_right.png differ diff --git a/week03/app/src/main/res/drawable/img_album_exp.png b/week03/app/src/main/res/drawable/img_album_exp.png new file mode 100644 index 0000000..6e3f38a Binary files /dev/null and b/week03/app/src/main/res/drawable/img_album_exp.png differ diff --git a/week03/app/src/main/res/drawable/img_album_exp2.png b/week03/app/src/main/res/drawable/img_album_exp2.png new file mode 100644 index 0000000..28ea3ee Binary files /dev/null and b/week03/app/src/main/res/drawable/img_album_exp2.png differ diff --git a/week03/app/src/main/res/drawable/img_album_lp.png b/week03/app/src/main/res/drawable/img_album_lp.png new file mode 100644 index 0000000..29fb1b4 Binary files /dev/null and b/week03/app/src/main/res/drawable/img_album_lp.png differ diff --git a/week03/app/src/main/res/drawable/img_first_album_default.png b/week03/app/src/main/res/drawable/img_first_album_default.png new file mode 100644 index 0000000..926d34f Binary files /dev/null and b/week03/app/src/main/res/drawable/img_first_album_default.png differ diff --git a/week03/app/src/main/res/drawable/img_home_viewpager_exp.png b/week03/app/src/main/res/drawable/img_home_viewpager_exp.png new file mode 100644 index 0000000..da78032 Binary files /dev/null and b/week03/app/src/main/res/drawable/img_home_viewpager_exp.png differ diff --git a/week03/app/src/main/res/drawable/img_home_viewpager_exp2.png b/week03/app/src/main/res/drawable/img_home_viewpager_exp2.png new file mode 100644 index 0000000..50fa4be Binary files /dev/null and b/week03/app/src/main/res/drawable/img_home_viewpager_exp2.png differ diff --git a/week03/app/src/main/res/drawable/img_potcast_exp.png b/week03/app/src/main/res/drawable/img_potcast_exp.png new file mode 100644 index 0000000..50a46e0 Binary files /dev/null and b/week03/app/src/main/res/drawable/img_potcast_exp.png differ diff --git a/week03/app/src/main/res/drawable/img_video_exp.png b/week03/app/src/main/res/drawable/img_video_exp.png new file mode 100644 index 0000000..7f6b05f Binary files /dev/null and b/week03/app/src/main/res/drawable/img_video_exp.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_down.png b/week03/app/src/main/res/drawable/nugu_btn_down.png new file mode 100644 index 0000000..03a04c5 Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_down.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_pause_32.png b/week03/app/src/main/res/drawable/nugu_btn_pause_32.png new file mode 100644 index 0000000..9388aa3 Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_pause_32.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_play_32.png b/week03/app/src/main/res/drawable/nugu_btn_play_32.png new file mode 100644 index 0000000..b781e4c Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_play_32.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_random_inactive.png b/week03/app/src/main/res/drawable/nugu_btn_random_inactive.png new file mode 100644 index 0000000..fe4f880 Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_random_inactive.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_repeat_inactive.png b/week03/app/src/main/res/drawable/nugu_btn_repeat_inactive.png new file mode 100644 index 0000000..1e4044d Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_repeat_inactive.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_skip_next_32.png b/week03/app/src/main/res/drawable/nugu_btn_skip_next_32.png new file mode 100644 index 0000000..fc02f28 Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_skip_next_32.png differ diff --git a/week03/app/src/main/res/drawable/nugu_btn_skip_previous_32.png b/week03/app/src/main/res/drawable/nugu_btn_skip_previous_32.png new file mode 100644 index 0000000..03ec854 Binary files /dev/null and b/week03/app/src/main/res/drawable/nugu_btn_skip_previous_32.png differ diff --git a/week03/app/src/main/res/drawable/textview_background_radius.xml b/week03/app/src/main/res/drawable/textview_background_radius.xml new file mode 100644 index 0000000..d250c1e --- /dev/null +++ b/week03/app/src/main/res/drawable/textview_background_radius.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/drawable/textview_background_select_color_radius.xml b/week03/app/src/main/res/drawable/textview_background_select_color_radius.xml new file mode 100644 index 0000000..8aaca4c --- /dev/null +++ b/week03/app/src/main/res/drawable/textview_background_select_color_radius.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/drawable/widget_black_play.png b/week03/app/src/main/res/drawable/widget_black_play.png new file mode 100644 index 0000000..0ec2700 Binary files /dev/null and b/week03/app/src/main/res/drawable/widget_black_play.png differ diff --git a/week03/app/src/main/res/layout/activity_main.xml b/week03/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..8cec909 --- /dev/null +++ b/week03/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/activity_song.xml b/week03/app/src/main/res/layout/activity_song.xml new file mode 100644 index 0000000..533a027 --- /dev/null +++ b/week03/app/src/main/res/layout/activity_song.xml @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_album.xml b/week03/app/src/main/res/layout/fragment_album.xml new file mode 100644 index 0000000..0b0742f --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_album.xml @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_banner.xml b/week03/app/src/main/res/layout/fragment_banner.xml new file mode 100644 index 0000000..b7ef866 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_banner.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_detail.xml b/week03/app/src/main/res/layout/fragment_detail.xml new file mode 100644 index 0000000..151ebe6 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_detail.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_home.xml b/week03/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..a194b36 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,792 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_locker.xml b/week03/app/src/main/res/layout/fragment_locker.xml new file mode 100644 index 0000000..c37d43c --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_locker.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week03/app/src/main/res/layout/fragment_look.xml b/week03/app/src/main/res/layout/fragment_look.xml new file mode 100644 index 0000000..c99bd69 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_look.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_savedalbum.xml b/week03/app/src/main/res/layout/fragment_savedalbum.xml new file mode 100644 index 0000000..669fea8 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_savedalbum.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_savedsong.xml b/week03/app/src/main/res/layout/fragment_savedsong.xml new file mode 100644 index 0000000..4f7e9f0 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_savedsong.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_search.xml b/week03/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..07de9d3 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_song.xml b/week03/app/src/main/res/layout/fragment_song.xml new file mode 100644 index 0000000..dfd2d03 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_song.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_songfile.xml b/week03/app/src/main/res/layout/fragment_songfile.xml new file mode 100644 index 0000000..05dca29 --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_songfile.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/layout/fragment_video.xml b/week03/app/src/main/res/layout/fragment_video.xml new file mode 100644 index 0000000..70e650d --- /dev/null +++ b/week03/app/src/main/res/layout/fragment_video.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/menu/bottom_nav_menu.xml b/week03/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000..2b56b8c --- /dev/null +++ b/week03/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week03/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week03/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week03/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week03/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week03/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week03/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/week03/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/week03/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week03/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/week03/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/week03/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week03/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/week03/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/week03/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week03/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/week03/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/week03/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week03/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/week03/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/week03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/week03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/week03/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week03/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/week03/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/week03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/week03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/week03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/week03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/week03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/week03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/week03/app/src/main/res/values/colors.xml b/week03/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..3922592 --- /dev/null +++ b/week03/app/src/main/res/values/colors.xml @@ -0,0 +1,13 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FFD3D3D3 + #FF0000FF + #3f3fff + \ No newline at end of file diff --git a/week03/app/src/main/res/values/strings.xml b/week03/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..63f5ff1 --- /dev/null +++ b/week03/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + FLO + + Hello blank fragment + \ No newline at end of file diff --git a/week03/app/src/main/res/values/themes.xml b/week03/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..6a7115a --- /dev/null +++ b/week03/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + + + + \ No newline at end of file diff --git a/week05/app/src/main/res/xml/backup_rules.xml b/week05/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..4df9255 --- /dev/null +++ b/week05/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/week05/app/src/main/res/xml/data_extraction_rules.xml b/week05/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/week05/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week05/app/src/test/java/com/example/flo/ExampleUnitTest.kt b/week05/app/src/test/java/com/example/flo/ExampleUnitTest.kt new file mode 100644 index 0000000..d39df20 --- /dev/null +++ b/week05/app/src/test/java/com/example/flo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.flo + +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/week05/build.gradle.kts b/week05/build.gradle.kts new file mode 100644 index 0000000..952b930 --- /dev/null +++ b/week05/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} \ No newline at end of file diff --git a/week05/gradle.properties b/week05/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/week05/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. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-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/week05/gradle/libs.versions.toml b/week05/gradle/libs.versions.toml new file mode 100644 index 0000000..5332b17 --- /dev/null +++ b/week05/gradle/libs.versions.toml @@ -0,0 +1,34 @@ +[versions] +agp = "8.13.0" +kotlin = "2.0.21" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2024.09.00" +constraintlayout = "2.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } + diff --git a/week05/gradle/wrapper/gradle-wrapper.jar b/week05/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/week05/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week05/gradle/wrapper/gradle-wrapper.properties b/week05/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..af10ccc --- /dev/null +++ b/week05/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Sep 28 16:12:35 KST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week05/gradlew b/week05/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/week05/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/week05/gradlew.bat b/week05/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/week05/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/week05/settings.gradle.kts b/week05/settings.gradle.kts new file mode 100644 index 0000000..2a48c99 --- /dev/null +++ b/week05/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "FLO" +include(":app") + \ No newline at end of file diff --git a/week06/.gitignore b/week06/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/week06/.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/week06/.idea/.name b/week06/.idea/.name new file mode 100644 index 0000000..997352e --- /dev/null +++ b/week06/.idea/.name @@ -0,0 +1 @@ +FLO \ No newline at end of file diff --git a/week06/.idea/AndroidProjectSystem.xml b/week06/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/week06/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/week06/.idea/compiler.xml b/week06/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/week06/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week06/.idea/deploymentTargetSelector.xml b/week06/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..eaf6efa --- /dev/null +++ b/week06/.idea/deploymentTargetSelector.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/week06/.idea/deviceManager.xml b/week06/.idea/deviceManager.xml new file mode 100644 index 0000000..eebfe8e --- /dev/null +++ b/week06/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week06/.idea/gradle.xml b/week06/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/week06/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week06/.idea/inspectionProfiles/Project_Default.xml b/week06/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/week06/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/week06/.idea/migrations.xml b/week06/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/week06/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/week06/.idea/misc.xml b/week06/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/week06/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/week06/.idea/runConfigurations.xml b/week06/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/week06/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week06/.idea/vcs.xml b/week06/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/week06/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/.gitignore b/week06/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/week06/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/week06/app/build.gradle.kts b/week06/app/build.gradle.kts new file mode 100644 index 0000000..470b1eb --- /dev/null +++ b/week06/app/build.gradle.kts @@ -0,0 +1,69 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "com.example.flo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.flo" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("androidx.fragment:fragment:1.8.9") + implementation("com.google.android.material:material:1.13.0") + implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("com.tbuonomo:dotsindicator:5.1.0") + implementation("androidx.recyclerview:recyclerview:1.4.0") + implementation("com.google.code.gson:gson:2.13.2") + implementation("androidx.core:core-splashscreen:1.0.1") +} \ No newline at end of file diff --git a/week06/app/proguard-rules.pro b/week06/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/week06/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/week06/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt b/week06/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..6dfac89 --- /dev/null +++ b/week06/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.flo + +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.flo", appContext.packageName) + } +} \ No newline at end of file diff --git a/week06/app/src/main/AndroidManifest.xml b/week06/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d61203a --- /dev/null +++ b/week06/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/activities/MainActivity.kt b/week06/app/src/main/java/com/example/flo/activities/MainActivity.kt new file mode 100644 index 0000000..79edd23 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/activities/MainActivity.kt @@ -0,0 +1,117 @@ +package com.example.flo.activities + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.home.HomeFragment +import com.example.flo.locker.LockerFragment +import com.example.flo.look.LookFragment +import com.example.flo.R +import com.example.flo.search.SearchFragment +import com.example.flo.dataclasses.Song +import com.example.flo.activities.SongActivity +import com.example.flo.databinding.ActivityMainBinding +import com.google.gson.Gson + +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + + private var song:Song = Song() + private var gson: Gson = Gson() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setTheme(R.style.Theme_FLO) + enableEdgeToEdge() + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + //하단플레이어에 나오는 노래를 Song객체에 저장 + val song = Song( + title = binding.mainMiniplayerTitleTv.text.toString(), + singer = binding.mainMiniplayerSingerTv.text.toString(), + second = 0, playTime = 60, isPlaying = false, music = "music_lilac" + ) +// val song = Song( +// title = binding.mainMiniplayerTitleTv.text.toString(), +// singer = binding.mainMiniplayerSingerTv.text.toString(), +// second = 0, playTime = 60, isPlaying = false +// ) + + //하단의 플레이어를 누르면 송액티비티로 전환. intent에 재생 노래 정보를 넣음 + binding.mainPlayerCl.setOnClickListener { + //finish() //현재 액티비티 종료 + val intent = Intent(this, SongActivity::class.java) + intent.putExtra("title", song.title) + intent.putExtra("singer", song.singer) + intent.putExtra("second", song.second) + intent.putExtra("playTime", song.playTime) + intent.putExtra("isPlaying", song.isPlaying) + intent.putExtra("music", song.music) + startActivity(intent) + } + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + //BottomNavigationView를 눌렀을 때 Fragment 변경하기 + binding.mainBnv.setOnItemSelectedListener { item -> + when (item.itemId) { + //매인 화면 + R.id.homeFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + true + } + //둘러보기 화면 + R.id.lookFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LookFragment()) + .commit() + true + } + //검색 화면 + R.id.searchFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, SearchFragment()) + .commit() + true + } + //보관함 화면 + R.id.lockerFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LockerFragment()) + .commit() + true + } + else -> false + } + } + } + + private fun setMiniPlayer(song: Song){ + binding.mainMiniplayerTitleTv.text = song.title + binding.mainMiniplayerSingerTv.text = song.singer + binding.mainProgressSb.progress = (song.second*100000)/song.playTime + } + + override fun onStart() { + super.onStart() + val sharedPreferences = getSharedPreferences("song", MODE_PRIVATE) + val songJson = sharedPreferences.getString("songData", null) + + song = if(songJson==null){ //예외 처리 + Song(title = "라일락", singer = "아이유(IU)", second = 0, playTime = 60, isPlaying = false) + } else { + gson.fromJson(songJson, Song::class.java) + } + + setMiniPlayer(song) + Log.d("MainActivity", "Loaded song: ${song.title}, ${song.second}/${song.playTime}") + } + + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/activities/SongActivity.kt b/week06/app/src/main/java/com/example/flo/activities/SongActivity.kt new file mode 100644 index 0000000..a51d2d6 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/activities/SongActivity.kt @@ -0,0 +1,188 @@ +package com.example.flo.activities + +import android.content.Intent +import android.content.SharedPreferences +import android.graphics.Color +import android.graphics.PorterDuff +import android.media.MediaPlayer +import android.os.Bundle +import android.util.Log +import android.view.View +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.R +import com.example.flo.databinding.ActivitySongBinding +import com.example.flo.dataclasses.PlayedSong +import com.example.flo.dataclasses.Song +import com.google.gson.Gson + +class SongActivity : AppCompatActivity() { + private lateinit var binding: ActivitySongBinding + lateinit var song: Song // 첫 isPlaying은 False + lateinit var timer: Timer + private var mediaPlayer: MediaPlayer? = null + private var gson: Gson = Gson() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySongBinding.inflate(layoutInflater) + setContentView(binding.root) + initSong() //송 데이터 받아와 실행 + setPlayer(song) + //우측 상단 버튼 누르면 액티비티 종료 + binding.songDownIb.setOnClickListener{ + finish() + } + //재생, 일시정지 + binding.songMiniplayerIv.setOnClickListener { + setPlayerStatus(true) + } + binding.songPauseIv.setOnClickListener { + setPlayerStatus(false) + } + //이전곡/다음곡 + binding.songPreviousIv.setOnClickListener { + restart() + } + binding.songNextIv.setOnClickListener { + restart() + } + //반복재생 + var isRoop = false + binding.songRepeatIv.setOnClickListener { + if (!isRoop) { + binding.songRepeatIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + isRoop = true + } else { + binding.songRepeatIv.clearColorFilter() + isRoop = false + } + } + //전체재생(랜덤재생인듯?) + var willPlayAll = false + binding.songRandomIv.setOnClickListener { + if (!willPlayAll) { + binding.songRandomIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + willPlayAll = true + } else { + binding.songRandomIv.clearColorFilter() + willPlayAll = false + } + } + } + + //메인액티비티에서 song데이터를 받아오는 함수 + private fun initSong() { + if (intent.hasExtra("title") && intent.hasExtra("singer")) { + song = Song( + title = intent.getStringExtra("title")!!, + singer = intent.getStringExtra("singer")!!, + second = intent.getIntExtra("second", 0), + playTime = intent.getIntExtra("playTime", 0), + isPlaying = intent.getBooleanExtra("isPlaying", false), + music = intent.getStringExtra("music")!! + ) + } + startTimer() + } + + //송 데이터를 뷰에 렌더링하는 함수 + private fun setPlayer(song: Song) { + binding.songMusicTitleTv.text = intent.getStringExtra("title") + binding.songSingerNameTv.text = intent.getStringExtra("singer") + binding.songStartTimeTv.text = String.format("%02d:%02d", song.second / 60, song.second % 60) + binding.songEndTimeTv.text = String.format("%02d:%02d", song.playTime / 60, song.second % 60) + binding.songProgressSb.progress = (song.second * 1000 / song.playTime) + val music = resources.getIdentifier(song.music, "raw", this.packageName) + mediaPlayer = MediaPlayer.create(this, music) + setPlayerStatus(song.isPlaying) + } + + //재생, 일시정지 버튼 로직 구현 함수 + private fun setPlayerStatus(isPlaying: Boolean) { + song.isPlaying = isPlaying + timer.isPlaying = isPlaying + if (isPlaying) { + binding.songMiniplayerIv.visibility = View.GONE + binding.songPauseIv.visibility = View.VISIBLE + mediaPlayer?.start() + } else { + binding.songMiniplayerIv.visibility = View.VISIBLE + binding.songPauseIv.visibility = View.GONE + if(mediaPlayer?.isPlaying==true) { // + mediaPlayer?.pause() + } + } + } + + //타이머 시작 함수 + private fun startTimer() { + timer = Timer(song.playTime, song.isPlaying) + timer.start() + } + + //재시작 함수 + private fun restart() { + timer.interrupt() // 기존 타이머 스레드 종료 + song.second = 0 // 곡 시간 초기화 + song.isPlaying = true // 재생 상태 설정 + setPlayer(song) // 송 데이터를 다시 세팅 -> setPlayerStatus함수 호출 -> true이므로 ||버튼이 나옴 + startTimer() // 새로운 타이머 스레드를 생성하고 실행 + } + + inner class Timer(private val playTime: Int, var isPlaying: Boolean = true) : Thread() { + private var second: Int = 0 // 타이머 텍스트뷰에 사용할 용도 + private var mills: Float = 0f // 경과된 시간 누적용, 시크바에 사용할 용도 + override fun run() { + super.run() + try { + while (true) { + if (second >= playTime) { + break + } + //노래가 재생중일동안 실행 + if (isPlaying) { + sleep(50) + mills += 50 + //시크바 갱신 + runOnUiThread { + binding.songProgressSb.progress = ((mills / playTime) * 100).toInt() + } + //타이머 텍스트뷰 갱신 + if (mills % 1000 == 0f) { + runOnUiThread { + binding.songStartTimeTv.text = + String.format("%02d:%02d", second / 60, second % 60) + } + second++ + } + } + } + } catch (e: InterruptedException) { //액티비티가 종료되었을 경우 스레드 종료 + Log.d("Song", "스레드가 죽었습니다. ${e.message}") + } + } + } + + // 사용자가 포커스를 잃었을 때 음악 중지 + override fun onPause() { + super.onPause() + setPlayerStatus(false) + song.second = ((binding.songProgressSb.progress * song.playTime) / 100) / 1000 + val sharedPreferences = getSharedPreferences("song", MODE_PRIVATE) + val editor = sharedPreferences.edit() //에디터 + val songJson = gson.toJson(song) + editor.putString("songData", songJson) //깃에서 커밋과 같음 + + editor.apply() //꼭 쓰기!! 깃에서 push와 같음 + } + + //앱이 꺼질때 스레드 종료 + override fun onDestroy() { + super.onDestroy() + timer.interrupt() +// mediaPlayer?.release() // 미디어플레이어가 갖고 있던 리소스 해제 +// mediaPlayer? = null //미디어 플레이어 해제 + } +} diff --git a/week06/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt b/week06/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt new file mode 100644 index 0000000..4f8dfbf --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt @@ -0,0 +1,67 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.albumfrag.AlbumVPAdapter +import com.example.flo.R +import com.example.flo.activities.MainActivity +import com.example.flo.databinding.FragmentAlbumBinding +import com.example.flo.dataclasses.Album +import com.example.flo.albumfrag.DetailFragment +import com.example.flo.home.HomeFragment +import com.google.android.material.tabs.TabLayoutMediator +import com.google.gson.Gson + +class AlbumFragment : Fragment() { + lateinit var binding: FragmentAlbumBinding + private var gson: Gson = Gson() + + private val information = arrayListOf("수록곡", "상세정보", "영상") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentAlbumBinding.inflate(inflater, container, false) + + val albumJson = arguments?.getString("album") + val album = gson.fromJson(albumJson, Album::class.java) + setInit(album) + + //홈프래그먼트로의 화면전환 + binding.albumBackIv.setOnClickListener { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commitAllowingStateLoss() + } + + //디테일 프래그먼트로의 데이터 전달(왜안되는거야 왜 로그캣에 널이 뜨는데) + val detailFragment = DetailFragment() + + val bundle = Bundle().apply { + putString("singerName", binding.albumSingerNameTv.toString()) + putString("albumTitle", binding.albumMusicTitleTv.toString()) + } + detailFragment.arguments = bundle + + //어댑터 객체 생성시 앨범 인스턴스도 넘겨줌 -> 송프래그먼트에 수록곡 정보를 넘겨주기위함 + val albumAdapter = AlbumVPAdapter(this, album) + binding.albumContentVp.adapter = albumAdapter + TabLayoutMediator(binding.albumContentTb, binding.albumContentVp) { tap, position -> + tap.text = information[position] + }.attach() + + return binding.root + + } + private fun setInit(album: Album) { + binding.albumAlbumIv.setImageResource(album.coverImage!!) + binding.albumMusicTitleTv.text = album.title.toString() + binding.albumSingerNameTv.text = album.singer.toString() + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt b/week06/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt new file mode 100644 index 0000000..345e63f --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt @@ -0,0 +1,32 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.example.flo.albumfrag.VideoFragment +import com.example.flo.dataclasses.Album +import com.example.flo.albumfrag.DetailFragment +import com.google.gson.Gson + +//수록곡 전달을 위해 인자 하나 더 추가 -> 나 이거 왜써놓은거지 ㅋㅋ +class AlbumVPAdapter(fragment: Fragment, private val album: Album) : FragmentStateAdapter(fragment){ + + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + return when(position) { + 0 -> SongFragment().apply { + arguments = Bundle().apply { + val albumJson = Gson().toJson(album) + putString("album", albumJson) + } + + } + 1 -> { + DetailFragment() + } + else -> VideoFragment() + } + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt b/week06/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt new file mode 100644 index 0000000..cea0ae4 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt @@ -0,0 +1,37 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentDetailBinding + +class DetailFragment : Fragment() { + lateinit var binding : FragmentDetailBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailBinding.inflate(inflater, container, false) + + //앨범프래그먼트에서 전달한 데이터를 받음 + val singerName = arguments?.getString("singerName") + val albumTitle = arguments?.getString("albumTitle") + + Log.d("DetailFragment", "받은 가수 이름: $singerName") + Log.d("DetailFragment", "받은 앨범 제목: $albumTitle") + + + binding.singerNameTv.text = singerName + binding.albumNameTv.text = albumTitle + + + return binding.root + } + + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt b/week06/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt new file mode 100644 index 0000000..7eec954 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt @@ -0,0 +1,51 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.R +import com.example.flo.albumfrag.SongRVAdapter +import com.example.flo.databinding.FragmentSongBinding +import com.example.flo.dataclasses.Album +import com.google.gson.Gson + +class SongFragment : Fragment() { + lateinit var binding : FragmentSongBinding +// private var songDatas = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongBinding.inflate(inflater, container, false) + + //수록곡 목록 표시를 위해 앨범 정보를 겟또 + val albumJson = arguments?.getString("album") + val album = Gson().fromJson(albumJson, Album::class.java) + + //리사이클러뷰 어댑터 등록 + val songRVAdapter = SongRVAdapter(album.songs ?: arrayListOf()) + binding.albumTrackRv.adapter = songRVAdapter + binding.albumTrackRv.layoutManager = LinearLayoutManager(context) + + //내 취향 믹스 미션 + var isON = false + + binding.songMixoffTg.setOnClickListener { + if (!isON) { + binding.songMixoffTg.setImageResource(R.drawable.btn_toggle_on) + isON = true + } else { + binding.songMixoffTg.setImageResource(R.drawable.btn_toggle_off) + isON = false + } + + } + + return binding.root + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt b/week06/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt new file mode 100644 index 0000000..0854847 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt @@ -0,0 +1,41 @@ +package com.example.flo.albumfrag + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSongBinding +import com.example.flo.dataclasses.Song + +class SongRVAdapter(private var songList: ArrayList): RecyclerView.Adapter(){ + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSongBinding = ItemSongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songList[position]) + + } + + override fun getItemCount():Int = songList.size + + inner class ViewHolder(var binding: ItemSongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListOrderTv.text = song.num + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt b/week06/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt new file mode 100644 index 0000000..d337c6a --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt @@ -0,0 +1,23 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentVideoBinding + +class VideoFragment : Fragment() { + lateinit var binding : FragmentVideoBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentVideoBinding.inflate(inflater, container, false) + + return binding.root + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/dataclasses/Album.kt b/week06/app/src/main/java/com/example/flo/dataclasses/Album.kt new file mode 100644 index 0000000..fe75f77 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/dataclasses/Album.kt @@ -0,0 +1,11 @@ +package com.example.flo.dataclasses + +data class Album( + var title: String? = "", + var singer: String? = "", + var coverImage: Int? = null, + // 수록곡 정보용 arraylist + var songs: ArrayList? = arrayListOf(), + //앨범 출시일/정규앨범 유무/장르 + val information: String? = "" +) \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/dataclasses/PlayedSong.kt b/week06/app/src/main/java/com/example/flo/dataclasses/PlayedSong.kt new file mode 100644 index 0000000..620cd5e --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/dataclasses/PlayedSong.kt @@ -0,0 +1,9 @@ +package com.example.flo.dataclasses + +data class PlayedSong( + val title : String = "", + val singer : String = "", + var second: Int = 0, + var playTime: Int = 0, + var isPlaying: Boolean = false +) diff --git a/week06/app/src/main/java/com/example/flo/dataclasses/SavedSong.kt b/week06/app/src/main/java/com/example/flo/dataclasses/SavedSong.kt new file mode 100644 index 0000000..f69e3af --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/dataclasses/SavedSong.kt @@ -0,0 +1,9 @@ +package com.example.flo.dataclasses + +import com.example.flo.R + +data class SavedSong( + val img: Int = R.drawable.img_album_exp2, + val title: String = "", + val singer: String = "", +) diff --git a/week06/app/src/main/java/com/example/flo/dataclasses/Song.kt b/week06/app/src/main/java/com/example/flo/dataclasses/Song.kt new file mode 100644 index 0000000..74734e1 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/dataclasses/Song.kt @@ -0,0 +1,12 @@ +package com.example.flo.dataclasses + +data class Song( + val num : String? = "01", + var title: String = "", + var singer: String = "", + var second: Int = 0, + var playTime: Int = 0, + var isPlaying: Boolean = false, + var music: String = "" + //val img: Int = R.drawable.img_album_exp2 +) diff --git a/week06/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt b/week06/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt new file mode 100644 index 0000000..c2632b2 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt @@ -0,0 +1,63 @@ +package com.example.flo.home + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemAlbumBinding +import com.example.flo.dataclasses.Album + +class AlbumRVAdapter(private var albumList: ArrayList): RecyclerView.Adapter() { + + //리스너 인터페이스 정의 + interface MyItemClickListener { + fun onItemClick(album: Album) +// fun onRemoveAlbum(position: Int) + } + private lateinit var myItemClickListener: MyItemClickListener + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun addItem(album: Album) { + albumList.add(album) + notifyDataSetChanged() + } + +// fun removeItem(position: Int) { +// albumList.removeAt(position) +// notifyDataSetChanged() +// } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemAlbumBinding = ItemAlbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + //아이템 뷰 객체를 던져줌 + return ViewHolder(binding) + } + + // 뷰홀더에 데이터를 바인딩해줄때마다 호출, 클릭 이벤트 작성 + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.itemView.setOnClickListener { myItemClickListener.onItemClick(albumList[position]) } + //holder.binding.itemAlbumTitleTv.setOnClickListener { myItemClickListener.onRemoveAlbum(position) } + } + + //데이터 세트 크기를 알려줌. 리사이클러뷰의 끝이 어딘지 + override fun getItemCount(): Int = albumList.size + + //뷰홀더 클래스 + inner class ViewHolder(var binding: ItemAlbumBinding): RecyclerView.ViewHolder(binding.root) { + + fun bind(album: Album) { + binding.itemAlbumTitleTv.text = album.title + binding.itemAlbumSingerTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImage!!) + } + + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/home/BannerFragment.kt b/week06/app/src/main/java/com/example/flo/home/BannerFragment.kt new file mode 100644 index 0000000..145a504 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/home/BannerFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentBannerBinding + +//인자를 넣어서 새로운 배너 프래그먼트 추가 +class BannerFragment(val imgRes : Int) : Fragment() { + lateinit var binding : FragmentBannerBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBannerBinding.inflate(inflater, container, false) + + binding.bannerImageIv.setImageResource(imgRes) + + return binding.root + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt b/week06/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt new file mode 100644 index 0000000..e406726 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt @@ -0,0 +1,23 @@ +package com.example.flo.home + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class BannerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + + private val fragmentlist : ArrayList = ArrayList() + + override fun getItemCount(): Int { // 데이터를 몇개를 전달할 것이냐 + return fragmentlist.size + } + + override fun createFragment(position: Int): Fragment = fragmentlist[position] + + //리스트에 추가하는 함수 + fun addFragment(fragment: Fragment) { + fragmentlist.add(fragment) + notifyItemInserted(fragmentlist.size - 1) //뷰페이저에게 새로운 값이 추가가 됐다고 알림 + } + + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/home/HomeFragment.kt b/week06/app/src/main/java/com/example/flo/home/HomeFragment.kt new file mode 100644 index 0000000..b527867 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/home/HomeFragment.kt @@ -0,0 +1,153 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.viewpager2.widget.ViewPager2 +import com.example.flo.albumfrag.AlbumFragment +import com.example.flo.home.AlbumRVAdapter +import com.example.flo.home.BannerVPAdapter +import com.example.flo.R +import com.example.flo.databinding.FragmentHomeBinding +import com.example.flo.dataclasses.Album +import com.example.flo.dataclasses.Song +import com.example.flo.activities.MainActivity +import com.google.gson.Gson + +class HomeFragment : Fragment() { + lateinit var binding: FragmentHomeBinding + private var albumDatas = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentHomeBinding.inflate(inflater, container, false) + +// binding.homeAlbumImgIv1.setOnClickListener { +// //앨범 프래그먼트로 데이터 전달 +// val bundle = Bundle() +// bundle.putString("album", binding.lilac.text.toString()) +// bundle.putString("singer", binding.iu.text.toString()) +// +// val albumFragment = AlbumFragment() +// albumFragment.arguments = bundle +// +// //화면 전환 +// (context as MainActivity).supportFragmentManager.beginTransaction() +// .replace(R.id.main_frm, albumFragment) +// .commitAllowingStateLoss() +// } + // 앨범 데이터 리스트 생성 더미 데이터 + albumDatas.apply { + add( + Album( + title = "Butter", + singer = "방탄소년단 (BTS)", + coverImage = R.drawable.img_album_exp, + songs = arrayListOf( + Song("01", "Butter", "방탄소년단 (BTS)"), + Song("02", "Permission to Dance", "방탄소년단 (BTS)"), + Song("03", "Butter (Instrumental)", "방탄소년단 (BTS)"), + Song("04", "Permission to Dance (Instrumental)", "방탄소년단 (BTS)") + ) + ) + ) + add( + Album( + title = "Lilac", + singer = "아이유 (IU)", + coverImage = R.drawable.img_album_exp2, + songs = arrayListOf( + Song("01", "라일락", "아이유 (IU)"), + Song("02", "Flu", "아이유 (IU)"), + Song("03", "Coin", "아이유 (IU)"), + Song("04", "봄 안녕 봄", "아이유 (IU)"), + Song("05", "Celebrity", "아이유 (IU)"), + Song("06", "돌림노래", "아이유 (IU)"), + Song("07", "빈 컵", "아이유 (IU)"), + Song("08", "아이와 나의 바다", "아이유 (IU)"), + Song("09", "어푸 (Ah puh )", "아이유 (IU)"), + Song("10", "에필로그", "아이유 (IU)") + ) + ) + ) + add( + Album( + title = "Temp", + singer = "김시선 (UMC)", + coverImage = R.drawable.img_potcast_exp + ) + ) + add( + Album( + title = "Classic", + singer = "베토벤 (Beethoven)", + coverImage = R.drawable.img_first_album_default, + songs = arrayListOf( + Song("01", "월광 소나타", "베토벤 (Beethoven)"), + Song("02", "비창 소나타", "베토벤 (Beethoven)"), + Song("03", "운명 교향곡", "베토벤 (Beethoven)"), + Song("04", "영웅 교향곡", "베토벤 (Beethoven)"), + Song("05", "환희의 송가", "베토벤 (Beethoven)"), + Song("06", "황제 협주곡", "베토벤 (Beethoven)") + + ) + ) + ) + } + + //리사이클러뷰 어댑터 등록 (앨범 나열) + val albumRVAdapter = AlbumRVAdapter(albumDatas) + binding.homeTodayMusicAlbumRv.adapter = albumRVAdapter + + //리사이클러뷰의 레이아웃 매니저 설정 + binding.homeTodayMusicAlbumRv.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, false + ) + + //등록한 리사이클러뷰 어댑터 객체에 클릭리스너 세팅 + albumRVAdapter.setMyItemClickListener(object : AlbumRVAdapter.MyItemClickListener { + override fun onItemClick(album: Album) { + changeAlbumFragment(album) + } + +// override fun onRemoveAlbum(position: Int) { +// albumRVAdapter.removeItem(position) +// } + }) + + //뷰페이저2에 광고 배너들 연결 + val bannerAdapter = BannerVPAdapter(this) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + binding.homeBannerVp.adapter = bannerAdapter + + //광고 뷰 페이저가 좌우로 스크롤 될수 있도록 지정 + binding.homeBannerVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + return binding.root + } + + private fun changeAlbumFragment(album: Album) { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, AlbumFragment().apply { + arguments = Bundle().apply { + val gson = Gson() + val albumJson = gson.toJson(album) //앨범객체를 Json으로 변환 + putString("album", albumJson) + } + }) + .commitAllowingStateLoss() + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/LockerFragment.kt b/week06/app/src/main/java/com/example/flo/locker/LockerFragment.kt new file mode 100644 index 0000000..700c524 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/LockerFragment.kt @@ -0,0 +1,48 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.locker.LockerVPAdapter +import com.example.flo.databinding.FragmentLockerBinding +import com.example.flo.dataclasses.Song +import com.google.android.material.tabs.TabLayoutMediator + +class LockerFragment : Fragment() { + lateinit var binding: FragmentLockerBinding +// private var songDatas = ArrayList< SavedSong>() + + private val information = arrayListOf("저장한 곡", "음악피일", "저장앨범") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLockerBinding.inflate(inflater, container, false) + + //데이터 리스트 생성 더미 데이터 +// songDatas.apply { +// add(SavedSong(img = R.drawable.img_album_exp, title = "Butter", +// singer = "방탄소년단 (BTS)")) +// add(SavedSong(img = R.drawable.img_album_exp2, title = "라일락", singer = "아이유 (IU)")) +// } + + //뷰페이저 어댑터 등록 + val lockerAdapter = LockerVPAdapter(this) + binding.lockerContentVp.adapter = lockerAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.lockerContentTb, binding.lockerContentVp) { tap, position -> + tap.text = information[position] + + }.attach() + return binding.root + } + + private fun setInit(song: Song) { + + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt b/week06/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt new file mode 100644 index 0000000..0e8cccb --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt @@ -0,0 +1,42 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.dataclasses.Song + +class LockerRVAdapter(private var songs: ArrayList) : RecyclerView.Adapter() + { + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.itemView.setOnClickListener { + + } + } + + override fun getItemCount(): Int = songs.size + + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt b/week06/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt new file mode 100644 index 0000000..9e8f745 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt @@ -0,0 +1,31 @@ +package com.example.flo.locker + +import android.util.Log +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class LockerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + Log.d("FragmentCheck2", "createfrag") +// val gson = Gson() +// val songJson = gson.toJson(song) + + return when(position) { + 0 -> { + SavedsongFragment() + + } + 1 -> { + SongfileFragment() + } + else -> { + SavedalbumFragment() + } + } + + } + + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt b/week06/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt new file mode 100644 index 0000000..fdfce24 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt @@ -0,0 +1,57 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedalbumBinding +import com.example.flo.dataclasses.Album + +class SavedAlbumRVAdapter(private var albumList: ArrayList): + RecyclerView.Adapter() { + + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveAlbum(position: Int) + } + + private lateinit var myItemClickListener: SavedAlbumRVAdapter.MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun removeAlbum(position: Int) { + albumList.removeAt(position) + notifyDataSetChanged() + } + + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): SavedAlbumRVAdapter.ViewHolder { + val binding = ItemSavedalbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: SavedAlbumRVAdapter.ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.binding.albumCrudIv.setOnClickListener { myItemClickListener.onRemoveAlbum(position) } + } + + override fun getItemCount(): Int = albumList.size + + inner class ViewHolder(var binding: ItemSavedalbumBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(album: Album) { + binding.albumTitleTv.text = album.title + binding.albumSingerNameTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImage!!) + binding.albumInformationTv.text = album.information + } + + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt b/week06/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt new file mode 100644 index 0000000..160d389 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt @@ -0,0 +1,70 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.R +import com.example.flo.databinding.FragmentSavedalbumBinding +import com.example.flo.dataclasses.Album +import com.example.flo.dataclasses.Song +import com.google.gson.Gson + +class SavedalbumFragment : Fragment() { + + lateinit var binding : FragmentSavedalbumBinding + private var albumDatas = ArrayList() + + override fun onCreateView( + + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedalbumBinding.inflate(inflater, container, false) + albumDatas.apply { + add( + Album( + title = "Butter", + singer = "방탄소년단(BTS)", + coverImage = R.drawable.img_album_exp, + information = "2021.03.25|정규|댄스 팝" + ) + ) + add( + Album( + title = "Great!", + singer = "모모랜드(MOMOLAND)", + coverImage = R.drawable.img_great_album_exp, + information = "2021.03.25|정규|댄스 팝" + ) + ) + } + + val savedAlbumRVAdapter = SavedAlbumRVAdapter(albumDatas) + binding.savedAlbumRv.adapter = savedAlbumRVAdapter + + binding.savedAlbumRv.layoutManager = LinearLayoutManager( + context, LinearLayoutManager.VERTICAL, false + ) + + //어댑터객체에 클릭 리스너 세팅 + savedAlbumRVAdapter.setMyItemClickListener(object: + SavedAlbumRVAdapter.MyItemClickListener { + override fun onRemoveAlbum(position: Int) { + savedAlbumRVAdapter.removeAlbum(position) + } + } + ) + + + val songJson = arguments?.getString("song") + val song = Gson().fromJson(songJson, Song::class.java) + + return binding.root + } + +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt b/week06/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt new file mode 100644 index 0000000..5777e26 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt @@ -0,0 +1,47 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.R +import com.example.flo.locker.SavedsongRVAdapter +import com.example.flo.databinding.FragmentSavedsongBinding +import com.example.flo.dataclasses.SavedSong + +class SavedsongFragment : Fragment() { + + lateinit var binding : FragmentSavedsongBinding + private var savedSongList = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedsongBinding.inflate(inflater, container, false) + //Log.d("FragmentCheck", "SavedsongFragment onCreateView") + + // 곡 리스트 더미 데이터 생성 + savedSongList.apply { + add(SavedSong(R.drawable.img_album_exp, "Butter", "방탄소년단 (BTS)")) + add(SavedSong(R.drawable.img_album_exp2, "아이와 나의 바다", "아이유 (IU)")) + add(SavedSong(R.drawable.img_first_album_default, "운명 교향곡", "베토벤 (Beethoven)")) + } + + //리사이클러뷰 어댑터 등록 + val savedsongRVAdapter = SavedsongRVAdapter(savedSongList) + binding.savedSongRv.adapter = savedsongRVAdapter + + //등록한 리사이클러뷰 어댑터 객체에 리스너 세팅 + savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { + override fun onRemoveSong(position: Int) { + savedsongRVAdapter.removeItem(position) + } + }) + + return binding.root + + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt b/week06/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt new file mode 100644 index 0000000..49ff186 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt @@ -0,0 +1,62 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.dataclasses.SavedSong + +class SavedsongRVAdapter(private var savedsongList: ArrayList): RecyclerView.Adapter() { + + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveSong(position: Int) + } + private lateinit var myItemClickListener: MyItemClickListener + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun addItem(savedSong: SavedSong) { + savedsongList.add(savedSong) + notifyDataSetChanged() + } + + //아이템 삭제용 + fun removeItem(position: Int) { + savedsongList.removeAt(position) + notifyDataSetChanged() + } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(savedsongList[position]) + holder.binding.songMoreIv.setOnClickListener { myItemClickListener.onRemoveSong(position) } + + } + + override fun getItemCount():Int = savedsongList.size + + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(savedsong: SavedSong) { + binding.songListAlbumImgIv.setImageResource(savedsong.img) + binding.songMusicTitleTv.text = savedsong.title + binding.songSingerNameTv.text = savedsong.singer + } + + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/locker/SongfileFragment.kt b/week06/app/src/main/java/com/example/flo/locker/SongfileFragment.kt new file mode 100644 index 0000000..720d1b9 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/locker/SongfileFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSongfileBinding + +class SongfileFragment : Fragment() { + + lateinit var binding : FragmentSongfileBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongfileBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SongfileFragment onCreateView") + + return binding.root + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/look/LookFragment.kt b/week06/app/src/main/java/com/example/flo/look/LookFragment.kt new file mode 100644 index 0000000..d129ef6 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/look/LookFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.look + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentLookBinding + +class LookFragment : Fragment() { + lateinit var binding: FragmentLookBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLookBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/search/SearchFragment.kt b/week06/app/src/main/java/com/example/flo/search/SearchFragment.kt new file mode 100644 index 0000000..4ad6136 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/search/SearchFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.search + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSearchBinding + +class SearchFragment : Fragment() { + lateinit var binding: FragmentSearchBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSearchBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/services/Foreground.kt b/week06/app/src/main/java/com/example/flo/services/Foreground.kt new file mode 100644 index 0000000..06e86f6 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/services/Foreground.kt @@ -0,0 +1,48 @@ +package com.example.flo.services + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class Foreground : Service() { + + val CHANNEL_ID = "Foreground" + val NOTI_ID = 713 + fun createNotificationChannel() { + //API 26이상에서는 사전에 채널을 등록해야 함. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = + NotificationChannel(CHANNEL_ID, "FOREGROUND", NotificationManager.IMPORTANCE_HIGH) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + createNotificationChannel() + //내가 띄울 Notification을 띄운다. + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher_round) + .setContentTitle("ForegroundService") + .setContentText("Hello World!") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + startForeground(NOTI_ID, notification) + + return super.onStartCommand(intent, flags, startId) + } + + override fun onBind(intent: Intent): IBinder { + return Binder() + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/services/MusicService.kt b/week06/app/src/main/java/com/example/flo/services/MusicService.kt new file mode 100644 index 0000000..4184776 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/services/MusicService.kt @@ -0,0 +1,128 @@ +package com.example.flo.services + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Intent +import android.media.MediaPlayer +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class MusicService : Service() { + + //채널 ID와 Notificiation ID는 자유롭게! + private val CHANNEL_ID = "ForegroundMusicService" + private val NOTI_ID = 713 + + private var mediaPlayer: MediaPlayer? = null + private val binder = MusicBinder() + + //현재 재생 중인 노래 정보를 저장할 변수 + private var currentSongTitle: String = "Unknown Title" + private var currentSongArtist: String = "Unknown Artist" + + //Activity에 Service 인스턴스를 전달 + inner class MusicBinder : Binder() { + fun getService(): MusicService = this@MusicService + } + + //서비스 시작 시 초기화 + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + //Notification 활성화 + createNotificationChannel() + + //Intent로 받은 정보들을 파싱 + val initialTitle = intent?.getStringExtra("songTitle") ?: "Unknown Title" + val initialArtist = intent?.getStringExtra("songArtist") ?: "Unknown Artist" + val isPlaying = intent?.getBooleanExtra("isPlaying", false) ?: false + + //MediaPlayer 및 변수 초기화 (임의로 노래를 연결) + if (mediaPlayer == null) { + mediaPlayer = MediaPlayer.create(this, R.raw.music_lilac) + currentSongTitle = initialTitle + currentSongArtist = initialArtist + if (isPlaying) { + mediaPlayer?.start() + } + } + + //알람도 같이 설정 + val notification = createNotification() + startForeground(NOTI_ID, notification) + + return START_STICKY + } + + override fun onBind(intent: Intent): IBinder { + return binder + } + + //알람 채널 설정(CHANNEL_ID와 name은 자유롭게 설정!) + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + "Foreground Music Service Channel", + NotificationManager.IMPORTANCE_HIGH + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + } + + //알람으로 노래가 재생중임을 표시 + private fun createNotification(): Notification { + val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle("음악 재생 중") + .setContentText("$currentSongTitle 이/가 재생 중입니다.") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setOngoing(true) + .setOnlyAlertOnce(true) + + return notificationBuilder.build() + } + + //외부에서 서비스에 접근 가능한 함수들 + //음악 재생 + fun playMusic() { + mediaPlayer?.start() + } + //음악 멈춤 + fun pauseMusic() { + mediaPlayer?.pause() + } + //인자로 받은 위치로 곡의 재생 위치 이동 + fun seekTo(position: Int) { + mediaPlayer?.seekTo(position) + } + //현재 재생중인 노래 정보 업데이트 + fun updateCurrentSongInfo(title: String, artist: String) { + currentSongTitle = title + currentSongArtist = artist + } + //현재 재생중인 노래의 길이 리턴 + fun getDuration(): Int { + return mediaPlayer?.duration ?: 0 + } + //현재 노래의 위치 리턴(SeekBar에 넣을 거) + fun getCurrentPosition(): Int { + return mediaPlayer?.currentPosition ?: 0 + } + //재생 중임? + fun isPlaying(): Boolean { + return mediaPlayer?.isPlaying ?: false + } + + override fun onDestroy() { + mediaPlayer?.stop() + mediaPlayer?.release() + mediaPlayer = null + super.onDestroy() + } +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/ui/theme/Color.kt b/week06/app/src/main/java/com/example/flo/ui/theme/Color.kt new file mode 100644 index 0000000..6b31678 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.flo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/ui/theme/Theme.kt b/week06/app/src/main/java/com/example/flo/ui/theme/Theme.kt new file mode 100644 index 0000000..cc69550 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.flo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FLOTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/week06/app/src/main/java/com/example/flo/ui/theme/Type.kt b/week06/app/src/main/java/com/example/flo/ui/theme/Type.kt new file mode 100644 index 0000000..9a198f8 --- /dev/null +++ b/week06/app/src/main/java/com/example/flo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.flo.ui.theme + +import androidx.compose.material3.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( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/week06/app/src/main/res/drawable/btn_actionbar_instagram.png b/week06/app/src/main/res/drawable/btn_actionbar_instagram.png new file mode 100644 index 0000000..90bc027 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_actionbar_instagram.png differ diff --git a/week06/app/src/main/res/drawable/btn_arrow_black.png b/week06/app/src/main/res/drawable/btn_arrow_black.png new file mode 100644 index 0000000..cc38ca8 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_arrow_black.png differ diff --git a/week06/app/src/main/res/drawable/btn_color_selector.xml b/week06/app/src/main/res/drawable/btn_color_selector.xml new file mode 100644 index 0000000..3ecf8a7 --- /dev/null +++ b/week06/app/src/main/res/drawable/btn_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/drawable/btn_main_arrow_more.png b/week06/app/src/main/res/drawable/btn_main_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_main_arrow_more.png differ diff --git a/week06/app/src/main/res/drawable/btn_main_mike.png b/week06/app/src/main/res/drawable/btn_main_mike.png new file mode 100644 index 0000000..9bddec6 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_main_mike.png differ diff --git a/week06/app/src/main/res/drawable/btn_main_setting.png b/week06/app/src/main/res/drawable/btn_main_setting.png new file mode 100644 index 0000000..7a8d5d6 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_main_setting.png differ diff --git a/week06/app/src/main/res/drawable/btn_main_ticket.png b/week06/app/src/main/res/drawable/btn_main_ticket.png new file mode 100644 index 0000000..52b6d64 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_main_ticket.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplay_mvpause.png b/week06/app/src/main/res/drawable/btn_miniplay_mvpause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplay_mvpause.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplay_mvplay.png b/week06/app/src/main/res/drawable/btn_miniplay_mvplay.png new file mode 100644 index 0000000..d118677 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplay_mvplay.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplay_pause.png b/week06/app/src/main/res/drawable/btn_miniplay_pause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplay_pause.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplayer_go_list.png b/week06/app/src/main/res/drawable/btn_miniplayer_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplayer_go_list.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplayer_next.png b/week06/app/src/main/res/drawable/btn_miniplayer_next.png new file mode 100644 index 0000000..3aedba3 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplayer_next.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplayer_play.png b/week06/app/src/main/res/drawable/btn_miniplayer_play.png new file mode 100644 index 0000000..f619072 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplayer_play.png differ diff --git a/week06/app/src/main/res/drawable/btn_miniplayer_previous.png b/week06/app/src/main/res/drawable/btn_miniplayer_previous.png new file mode 100644 index 0000000..d0bf1f6 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_miniplayer_previous.png differ diff --git a/week06/app/src/main/res/drawable/btn_panel_play_large.png b/week06/app/src/main/res/drawable/btn_panel_play_large.png new file mode 100644 index 0000000..4ac7103 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_panel_play_large.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_eq_off.png b/week06/app/src/main/res/drawable/btn_player_eq_off.png new file mode 100644 index 0000000..f23d9c6 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_eq_off.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_go_list.png b/week06/app/src/main/res/drawable/btn_player_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_go_list.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_more.png b/week06/app/src/main/res/drawable/btn_player_more.png new file mode 100644 index 0000000..a8ad9e6 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_more.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_play.png b/week06/app/src/main/res/drawable/btn_player_play.png new file mode 100644 index 0000000..f6c3201 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_play.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_related.png b/week06/app/src/main/res/drawable/btn_player_related.png new file mode 100644 index 0000000..9026fe5 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_related.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_setting.png b/week06/app/src/main/res/drawable/btn_player_setting.png new file mode 100644 index 0000000..0df8f69 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_setting.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_unlike_off.png b/week06/app/src/main/res/drawable/btn_player_unlike_off.png new file mode 100644 index 0000000..b539504 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_unlike_off.png differ diff --git a/week06/app/src/main/res/drawable/btn_player_unlike_on.png b/week06/app/src/main/res/drawable/btn_player_unlike_on.png new file mode 100644 index 0000000..45a43ca Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_player_unlike_on.png differ diff --git a/week06/app/src/main/res/drawable/btn_playlist_select_off.png b/week06/app/src/main/res/drawable/btn_playlist_select_off.png new file mode 100644 index 0000000..62ef45c Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_playlist_select_off.png differ diff --git a/week06/app/src/main/res/drawable/btn_playlist_select_on.png b/week06/app/src/main/res/drawable/btn_playlist_select_on.png new file mode 100644 index 0000000..2d3b6af Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_playlist_select_on.png differ diff --git a/week06/app/src/main/res/drawable/btn_toggle_off.png b/week06/app/src/main/res/drawable/btn_toggle_off.png new file mode 100644 index 0000000..983360d Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_toggle_off.png differ diff --git a/week06/app/src/main/res/drawable/btn_toggle_on.png b/week06/app/src/main/res/drawable/btn_toggle_on.png new file mode 100644 index 0000000..fb609f4 Binary files /dev/null and b/week06/app/src/main/res/drawable/btn_toggle_on.png differ diff --git a/week06/app/src/main/res/drawable/discovery_banner_aos.jpg b/week06/app/src/main/res/drawable/discovery_banner_aos.jpg new file mode 100644 index 0000000..c905515 Binary files /dev/null and b/week06/app/src/main/res/drawable/discovery_banner_aos.jpg differ diff --git a/week06/app/src/main/res/drawable/ic_all_album_play.xml b/week06/app/src/main/res/drawable/ic_all_album_play.xml new file mode 100644 index 0000000..21f11cb --- /dev/null +++ b/week06/app/src/main/res/drawable/ic_all_album_play.xml @@ -0,0 +1,9 @@ + + + diff --git a/week06/app/src/main/res/drawable/ic_bottom_home_no_select.png b/week06/app/src/main/res/drawable/ic_bottom_home_no_select.png new file mode 100644 index 0000000..69a8ab6 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_bottom_home_no_select.png differ diff --git a/week06/app/src/main/res/drawable/ic_bottom_locker_no_select.png b/week06/app/src/main/res/drawable/ic_bottom_locker_no_select.png new file mode 100644 index 0000000..a67dec3 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_bottom_locker_no_select.png differ diff --git a/week06/app/src/main/res/drawable/ic_bottom_look_no_select.png b/week06/app/src/main/res/drawable/ic_bottom_look_no_select.png new file mode 100644 index 0000000..6c2f4f0 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_bottom_look_no_select.png differ diff --git a/week06/app/src/main/res/drawable/ic_bottom_search_no_select.png b/week06/app/src/main/res/drawable/ic_bottom_search_no_select.png new file mode 100644 index 0000000..a77b8c5 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_bottom_search_no_select.png differ diff --git a/week06/app/src/main/res/drawable/ic_check.xml b/week06/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..bec5bec --- /dev/null +++ b/week06/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,12 @@ + + + diff --git a/week06/app/src/main/res/drawable/ic_flo_logo.png b/week06/app/src/main/res/drawable/ic_flo_logo.png new file mode 100644 index 0000000..643224d Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_flo_logo.png differ diff --git a/week06/app/src/main/res/drawable/ic_launcher_background.xml b/week06/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/week06/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week06/app/src/main/res/drawable/ic_launcher_foreground.xml b/week06/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/week06/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/drawable/ic_main_facebook.png b/week06/app/src/main/res/drawable/ic_main_facebook.png new file mode 100644 index 0000000..83e9732 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_main_facebook.png differ diff --git a/week06/app/src/main/res/drawable/ic_main_instagram.png b/week06/app/src/main/res/drawable/ic_main_instagram.png new file mode 100644 index 0000000..398ce61 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_main_instagram.png differ diff --git a/week06/app/src/main/res/drawable/ic_main_twitter.png b/week06/app/src/main/res/drawable/ic_main_twitter.png new file mode 100644 index 0000000..6ddc68e Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_main_twitter.png differ diff --git a/week06/app/src/main/res/drawable/ic_main_youtube.png b/week06/app/src/main/res/drawable/ic_main_youtube.png new file mode 100644 index 0000000..0c4ec93 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_main_youtube.png differ diff --git a/week06/app/src/main/res/drawable/ic_my_like_off.png b/week06/app/src/main/res/drawable/ic_my_like_off.png new file mode 100644 index 0000000..c06e139 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_my_like_off.png differ diff --git a/week06/app/src/main/res/drawable/ic_my_like_on.png b/week06/app/src/main/res/drawable/ic_my_like_on.png new file mode 100644 index 0000000..22577c0 Binary files /dev/null and b/week06/app/src/main/res/drawable/ic_my_like_on.png differ diff --git a/week06/app/src/main/res/drawable/icon_browse_arrow_right.png b/week06/app/src/main/res/drawable/icon_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week06/app/src/main/res/drawable/icon_browse_arrow_right.png differ diff --git a/week06/app/src/main/res/drawable/img_album_exp.png b/week06/app/src/main/res/drawable/img_album_exp.png new file mode 100644 index 0000000..6e3f38a Binary files /dev/null and b/week06/app/src/main/res/drawable/img_album_exp.png differ diff --git a/week06/app/src/main/res/drawable/img_album_exp2.png b/week06/app/src/main/res/drawable/img_album_exp2.png new file mode 100644 index 0000000..28ea3ee Binary files /dev/null and b/week06/app/src/main/res/drawable/img_album_exp2.png differ diff --git a/week06/app/src/main/res/drawable/img_album_lp.png b/week06/app/src/main/res/drawable/img_album_lp.png new file mode 100644 index 0000000..29fb1b4 Binary files /dev/null and b/week06/app/src/main/res/drawable/img_album_lp.png differ diff --git a/week06/app/src/main/res/drawable/img_first_album_default.png b/week06/app/src/main/res/drawable/img_first_album_default.png new file mode 100644 index 0000000..926d34f Binary files /dev/null and b/week06/app/src/main/res/drawable/img_first_album_default.png differ diff --git a/week06/app/src/main/res/drawable/img_great_album_exp.jpg b/week06/app/src/main/res/drawable/img_great_album_exp.jpg new file mode 100644 index 0000000..33efe01 Binary files /dev/null and b/week06/app/src/main/res/drawable/img_great_album_exp.jpg differ diff --git a/week06/app/src/main/res/drawable/img_home_viewpager_exp.png b/week06/app/src/main/res/drawable/img_home_viewpager_exp.png new file mode 100644 index 0000000..da78032 Binary files /dev/null and b/week06/app/src/main/res/drawable/img_home_viewpager_exp.png differ diff --git a/week06/app/src/main/res/drawable/img_home_viewpager_exp2.png b/week06/app/src/main/res/drawable/img_home_viewpager_exp2.png new file mode 100644 index 0000000..50fa4be Binary files /dev/null and b/week06/app/src/main/res/drawable/img_home_viewpager_exp2.png differ diff --git a/week06/app/src/main/res/drawable/img_potcast_exp.png b/week06/app/src/main/res/drawable/img_potcast_exp.png new file mode 100644 index 0000000..50a46e0 Binary files /dev/null and b/week06/app/src/main/res/drawable/img_potcast_exp.png differ diff --git a/week06/app/src/main/res/drawable/img_video_exp.png b/week06/app/src/main/res/drawable/img_video_exp.png new file mode 100644 index 0000000..7f6b05f Binary files /dev/null and b/week06/app/src/main/res/drawable/img_video_exp.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_down.png b/week06/app/src/main/res/drawable/nugu_btn_down.png new file mode 100644 index 0000000..03a04c5 Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_down.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_pause_32.png b/week06/app/src/main/res/drawable/nugu_btn_pause_32.png new file mode 100644 index 0000000..9388aa3 Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_pause_32.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_play_32.png b/week06/app/src/main/res/drawable/nugu_btn_play_32.png new file mode 100644 index 0000000..b781e4c Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_play_32.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_random_inactive.png b/week06/app/src/main/res/drawable/nugu_btn_random_inactive.png new file mode 100644 index 0000000..fe4f880 Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_random_inactive.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_repeat_inactive.png b/week06/app/src/main/res/drawable/nugu_btn_repeat_inactive.png new file mode 100644 index 0000000..1e4044d Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_repeat_inactive.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_skip_next_32.png b/week06/app/src/main/res/drawable/nugu_btn_skip_next_32.png new file mode 100644 index 0000000..fc02f28 Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_skip_next_32.png differ diff --git a/week06/app/src/main/res/drawable/nugu_btn_skip_previous_32.png b/week06/app/src/main/res/drawable/nugu_btn_skip_previous_32.png new file mode 100644 index 0000000..03ec854 Binary files /dev/null and b/week06/app/src/main/res/drawable/nugu_btn_skip_previous_32.png differ diff --git a/week06/app/src/main/res/drawable/splash.xml b/week06/app/src/main/res/drawable/splash.xml new file mode 100644 index 0000000..da83aa4 --- /dev/null +++ b/week06/app/src/main/res/drawable/splash.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/drawable/textview_background_radius.xml b/week06/app/src/main/res/drawable/textview_background_radius.xml new file mode 100644 index 0000000..d250c1e --- /dev/null +++ b/week06/app/src/main/res/drawable/textview_background_radius.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/drawable/textview_background_select_color_radius.xml b/week06/app/src/main/res/drawable/textview_background_select_color_radius.xml new file mode 100644 index 0000000..8aaca4c --- /dev/null +++ b/week06/app/src/main/res/drawable/textview_background_select_color_radius.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/drawable/widget_black_play.png b/week06/app/src/main/res/drawable/widget_black_play.png new file mode 100644 index 0000000..0ec2700 Binary files /dev/null and b/week06/app/src/main/res/drawable/widget_black_play.png differ diff --git a/week06/app/src/main/res/layout/activity/activity_test.xml b/week06/app/src/main/res/layout/activity/activity_test.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/week06/app/src/main/res/layout/activity/activity_test.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/activity_main.xml b/week06/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..3f45054 --- /dev/null +++ b/week06/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/activity_song.xml b/week06/app/src/main/res/layout/activity_song.xml new file mode 100644 index 0000000..73a6cc4 --- /dev/null +++ b/week06/app/src/main/res/layout/activity_song.xml @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/activity_splash.xml b/week06/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 0000000..29ce312 --- /dev/null +++ b/week06/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_album.xml b/week06/app/src/main/res/layout/fragment_album.xml new file mode 100644 index 0000000..79aaf13 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_album.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_banner.xml b/week06/app/src/main/res/layout/fragment_banner.xml new file mode 100644 index 0000000..b7ef866 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_banner.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_detail.xml b/week06/app/src/main/res/layout/fragment_detail.xml new file mode 100644 index 0000000..151ebe6 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_detail.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_home.xml b/week06/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..90215e6 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_locker.xml b/week06/app/src/main/res/layout/fragment_locker.xml new file mode 100644 index 0000000..ebe1667 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_locker.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week06/app/src/main/res/layout/fragment_look.xml b/week06/app/src/main/res/layout/fragment_look.xml new file mode 100644 index 0000000..2d217e7 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_look.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_savedalbum.xml b/week06/app/src/main/res/layout/fragment_savedalbum.xml new file mode 100644 index 0000000..c395bf2 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_savedalbum.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/week06/app/src/main/res/layout/fragment_savedsong.xml b/week06/app/src/main/res/layout/fragment_savedsong.xml new file mode 100644 index 0000000..41fb837 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_savedsong.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_search.xml b/week06/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..301f760 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_song.xml b/week06/app/src/main/res/layout/fragment_song.xml new file mode 100644 index 0000000..439b6f3 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_song.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_songfile.xml b/week06/app/src/main/res/layout/fragment_songfile.xml new file mode 100644 index 0000000..05dca29 --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_songfile.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/fragment_video.xml b/week06/app/src/main/res/layout/fragment_video.xml new file mode 100644 index 0000000..70e650d --- /dev/null +++ b/week06/app/src/main/res/layout/fragment_video.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/item_album.xml b/week06/app/src/main/res/layout/item_album.xml new file mode 100644 index 0000000..99ae14e --- /dev/null +++ b/week06/app/src/main/res/layout/item_album.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/item_savedalbum.xml b/week06/app/src/main/res/layout/item_savedalbum.xml new file mode 100644 index 0000000..cabe757 --- /dev/null +++ b/week06/app/src/main/res/layout/item_savedalbum.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/item_savedsong.xml b/week06/app/src/main/res/layout/item_savedsong.xml new file mode 100644 index 0000000..fc292d7 --- /dev/null +++ b/week06/app/src/main/res/layout/item_savedsong.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/layout/item_song.xml b/week06/app/src/main/res/layout/item_song.xml new file mode 100644 index 0000000..bf9e8a2 --- /dev/null +++ b/week06/app/src/main/res/layout/item_song.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/menu/bottom_nav_menu.xml b/week06/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000..2b56b8c --- /dev/null +++ b/week06/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week06/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week06/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week06/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week06/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week06/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/week06/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/week06/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week06/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/week06/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/week06/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week06/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/week06/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/week06/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week06/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/week06/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/week06/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week06/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/week06/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/week06/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week06/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/week06/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/week06/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week06/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/week06/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/week06/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week06/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/week06/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/week06/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week06/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/week06/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/week06/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week06/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/week06/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/week06/app/src/main/res/raw/music_lilac.mp3 b/week06/app/src/main/res/raw/music_lilac.mp3 new file mode 100644 index 0000000..7c85690 Binary files /dev/null and b/week06/app/src/main/res/raw/music_lilac.mp3 differ diff --git a/week06/app/src/main/res/values/colors.xml b/week06/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..71cd486 --- /dev/null +++ b/week06/app/src/main/res/values/colors.xml @@ -0,0 +1,24 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FFD3D3D3 + #FF0000FF + #3f3fff + + #9cbee2 + #062342 + #424242 + #6bb2ff + + #00ff0000 + #3f3fff + #a8a8a8 + #3f3fff + #a8a8a8 + \ No newline at end of file diff --git a/week06/app/src/main/res/values/strings.xml b/week06/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..63f5ff1 --- /dev/null +++ b/week06/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + FLO + + Hello blank fragment + \ No newline at end of file diff --git a/week06/app/src/main/res/values/themes.xml b/week06/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e76a4bf --- /dev/null +++ b/week06/app/src/main/res/values/themes.xml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/xml/backup_rules.xml b/week06/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..4df9255 --- /dev/null +++ b/week06/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/week06/app/src/main/res/xml/data_extraction_rules.xml b/week06/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/week06/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week06/app/src/test/java/com/example/flo/ExampleUnitTest.kt b/week06/app/src/test/java/com/example/flo/ExampleUnitTest.kt new file mode 100644 index 0000000..d39df20 --- /dev/null +++ b/week06/app/src/test/java/com/example/flo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.flo + +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/week06/build.gradle.kts b/week06/build.gradle.kts new file mode 100644 index 0000000..952b930 --- /dev/null +++ b/week06/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} \ No newline at end of file diff --git a/week06/gradle.properties b/week06/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/week06/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. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-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/week06/gradle/libs.versions.toml b/week06/gradle/libs.versions.toml new file mode 100644 index 0000000..5332b17 --- /dev/null +++ b/week06/gradle/libs.versions.toml @@ -0,0 +1,34 @@ +[versions] +agp = "8.13.0" +kotlin = "2.0.21" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2024.09.00" +constraintlayout = "2.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } + diff --git a/week06/gradle/wrapper/gradle-wrapper.jar b/week06/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/week06/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week06/gradle/wrapper/gradle-wrapper.properties b/week06/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..af10ccc --- /dev/null +++ b/week06/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Sep 28 16:12:35 KST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week06/gradlew b/week06/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/week06/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/week06/gradlew.bat b/week06/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/week06/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/week06/settings.gradle.kts b/week06/settings.gradle.kts new file mode 100644 index 0000000..2a48c99 --- /dev/null +++ b/week06/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "FLO" +include(":app") + \ No newline at end of file diff --git a/week07/.gitignore b/week07/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/week07/.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/week07/.idea/.name b/week07/.idea/.name new file mode 100644 index 0000000..997352e --- /dev/null +++ b/week07/.idea/.name @@ -0,0 +1 @@ +FLO \ No newline at end of file diff --git a/week07/.idea/AndroidProjectSystem.xml b/week07/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/week07/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/week07/.idea/compiler.xml b/week07/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/week07/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week07/.idea/deploymentTargetSelector.xml b/week07/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..d2c491b --- /dev/null +++ b/week07/.idea/deploymentTargetSelector.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/week07/.idea/deviceManager.xml b/week07/.idea/deviceManager.xml new file mode 100644 index 0000000..eebfe8e --- /dev/null +++ b/week07/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week07/.idea/gradle.xml b/week07/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/week07/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week07/.idea/inspectionProfiles/Project_Default.xml b/week07/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/week07/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/week07/.idea/migrations.xml b/week07/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/week07/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/week07/.idea/misc.xml b/week07/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/week07/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/week07/.idea/runConfigurations.xml b/week07/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/week07/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week07/.idea/vcs.xml b/week07/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/week07/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/.gitignore b/week07/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/week07/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/week07/app/build.gradle.kts b/week07/app/build.gradle.kts new file mode 100644 index 0000000..16ba0c1 --- /dev/null +++ b/week07/app/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + + id("kotlin-kapt") + +} + +android { + namespace = "com.example.flo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.flo" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("androidx.fragment:fragment:1.8.9") + implementation("com.google.android.material:material:1.13.0") + implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("com.tbuonomo:dotsindicator:5.1.0") + implementation("androidx.recyclerview:recyclerview:1.4.0") + implementation("com.google.code.gson:gson:2.13.2") + implementation("androidx.core:core-splashscreen:1.0.1") + + //roomDB + implementation("androidx.room:room-ktx:2.8.3") + implementation("androidx.room:room-runtime:2.8.3") + //implementation("androidx.room:room-compiler:2.8.3") + kapt("androidx.room:room-compiler:2.8.3") +} \ No newline at end of file diff --git a/week07/app/proguard-rules.pro b/week07/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/week07/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/week07/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt b/week07/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..6dfac89 --- /dev/null +++ b/week07/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.flo + +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.flo", appContext.packageName) + } +} \ No newline at end of file diff --git a/week07/app/src/main/AndroidManifest.xml b/week07/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d61203a --- /dev/null +++ b/week07/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/activities/MainActivity.kt b/week07/app/src/main/java/com/example/flo/activities/MainActivity.kt new file mode 100644 index 0000000..9301a57 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/activities/MainActivity.kt @@ -0,0 +1,211 @@ +package com.example.flo.activities + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.home.HomeFragment +import com.example.flo.locker.LockerFragment +import com.example.flo.look.LookFragment +import com.example.flo.R +import com.example.flo.search.SearchFragment +import com.example.flo.data.Song +import com.example.flo.data.SongDatabase +import com.example.flo.databinding.ActivityMainBinding +import com.google.gson.Gson + +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + + private var song:Song = Song() + private var gson: Gson = Gson() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setTheme(R.style.Theme_FLO) + enableEdgeToEdge() + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + inputDummySongs() //더미 데이터 db에 삽입 + + //하단플레이어에 나오는 노래를 Song객체에 저장 -> roomDB로 대체 +// val song = Song( +// title = binding.mainMiniplayerTitleTv.text.toString(), +// singer = binding.mainMiniplayerSingerTv.text.toString(), +// second = 0, playTime = 60, isPlaying = false, music = "music_lilac" +// ) + + //하단의 플레이어를 누르면 송액티비티로 전환. 이때 sharedPreference에 노래의 id를 저장 + binding.mainPlayerCl.setOnClickListener { + //에디터를 만들고 + val editor = getSharedPreferences("song", MODE_PRIVATE).edit() + + //송의 id를 넣어준다. + editor.putInt("songId", song.id) + + //최종 커밋 + editor.apply() + + //인텐트는 단순 전환 기능만. sharedPrefernece와 DB가 알아서 해주니까. + val intent = Intent(this, SongActivity::class.java) + startActivity(intent) + } + + //실행 시 첫 화면 설정 -> 홈프래그먼트 + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + + //BottomNavigationView를 눌렀을 때 Fragment 변경하기 + binding.mainBnv.setOnItemSelectedListener { item -> + when (item.itemId) { + //매인 화면 + R.id.homeFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + true + } + //둘러보기 화면 + R.id.lookFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LookFragment()) + .commit() + true + } + //검색 화면 + R.id.searchFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, SearchFragment()) + .commit() + true + } + //보관함 화면 + R.id.lockerFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LockerFragment()) + .commit() + true + } + else -> false + } + } + } + + //메인 액티비티가 시작될 때-> sharedprference에서 id값을 가져와서 DB에서 해당 id에 해당하는 song을 가져옴 + override fun onStart() { + super.onStart() + //sharedprference에서 id값을 가져옴 + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId", 0) + + //DB인스턴스를 만들고 + val songDB = SongDatabase.getInstance(this)!! + + //DB에서 해당 id에 해당하는 song을 가져옴 + song = if (songId==0) { + songDB.songDao().getSong(1) + } else { + songDB.songDao().getSong(songId) + } + + Log.d("song ID", song.id.toString()) // 디버깅 + + //가져온 송 데이터를 뷰바인딩 + setMiniPlayer(song) + } + + private fun setMiniPlayer(song: Song){ + binding.mainMiniplayerTitleTv.text = song.title + binding.mainMiniplayerSingerTv.text = song.singer + binding.mainProgressSb.progress = (song.second*100000)/song.playTime + } + + //DB에 데이터가 없다면 더미 데이터를 넣는 작업 + private fun inputDummySongs() { + val songDB = SongDatabase.getInstance(this)!! + val songs = songDB.songDao().getSongs() + + //데이터가 있다면 종료 + if (songs.isNotEmpty()) return + + //데이터가 없을 경우 + songDB.songDao().insert( + Song( + title = "Lilac", + singer = "아이유 (IU)", + second = 0, + playTime = 230, + isPlaying = false, + music = "music_lilac", + coverImg = R.drawable.img_album_exp2, + isLike = false, + albumIdx = 1 + ) + ) + + songDB.songDao().insert( + Song( + title = "BBoom BBoom", + singer = "모모랜드 (MOMOLAND)", + second = 0, + playTime = 240, + isPlaying = false, + music = "music_bboom", + coverImg = R.drawable.img_great_album_exp, + isLike = false, + albumIdx = 2 + ) + ) + + songDB.songDao().insert( + Song( + title = "Butter", + singer = "방탄소년단 (BTS)", + second = 0, + playTime = 180, + isPlaying = false, + music = "music_butter", + coverImg = R.drawable.img_album_exp, + isLike = false, + albumIdx = 3 + ) + ) + + songDB.songDao().insert( + Song( + title = "IRIS OUT", + singer = "요네즈 켄시 (Kenshi Yonezu)", + second = 0, + playTime = 155, + isPlaying = false, + music = "music_irisout", + coverImg = R.drawable.img_iris_album_exp, + isLike = false, + albumIdx = 4 + ) + ) + + songDB.songDao().insert( + Song( + title = "Oort Cloud (오르트 구름)", + singer = "윤하 (YOUNHA)", + second = 0, + playTime = 210, + isPlaying = false, + music = "music_oortcloud", + coverImg = R.drawable.img_oort_album_exp, + isLike = false, + albumIdx = 5 + ) + ) + + //DB에 데이터가 잘 들어갔는지 로그로 확인 + val _songs = songDB.songDao().getSongs() //테이블의 모든 송을 가져옴 + Log.d("DB data", _songs.toString()) //DB에 데이터가 잘 들어갔는지 확인 + + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/activities/SongActivity.kt b/week07/app/src/main/java/com/example/flo/activities/SongActivity.kt new file mode 100644 index 0000000..0d04e5c --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/activities/SongActivity.kt @@ -0,0 +1,262 @@ +package com.example.flo.activities + +import android.graphics.Color +import android.graphics.PorterDuff +import android.media.MediaPlayer +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.databinding.ActivitySongBinding +import com.example.flo.data.Song +import com.example.flo.data.SongDatabase +import com.google.gson.Gson +import com.example.flo.R + +class SongActivity : AppCompatActivity() { + private lateinit var binding: ActivitySongBinding + //lateinit var song: Song // 첫 isPlaying은 False + + lateinit var timer: Timer + private var mediaPlayer: MediaPlayer? = null + private var gson: Gson = Gson() + + // 재생할 "노래 목록(플레이리스트)"을 담기 위한 리스트. + // 여러 곡을 담고 이전곡/다음곡으로 이동할 수 있게 하기 위해 존재 + val songs = arrayListOf() + lateinit var songDB: SongDatabase // DB인스턴스 선언. DB CRUD작업을 할 때는 필수인 것 같다. + var nowPos = 0 //현재 곡을 가리키는 전역변수 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySongBinding.inflate(layoutInflater) + setContentView(binding.root) + initPlayList() //DB에서 모든 송들을 가져와 songs에 저장 + initSong() //송 데이터 받아와 실행 + initClickListener() + //setPlayer(songs[nowPos]) + + //반복재생 + var isRoop = false + binding.songRepeatIv.setOnClickListener { + if (!isRoop) { + binding.songRepeatIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + isRoop = true + } else { + binding.songRepeatIv.clearColorFilter() + isRoop = false + } + } + //전체재생(랜덤재생인듯?) + var willPlayAll = false + binding.songRandomIv.setOnClickListener { + if (!willPlayAll) { + binding.songRandomIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + willPlayAll = true + } else { + binding.songRandomIv.clearColorFilter() + willPlayAll = false + } + } + } + + // 사용자가 포커스를 잃었을 때 음악 중지 + override fun onPause() { + super.onPause() + setPlayerStatus(false) + songs[nowPos].second = ((binding.songProgressSb.progress * songs[nowPos].playTime) / 100) / 1000 + val sharedPreferences = getSharedPreferences("song", MODE_PRIVATE) + val editor = sharedPreferences.edit() //에디터 + + editor.putInt("songId", songs[nowPos].id) + + editor.apply() //꼭 쓰기!! 깃에서 push와 같음 + } + + //앱이 꺼질때 스레드 종료 + override fun onDestroy() { + super.onDestroy() + timer.interrupt() +// mediaPlayer?.release() // 미디어플레이어가 갖고 있던 리소스 해제 +// mediaPlayer? = null //미디어 플레이어 해제 + } + + //DB에서 모든 송들을 가져와 songs에 저장 + private fun initPlayList(){ + songDB = SongDatabase.getInstance(this)!! + songs.addAll(songDB.songDao().getSongs()) + } + + private fun initClickListener()= with(binding){ + //우측 상단 버튼 누르면 액티비티 종료 + songDownIb.setOnClickListener{ + finish() + } + //재생, 일시정지 + songMiniplayerIv.setOnClickListener { + setPlayerStatus(true) + } + songPauseIv.setOnClickListener { + setPlayerStatus(false) + } + + //이전곡/다음곡 + songPreviousIv.setOnClickListener { + moveSong(-1) + } + songNextIv.setOnClickListener { + moveSong(+1) + } + + songLikeIv.setOnClickListener { + setLike(songs[nowPos].isLike) + } + } + + //SharedPreference에서 id값을 받아와서 songid를 통해서 songs와 비교해서 index값을 구하는 함수 + private fun initSong() { + //sharedpreference에서 id를 받아옴 + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId", 0) + + //송의 id를 nowPos에 저장 + nowPos = getPlayingSongPosition(songId) + Log.d("now Song ID", songs[nowPos].id.toString()) + startTimer() //타이머 시작 + //뷰 렌더링, 미디어플레이어 시작 + setPlayer(songs[nowPos]) + } + + // + private fun getPlayingSongPosition(songId: Int): Int { + for(i in 0 until songs.size) { + if(songs[i].id==songId) { + return i + } + } + return 0 + } + + //좋아요 버튼 이벤트 + private fun setLike(isLike: Boolean) { + songs[nowPos].isLike = !isLike + songDB.songDao().updateIsLikeById(!isLike,songs[nowPos].id) + + if (!isLike) { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_on) + }else { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + } + + private fun moveSong(direct: Int) { + if (nowPos + direct<0) { + Toast.makeText(this, "first song", Toast.LENGTH_SHORT).show() + return + } + if (nowPos+direct >= songs.size) { + Toast.makeText(this, "last song", Toast.LENGTH_SHORT).show() + return + } + nowPos += direct + timer.interrupt() + + mediaPlayer?.release() + mediaPlayer = null + + setPlayer(songs[nowPos]) //뷰렌더링, 노래 시작 + startTimer() // ✅ 새 MediaPlayer로 세팅된 후 타이머 시작 + Log.d("현재 곡", songs[nowPos].music) + + } + + //송 데이터를 뷰에 렌더링하는 함수 + private fun setPlayer(song: Song) { + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + binding.songStartTimeTv.text = String.format("%02d:%02d", song.second / 60, song.second % 60) + binding.songEndTimeTv.text = String.format("%02d:%02d", song.playTime / 60, song.playTime % 60) + binding.songAlbumIv.setImageResource(song.coverImg!!) + binding.songProgressSb.progress = (song.second * 1000 / song.playTime) + + val music = resources.getIdentifier(song.music, "raw", this.packageName) + mediaPlayer = MediaPlayer.create(this, music) + + //좋아요 + if (song.isLike) { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_on) + }else { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + setPlayerStatus(song.isPlaying) + } + + //재생, 일시정지 버튼 로직 구현 함수 + private fun setPlayerStatus(isPlaying: Boolean) { + songs[nowPos].isPlaying = isPlaying + timer.isPlaying = isPlaying + if (isPlaying) { + binding.songMiniplayerIv.visibility = View.GONE + binding.songPauseIv.visibility = View.VISIBLE + mediaPlayer?.start() + } else { + binding.songMiniplayerIv.visibility = View.VISIBLE + binding.songPauseIv.visibility = View.GONE + if(mediaPlayer?.isPlaying==true) { // + mediaPlayer?.pause() + } + } + } + + //타이머 시작 함수 + private fun startTimer() { + timer = Timer(songs[nowPos].playTime, songs[nowPos].isPlaying) + timer.start() + } + + //재시작 함수 + private fun restart() { + timer.interrupt() // 기존 타이머 스레드 종료 + songs[nowPos].second = 0 // 곡 시간 초기화 + songs[nowPos].isPlaying = true // 재생 상태 설정 + setPlayer(songs[nowPos]) // 송 데이터를 다시 세팅 -> setPlayerStatus함수 호출 -> true이므로 ||버튼이 나옴 + startTimer() // 새로운 타이머 스레드를 생성하고 실행 + } + inner class Timer(private val playTime: Int, var isPlaying: Boolean = true) : Thread() { + private var second: Int = 0 // 타이머 텍스트뷰에 사용할 용도 + private var mills: Float = 0f // 경과된 시간 누적용, 시크바에 사용할 용도 + override fun run() { + super.run() + try { + while (true) { + if (second >= playTime) { + break + } + //노래가 재생중일동안 실행 + if (isPlaying) { + sleep(50) + mills += 50 + //시크바 갱신 + runOnUiThread { + binding.songProgressSb.progress = ((mills / playTime) * 100).toInt() + } + //타이머 텍스트뷰 갱신 + if (mills % 1000 == 0f) { + runOnUiThread { + binding.songStartTimeTv.text = + String.format("%02d:%02d", second / 60, second % 60) + } + second++ + } + } + } + } catch (e: InterruptedException) { //액티비티가 종료되었을 경우 스레드 종료 + Log.d("Song", "스레드가 죽었습니다. ${e.message}") + } + } + } + +} diff --git a/week07/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt b/week07/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt new file mode 100644 index 0000000..0ddfa14 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt @@ -0,0 +1,71 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.R +import com.example.flo.activities.MainActivity +import com.example.flo.databinding.FragmentAlbumBinding +import com.example.flo.data.Album +import com.example.flo.data.SongDatabase +import com.example.flo.home.HomeFragment +import com.google.android.material.tabs.TabLayoutMediator +import com.google.gson.Gson + +class AlbumFragment : Fragment() { + lateinit var binding: FragmentAlbumBinding + private var gson: Gson = Gson() + + private val information = arrayListOf("수록곡", "상세정보", "영상") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentAlbumBinding.inflate(inflater, container, false) + +// val albumJson = arguments?.getString("album") +// val album = gson.fromJson(albumJson, Album::class.java) + + val album = getAlbumDatas() //전달받은 앨범 데이터 가져옴 + setInit(album) //앨범 정보 뷰바인딩 + + //홈프래그먼트로의 화면전환 + binding.albumBackIv.setOnClickListener { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commitAllowingStateLoss() + } + + //뷰페이저 어댑터 객체 생성시 앨범 id를 넘겨줌 -> 송프래그먼트(수록곡) 정보를 넘겨줌 + val albumAdapter = AlbumVPAdapter(this, album.id) + binding.albumContentVp.adapter = albumAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.albumContentTb, binding.albumContentVp) { tap, position -> + tap.text = information[position] + }.attach() + + return binding.root + + } + private fun getAlbumDatas(): Album { + // 1. arguments로 전달받은 albumId 꺼내기 + val albumId = arguments?.getInt("albumId", 0) ?: 0 + // 2. DB에서 앨범 조회 + val songDB = SongDatabase.getInstance(requireContext())!! + val album = songDB.albumDao().getAlbum(albumId) + return album + } + + //앨범 정보 뷰바인딩 + private fun setInit(album: Album) { + binding.albumAlbumIv.setImageResource(album.coverImg!!) + binding.albumMusicTitleTv.text = album.title.toString() + binding.albumSingerNameTv.text = album.singer.toString() + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt b/week07/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt new file mode 100644 index 0000000..311b467 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt @@ -0,0 +1,27 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.example.flo.data.Album +import com.google.gson.Gson + +//수록곡 전달을 위해 인자 하나 더 추가 -> 나 이거 왜써놓은거지 ㅋㅋ +class AlbumVPAdapter(fragment: Fragment, private val albumId: Int) : FragmentStateAdapter(fragment){ + + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + val bundle = Bundle().apply { + putInt("albumId", albumId) + } + + return when (position) { + 0 -> SongFragment().apply { arguments = bundle } + 1 -> DetailFragment().apply { arguments = bundle } + else -> VideoFragment().apply { arguments = bundle } + } + + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt b/week07/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt new file mode 100644 index 0000000..cea0ae4 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt @@ -0,0 +1,37 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentDetailBinding + +class DetailFragment : Fragment() { + lateinit var binding : FragmentDetailBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailBinding.inflate(inflater, container, false) + + //앨범프래그먼트에서 전달한 데이터를 받음 + val singerName = arguments?.getString("singerName") + val albumTitle = arguments?.getString("albumTitle") + + Log.d("DetailFragment", "받은 가수 이름: $singerName") + Log.d("DetailFragment", "받은 앨범 제목: $albumTitle") + + + binding.singerNameTv.text = singerName + binding.albumNameTv.text = albumTitle + + + return binding.root + } + + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt b/week07/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt new file mode 100644 index 0000000..c790c17 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt @@ -0,0 +1,49 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.R +import com.example.flo.databinding.FragmentSongBinding +import com.example.flo.data.Album +import com.example.flo.data.Song +import com.example.flo.data.SongDatabase +import com.google.gson.Gson + +class SongFragment : Fragment() { + lateinit var binding: FragmentSongBinding + private var songDatas = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentSongBinding.inflate(inflater, container, false) + + // 전달받은 albumId 꺼내기 + val albumId = arguments?.getInt("albumId", 0) ?: 0 + + // DB에서 수록곡 조회 + val songDB = SongDatabase.getInstance(requireContext())!! + songDatas = ArrayList(songDB.songDao().getSongsInAlbum(albumId)) + + // 리사이클러뷰 어댑터 등록 + val songRVAdapter = SongRVAdapter(songDatas) + binding.albumTrackRv.adapter = songRVAdapter + binding.albumTrackRv.layoutManager = LinearLayoutManager(context) + + // 믹스 토글 버튼 + var isON = false + binding.songMixoffTg.setOnClickListener { + isON = !isON + binding.songMixoffTg.setImageResource( + if (isON) R.drawable.btn_toggle_on else R.drawable.btn_toggle_off + ) + } + return binding.root + } +} diff --git a/week07/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt b/week07/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt new file mode 100644 index 0000000..6fe7ab1 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt @@ -0,0 +1,40 @@ +package com.example.flo.albumfrag + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSongBinding +import com.example.flo.data.Song + +class SongRVAdapter(private var songList: ArrayList): RecyclerView.Adapter(){ + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSongBinding = ItemSongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songList[position]) + } + + override fun getItemCount():Int = songList.size + + inner class ViewHolder(var binding: ItemSongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListOrderTv.text = song.num + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt b/week07/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt new file mode 100644 index 0000000..d337c6a --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt @@ -0,0 +1,23 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentVideoBinding + +class VideoFragment : Fragment() { + lateinit var binding : FragmentVideoBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentVideoBinding.inflate(inflater, container, false) + + return binding.root + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/data/Album.kt b/week07/app/src/main/java/com/example/flo/data/Album.kt new file mode 100644 index 0000000..d772b4f --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/data/Album.kt @@ -0,0 +1,15 @@ +package com.example.flo.data + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "AlbumTable") +data class Album ( + @PrimaryKey(autoGenerate = true) + var id: Int = 0, +// var info: String = "", + var title: String = "", + var singer: String = "", + var isLike: Boolean = false, + var coverImg: Int? = null, +) \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/data/AlbumDao.kt b/week07/app/src/main/java/com/example/flo/data/AlbumDao.kt new file mode 100644 index 0000000..9db5375 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/data/AlbumDao.kt @@ -0,0 +1,22 @@ +package com.example.flo.data + +import androidx.room.* +@Dao +interface AlbumDao { + @Insert + fun insert(album: Album) + + @Update + fun update(album: Album) + + @Delete + fun delete(album: Album) + + @Query("SELECT * FROM AlbumTable") // 테이블의 모든 값을 가져와라 + fun getAlbums(): List + + //WHERE을 조건문처럼 사용, id값으로 해당하는 앨범을 받아옴 + @Query("SELECT*FROM AlbumTable WHERE id=:id") + fun getAlbum(id: Int): Album + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/data/Song.kt b/week07/app/src/main/java/com/example/flo/data/Song.kt new file mode 100644 index 0000000..36f2e3c --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/data/Song.kt @@ -0,0 +1,22 @@ +package com.example.flo.data + +import androidx.room.Entity +import androidx.room.PrimaryKey + +//제목, 가수, 사진, 재생시간, 현재 재생시간, isPlaying(재생 되고 있는지) + +@Entity(tableName = "SongTable") +data class Song( + val num : String? = "01", + var title: String = "", + var singer: String = "", + var second: Int = 0, + var playTime: Int = 0, + var isPlaying: Boolean = false, + var music: String = "", + var coverImg: Int? = null, + var isLike: Boolean = false, + var albumIdx: Int? = 0 +){ + @PrimaryKey(autoGenerate = true) var id: Int = 0 +} diff --git a/week07/app/src/main/java/com/example/flo/data/SongDao.kt b/week07/app/src/main/java/com/example/flo/data/SongDao.kt new file mode 100644 index 0000000..258864e --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/data/SongDao.kt @@ -0,0 +1,39 @@ +package com.example.flo.data + +import android.R +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update + +@Dao +interface SongDao { + @Insert + fun insert(song: Song) + @Update + fun update(song: Song) + + @Delete + fun delete(song: Song) + + //SELECT:데이터를 선택해서 가져와라, *: 모든 데이터를, FROM: 어디서 가져올지 + @Query("SELECT*FROM SongTable") + fun getSongs(): List + + //WHERE을 조건문처럼 사용, id값으로 해당하는 송을 받아옴 + @Query("SELECT*FROM SongTable WHERE id=:id") + fun getSong(id: Int): Song + + //좋아요를 했을 때 DB에 곡의 id를 추가하는 함수 + @Query("UPDATE SongTable SET isLike= :isLike WHERE id = :id") + fun updateIsLikeById(isLike: Boolean, id: Int) + + //DB에서 좋아요 된 곡들을 가져오는 함수 + @Query("SELECT*FROM SongTable WHERE isLike = :isLike") + fun getLikedSongs(isLike: Boolean): List + + @Query("SELECT * FROM SongTable WHERE albumIdx = :albumIdx") + fun getSongsInAlbum(albumIdx: Int): List + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/data/SongDatabase.kt b/week07/app/src/main/java/com/example/flo/data/SongDatabase.kt new file mode 100644 index 0000000..ec7e230 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/data/SongDatabase.kt @@ -0,0 +1,31 @@ +package com.example.flo.data + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [Song::class, Album::class], version = 2) +abstract class SongDatabase: RoomDatabase() { + abstract fun songDao(): SongDao + abstract fun albumDao(): AlbumDao + companion object { + private var instance: SongDatabase? = null + + @Synchronized + fun getInstance(context: Context): SongDatabase? { + if (instance==null) { + synchronized(SongDatabase::class){ + instance = Room.databaseBuilder( + context.applicationContext, + SongDatabase::class.java, + name = "song-database" //다른 데이터 베이스랑 이름 겹치면 꼬임 + ).fallbackToDestructiveMigration().allowMainThreadQueries().build() //원래는 메인 스레드로 하는 게 아님 + } + } + + return instance + } + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt b/week07/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt new file mode 100644 index 0000000..b2daa62 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt @@ -0,0 +1,63 @@ +package com.example.flo.home + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemAlbumBinding +import com.example.flo.data.Album + +class AlbumRVAdapter(private var albumList: ArrayList): RecyclerView.Adapter() { + + //리스너 인터페이스 정의 + interface MyItemClickListener { + fun onItemClick(album: Album) +// fun onRemoveAlbum(position: Int) + } + private lateinit var myItemClickListener: MyItemClickListener + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun addItem(album: Album) { + albumList.add(album) + notifyDataSetChanged() + } + +// fun removeItem(position: Int) { +// albumList.removeAt(position) +// notifyDataSetChanged() +// } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemAlbumBinding = ItemAlbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + //아이템 뷰 객체를 던져줌 + return ViewHolder(binding) + } + + // 뷰홀더에 데이터를 바인딩해줄때마다 호출, 클릭 이벤트 작성 + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.itemView.setOnClickListener { myItemClickListener.onItemClick(albumList[position]) } + //holder.binding.itemAlbumTitleTv.setOnClickListener { myItemClickListener.onRemoveAlbum(position) } + } + + //데이터 세트 크기를 알려줌. 리사이클러뷰의 끝이 어딘지 + override fun getItemCount(): Int = albumList.size + + //뷰홀더 클래스 + inner class ViewHolder(var binding: ItemAlbumBinding): RecyclerView.ViewHolder(binding.root) { + + fun bind(album: Album) { + binding.itemAlbumTitleTv.text = album.title + binding.itemAlbumSingerTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImg!!) + } + + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/home/BannerFragment.kt b/week07/app/src/main/java/com/example/flo/home/BannerFragment.kt new file mode 100644 index 0000000..145a504 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/home/BannerFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentBannerBinding + +//인자를 넣어서 새로운 배너 프래그먼트 추가 +class BannerFragment(val imgRes : Int) : Fragment() { + lateinit var binding : FragmentBannerBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBannerBinding.inflate(inflater, container, false) + + binding.bannerImageIv.setImageResource(imgRes) + + return binding.root + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt b/week07/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt new file mode 100644 index 0000000..e406726 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt @@ -0,0 +1,23 @@ +package com.example.flo.home + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class BannerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + + private val fragmentlist : ArrayList = ArrayList() + + override fun getItemCount(): Int { // 데이터를 몇개를 전달할 것이냐 + return fragmentlist.size + } + + override fun createFragment(position: Int): Fragment = fragmentlist[position] + + //리스트에 추가하는 함수 + fun addFragment(fragment: Fragment) { + fragmentlist.add(fragment) + notifyItemInserted(fragmentlist.size - 1) //뷰페이저에게 새로운 값이 추가가 됐다고 알림 + } + + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/home/HomeFragment.kt b/week07/app/src/main/java/com/example/flo/home/HomeFragment.kt new file mode 100644 index 0000000..9e85999 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/home/HomeFragment.kt @@ -0,0 +1,103 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.viewpager2.widget.ViewPager2 +import com.example.flo.albumfrag.AlbumFragment +import com.example.flo.R +import com.example.flo.databinding.FragmentHomeBinding +import com.example.flo.data.Album +import com.example.flo.data.Song +import com.example.flo.activities.MainActivity +import com.example.flo.data.SongDatabase +import com.google.gson.Gson + +class HomeFragment : Fragment() { + lateinit var binding: FragmentHomeBinding + private var albumDatas = ArrayList() // 오늘의 앨범에 나올 앨범들을 위함 + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentHomeBinding.inflate(inflater, container, false) + inputDummyAlbums() //DB에 앨범데이터 삽입(초기설정용) + + albumDatas = getTodayAlbumDatas() //DB에서 앨범 리스트 가져오기 + + //리사이클러뷰 어댑터 등록 (앨범 나열) + val albumRVAdapter = AlbumRVAdapter(albumDatas) + binding.homeTodayMusicAlbumRv.adapter = albumRVAdapter + + //리사이클러뷰의 레이아웃 매니저 설정 + binding.homeTodayMusicAlbumRv.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, false + ) + + //등록한 리사이클러뷰 어댑터 객체에 클릭리스너 세팅 + albumRVAdapter.setMyItemClickListener(object : AlbumRVAdapter.MyItemClickListener { + override fun onItemClick(album: Album) { + changeAlbumFragment(album) //앨범프래그먼트로 전환 시 클릭한 앨범의 id 전달 + } + +// override fun onRemoveAlbum(position: Int) { +// albumRVAdapter.removeItem(position) +// } + }) + + //뷰페이저2에 광고 배너들 연결 + val bannerAdapter = BannerVPAdapter(this) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + binding.homeBannerVp.adapter = bannerAdapter + + //광고 뷰 페이저가 좌우로 스크롤 될수 있도록 지정 + binding.homeBannerVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + return binding.root + } + + private fun inputDummyAlbums() { + //DB인스턴스를 만든다 + val songDB = SongDatabase.getInstance(requireContext())!! + val albums = songDB.albumDao().getAlbums() + + //앨범 데이터가 있다면 종료 + if (albums.isNotEmpty()) return + + //데이터가 없을 경우 -> 앨범 데이터 삽입 + songDB.albumDao().apply { + insert(Album(1, "LILAC", "아이유 (IU)", false, R.drawable.img_album_exp2)) + insert(Album(2, "GREAT!", "모모랜드 (MOMOLAND)", false, R.drawable.img_great_album_exp)) + insert(Album(3, "Butter", "방탄소년단 (BTS)", false, R.drawable.img_album_exp)) + insert(Album(4, "LOST CORNER", "요네즈 켄시 (Kenshi Yonezu)", false, R.drawable.img_iris_album_exp)) + insert(Album(5, "END THEORY", "윤하 (YOUNHA)", false, R.drawable.img_oort_album_exp)) + } + } + private fun getTodayAlbumDatas(): ArrayList { + val songDB = SongDatabase.getInstance(requireContext())!! + albumDatas = ArrayList(songDB.albumDao().getAlbums()) // DB에서 앨범 리스트 가져오기 + return albumDatas + } + + //앨범프래그먼트로 전환 시 클릭한 앨범의 id 전달 + private fun changeAlbumFragment(album: Album) { + val bundle = Bundle().apply { + putInt("albumId", album.id) // ID만 전달 + } + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, AlbumFragment().apply { arguments = bundle }) + .commitAllowingStateLoss() + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/LockerFragment.kt b/week07/app/src/main/java/com/example/flo/locker/LockerFragment.kt new file mode 100644 index 0000000..f040bf5 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/LockerFragment.kt @@ -0,0 +1,40 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentLockerBinding +import com.example.flo.data.Song +import com.google.android.material.tabs.TabLayoutMediator + +class LockerFragment : Fragment() { + lateinit var binding: FragmentLockerBinding +// private var songDatas = ArrayList< SavedSong>() + + private val information = arrayListOf("저장한 곡", "음악피일", "저장앨범") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLockerBinding.inflate(inflater, container, false) + + //뷰페이저 어댑터 등록 + val lockerAdapter = LockerVPAdapter(this) + binding.lockerContentVp.adapter = lockerAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.lockerContentTb, binding.lockerContentVp) { tap, position -> + tap.text = information[position] + + }.attach() + return binding.root + } + + private fun setInit(song: Song) { + + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt b/week07/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt new file mode 100644 index 0000000..13e654d --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt @@ -0,0 +1,42 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.data.Song + +class LockerRVAdapter(private var songs: ArrayList) : RecyclerView.Adapter() + { + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.itemView.setOnClickListener { + + } + } + + override fun getItemCount(): Int = songs.size + + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt b/week07/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt new file mode 100644 index 0000000..9e8f745 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt @@ -0,0 +1,31 @@ +package com.example.flo.locker + +import android.util.Log +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class LockerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + Log.d("FragmentCheck2", "createfrag") +// val gson = Gson() +// val songJson = gson.toJson(song) + + return when(position) { + 0 -> { + SavedsongFragment() + + } + 1 -> { + SongfileFragment() + } + else -> { + SavedalbumFragment() + } + } + + } + + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt b/week07/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt new file mode 100644 index 0000000..4ba78b9 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt @@ -0,0 +1,57 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedalbumBinding +import com.example.flo.data.Album + +class SavedAlbumRVAdapter(private var albumList: ArrayList): + RecyclerView.Adapter() { + + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveAlbum(position: Int) + } + + private lateinit var myItemClickListener: SavedAlbumRVAdapter.MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun removeAlbum(position: Int) { + albumList.removeAt(position) + notifyDataSetChanged() + } + + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): SavedAlbumRVAdapter.ViewHolder { + val binding = ItemSavedalbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: SavedAlbumRVAdapter.ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.binding.albumCrudIv.setOnClickListener { myItemClickListener.onRemoveAlbum(position) } + } + + override fun getItemCount(): Int = albumList.size + + inner class ViewHolder(var binding: ItemSavedalbumBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(album: Album) { + binding.albumTitleTv.text = album.title + binding.albumSingerNameTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImg!!) + //binding.albumInformationTv.text = album.information + } + + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt b/week07/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt new file mode 100644 index 0000000..03854ff --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt @@ -0,0 +1,70 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.R +import com.example.flo.databinding.FragmentSavedalbumBinding +import com.example.flo.data.Album +import com.example.flo.data.Song +import com.google.gson.Gson + +class SavedalbumFragment : Fragment() { + + //갱신 + lateinit var binding : FragmentSavedalbumBinding + private var albumDatas = ArrayList() + + override fun onCreateView( + + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedalbumBinding.inflate(inflater, container, false) +// albumDatas.apply { +// add( +// Album( +// title = "Butter", +// singer = "방탄소년단(BTS)", +// coverImage = R.drawable.img_album_exp, +// information = "2021.03.25|정규|댄스 팝" +// ) +// ) +// add( +// Album( +// title = "Great!", +// singer = "모모랜드(MOMOLAND)", +// coverImage = R.drawable.img_great_album_exp, +// information = "2021.03.25|정규|댄스 팝" +// ) +// ) +// } +// +// val savedAlbumRVAdapter = SavedAlbumRVAdapter(albumDatas) +// binding.savedAlbumRv.adapter = savedAlbumRVAdapter +// +// binding.savedAlbumRv.layoutManager = LinearLayoutManager( +// context, LinearLayoutManager.VERTICAL, false +// ) +// +// //어댑터객체에 클릭 리스너 세팅 +// savedAlbumRVAdapter.setMyItemClickListener(object: +// SavedAlbumRVAdapter.MyItemClickListener { +// override fun onRemoveAlbum(position: Int) { +// savedAlbumRVAdapter.removeAlbum(position) +// } +// } +// ) +// +// +// val songJson = arguments?.getString("song") +// val song = Gson().fromJson(songJson, Song::class.java) + + return binding.root + } + +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt b/week07/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt new file mode 100644 index 0000000..17c02e3 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt @@ -0,0 +1,68 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.R +import com.example.flo.databinding.FragmentSavedsongBinding +import com.example.flo.data.Song +import com.example.flo.data.SongDatabase + +class SavedsongFragment : Fragment() { + + lateinit var binding : FragmentSavedsongBinding + lateinit var songDB: SongDatabase + //private var savedSongList = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedsongBinding.inflate(inflater, container, false) + songDB = SongDatabase.getInstance(requireContext())!! + + // 곡 리스트 더미 데이터 생성 +// savedSongList.apply { +// add(SavedSong(R.drawable.img_album_exp, "Butter", "방탄소년단 (BTS)")) +// add(SavedSong(R.drawable.img_album_exp2, "아이와 나의 바다", "아이유 (IU)")) +// add(SavedSong(R.drawable.img_first_album_default, "운명 교향곡", "베토벤 (Beethoven)")) +// } + + //리사이클러뷰 어댑터 등록 +// val savedsongRVAdapter = SavedsongRVAdapter() +// binding.savedSongRv.adapter = savedsongRVAdapter + + + //등록한 리사이클러뷰 어댑터 객체에 리스너 세팅 +// savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { +// override fun onRemoveSong(position: Int) { +// savedsongRVAdapter.removeItem(position) +// } +// }) + + return binding.root + } + + override fun onStart() { + super.onStart() + initRecyclerView() + } + + private fun initRecyclerView() { + //리사이클러뷰 어댑터 등록 + val savedsongRVAdapter = SavedsongRVAdapter() + savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { + override fun onRemoveSong(songId: Int) { + songDB.songDao().updateIsLikeById(false, songId) + } + }) + + binding.savedSongRv.adapter = savedsongRVAdapter + + savedsongRVAdapter.addSongs(songDB.songDao().getLikedSongs(true) as ArrayList) + + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt b/week07/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt new file mode 100644 index 0000000..6149199 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt @@ -0,0 +1,71 @@ +package com.example.flo.locker + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.data.Song + +class SavedsongRVAdapter(): RecyclerView.Adapter() { + private var songs = ArrayList() + + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveSong(songId: Int) + } + + private lateinit var myItemClickListener: MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.binding.songMoreIv.setOnClickListener { + myItemClickListener.onRemoveSong(songs[position].id) + removeSong(position) //리사이클러뷰에서 삭제 + } + + } + + override fun getItemCount():Int = songs.size + + @SuppressLint("NotifyDataSetChanged") + fun addSongs(songs: ArrayList) { + this.songs.clear() + this.songs.addAll(songs) + + notifyDataSetChanged() + } + + @SuppressLint("NotifyDataSetChanged") + fun removeSong(position: Int) { + songs.removeAt(position) + notifyDataSetChanged() + } + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListAlbumImgIv.setImageResource(song.coverImg!!) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/locker/SongfileFragment.kt b/week07/app/src/main/java/com/example/flo/locker/SongfileFragment.kt new file mode 100644 index 0000000..720d1b9 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/locker/SongfileFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSongfileBinding + +class SongfileFragment : Fragment() { + + lateinit var binding : FragmentSongfileBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongfileBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SongfileFragment onCreateView") + + return binding.root + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/look/LookFragment.kt b/week07/app/src/main/java/com/example/flo/look/LookFragment.kt new file mode 100644 index 0000000..d129ef6 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/look/LookFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.look + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentLookBinding + +class LookFragment : Fragment() { + lateinit var binding: FragmentLookBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLookBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/search/SearchFragment.kt b/week07/app/src/main/java/com/example/flo/search/SearchFragment.kt new file mode 100644 index 0000000..4ad6136 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/search/SearchFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.search + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSearchBinding + +class SearchFragment : Fragment() { + lateinit var binding: FragmentSearchBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSearchBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/services/Foreground.kt b/week07/app/src/main/java/com/example/flo/services/Foreground.kt new file mode 100644 index 0000000..06e86f6 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/services/Foreground.kt @@ -0,0 +1,48 @@ +package com.example.flo.services + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class Foreground : Service() { + + val CHANNEL_ID = "Foreground" + val NOTI_ID = 713 + fun createNotificationChannel() { + //API 26이상에서는 사전에 채널을 등록해야 함. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = + NotificationChannel(CHANNEL_ID, "FOREGROUND", NotificationManager.IMPORTANCE_HIGH) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + createNotificationChannel() + //내가 띄울 Notification을 띄운다. + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher_round) + .setContentTitle("ForegroundService") + .setContentText("Hello World!") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + startForeground(NOTI_ID, notification) + + return super.onStartCommand(intent, flags, startId) + } + + override fun onBind(intent: Intent): IBinder { + return Binder() + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/services/MusicService.kt b/week07/app/src/main/java/com/example/flo/services/MusicService.kt new file mode 100644 index 0000000..4184776 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/services/MusicService.kt @@ -0,0 +1,128 @@ +package com.example.flo.services + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Intent +import android.media.MediaPlayer +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class MusicService : Service() { + + //채널 ID와 Notificiation ID는 자유롭게! + private val CHANNEL_ID = "ForegroundMusicService" + private val NOTI_ID = 713 + + private var mediaPlayer: MediaPlayer? = null + private val binder = MusicBinder() + + //현재 재생 중인 노래 정보를 저장할 변수 + private var currentSongTitle: String = "Unknown Title" + private var currentSongArtist: String = "Unknown Artist" + + //Activity에 Service 인스턴스를 전달 + inner class MusicBinder : Binder() { + fun getService(): MusicService = this@MusicService + } + + //서비스 시작 시 초기화 + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + //Notification 활성화 + createNotificationChannel() + + //Intent로 받은 정보들을 파싱 + val initialTitle = intent?.getStringExtra("songTitle") ?: "Unknown Title" + val initialArtist = intent?.getStringExtra("songArtist") ?: "Unknown Artist" + val isPlaying = intent?.getBooleanExtra("isPlaying", false) ?: false + + //MediaPlayer 및 변수 초기화 (임의로 노래를 연결) + if (mediaPlayer == null) { + mediaPlayer = MediaPlayer.create(this, R.raw.music_lilac) + currentSongTitle = initialTitle + currentSongArtist = initialArtist + if (isPlaying) { + mediaPlayer?.start() + } + } + + //알람도 같이 설정 + val notification = createNotification() + startForeground(NOTI_ID, notification) + + return START_STICKY + } + + override fun onBind(intent: Intent): IBinder { + return binder + } + + //알람 채널 설정(CHANNEL_ID와 name은 자유롭게 설정!) + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + "Foreground Music Service Channel", + NotificationManager.IMPORTANCE_HIGH + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + } + + //알람으로 노래가 재생중임을 표시 + private fun createNotification(): Notification { + val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle("음악 재생 중") + .setContentText("$currentSongTitle 이/가 재생 중입니다.") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setOngoing(true) + .setOnlyAlertOnce(true) + + return notificationBuilder.build() + } + + //외부에서 서비스에 접근 가능한 함수들 + //음악 재생 + fun playMusic() { + mediaPlayer?.start() + } + //음악 멈춤 + fun pauseMusic() { + mediaPlayer?.pause() + } + //인자로 받은 위치로 곡의 재생 위치 이동 + fun seekTo(position: Int) { + mediaPlayer?.seekTo(position) + } + //현재 재생중인 노래 정보 업데이트 + fun updateCurrentSongInfo(title: String, artist: String) { + currentSongTitle = title + currentSongArtist = artist + } + //현재 재생중인 노래의 길이 리턴 + fun getDuration(): Int { + return mediaPlayer?.duration ?: 0 + } + //현재 노래의 위치 리턴(SeekBar에 넣을 거) + fun getCurrentPosition(): Int { + return mediaPlayer?.currentPosition ?: 0 + } + //재생 중임? + fun isPlaying(): Boolean { + return mediaPlayer?.isPlaying ?: false + } + + override fun onDestroy() { + mediaPlayer?.stop() + mediaPlayer?.release() + mediaPlayer = null + super.onDestroy() + } +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/ui/theme/Color.kt b/week07/app/src/main/java/com/example/flo/ui/theme/Color.kt new file mode 100644 index 0000000..6b31678 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.flo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/ui/theme/Theme.kt b/week07/app/src/main/java/com/example/flo/ui/theme/Theme.kt new file mode 100644 index 0000000..cc69550 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.flo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FLOTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/week07/app/src/main/java/com/example/flo/ui/theme/Type.kt b/week07/app/src/main/java/com/example/flo/ui/theme/Type.kt new file mode 100644 index 0000000..9a198f8 --- /dev/null +++ b/week07/app/src/main/java/com/example/flo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.flo.ui.theme + +import androidx.compose.material3.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( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/week07/app/src/main/res/drawable/btn_actionbar_instagram.png b/week07/app/src/main/res/drawable/btn_actionbar_instagram.png new file mode 100644 index 0000000..90bc027 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_actionbar_instagram.png differ diff --git a/week07/app/src/main/res/drawable/btn_arrow_black.png b/week07/app/src/main/res/drawable/btn_arrow_black.png new file mode 100644 index 0000000..cc38ca8 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_arrow_black.png differ diff --git a/week07/app/src/main/res/drawable/btn_color_selector.xml b/week07/app/src/main/res/drawable/btn_color_selector.xml new file mode 100644 index 0000000..3ecf8a7 --- /dev/null +++ b/week07/app/src/main/res/drawable/btn_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/drawable/btn_main_arrow_more.png b/week07/app/src/main/res/drawable/btn_main_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_main_arrow_more.png differ diff --git a/week07/app/src/main/res/drawable/btn_main_mike.png b/week07/app/src/main/res/drawable/btn_main_mike.png new file mode 100644 index 0000000..9bddec6 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_main_mike.png differ diff --git a/week07/app/src/main/res/drawable/btn_main_setting.png b/week07/app/src/main/res/drawable/btn_main_setting.png new file mode 100644 index 0000000..7a8d5d6 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_main_setting.png differ diff --git a/week07/app/src/main/res/drawable/btn_main_ticket.png b/week07/app/src/main/res/drawable/btn_main_ticket.png new file mode 100644 index 0000000..52b6d64 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_main_ticket.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplay_mvpause.png b/week07/app/src/main/res/drawable/btn_miniplay_mvpause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplay_mvpause.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplay_mvplay.png b/week07/app/src/main/res/drawable/btn_miniplay_mvplay.png new file mode 100644 index 0000000..d118677 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplay_mvplay.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplay_pause.png b/week07/app/src/main/res/drawable/btn_miniplay_pause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplay_pause.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplayer_go_list.png b/week07/app/src/main/res/drawable/btn_miniplayer_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplayer_go_list.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplayer_next.png b/week07/app/src/main/res/drawable/btn_miniplayer_next.png new file mode 100644 index 0000000..3aedba3 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplayer_next.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplayer_play.png b/week07/app/src/main/res/drawable/btn_miniplayer_play.png new file mode 100644 index 0000000..f619072 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplayer_play.png differ diff --git a/week07/app/src/main/res/drawable/btn_miniplayer_previous.png b/week07/app/src/main/res/drawable/btn_miniplayer_previous.png new file mode 100644 index 0000000..d0bf1f6 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_miniplayer_previous.png differ diff --git a/week07/app/src/main/res/drawable/btn_panel_play_large.png b/week07/app/src/main/res/drawable/btn_panel_play_large.png new file mode 100644 index 0000000..4ac7103 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_panel_play_large.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_eq_off.png b/week07/app/src/main/res/drawable/btn_player_eq_off.png new file mode 100644 index 0000000..f23d9c6 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_eq_off.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_go_list.png b/week07/app/src/main/res/drawable/btn_player_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_go_list.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_more.png b/week07/app/src/main/res/drawable/btn_player_more.png new file mode 100644 index 0000000..a8ad9e6 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_more.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_play.png b/week07/app/src/main/res/drawable/btn_player_play.png new file mode 100644 index 0000000..f6c3201 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_play.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_related.png b/week07/app/src/main/res/drawable/btn_player_related.png new file mode 100644 index 0000000..9026fe5 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_related.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_setting.png b/week07/app/src/main/res/drawable/btn_player_setting.png new file mode 100644 index 0000000..0df8f69 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_setting.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_unlike_off.png b/week07/app/src/main/res/drawable/btn_player_unlike_off.png new file mode 100644 index 0000000..b539504 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_unlike_off.png differ diff --git a/week07/app/src/main/res/drawable/btn_player_unlike_on.png b/week07/app/src/main/res/drawable/btn_player_unlike_on.png new file mode 100644 index 0000000..45a43ca Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_player_unlike_on.png differ diff --git a/week07/app/src/main/res/drawable/btn_playlist_select_off.png b/week07/app/src/main/res/drawable/btn_playlist_select_off.png new file mode 100644 index 0000000..62ef45c Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_playlist_select_off.png differ diff --git a/week07/app/src/main/res/drawable/btn_playlist_select_on.png b/week07/app/src/main/res/drawable/btn_playlist_select_on.png new file mode 100644 index 0000000..2d3b6af Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_playlist_select_on.png differ diff --git a/week07/app/src/main/res/drawable/btn_toggle_off.png b/week07/app/src/main/res/drawable/btn_toggle_off.png new file mode 100644 index 0000000..983360d Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_toggle_off.png differ diff --git a/week07/app/src/main/res/drawable/btn_toggle_on.png b/week07/app/src/main/res/drawable/btn_toggle_on.png new file mode 100644 index 0000000..fb609f4 Binary files /dev/null and b/week07/app/src/main/res/drawable/btn_toggle_on.png differ diff --git a/week07/app/src/main/res/drawable/discovery_banner_aos.jpg b/week07/app/src/main/res/drawable/discovery_banner_aos.jpg new file mode 100644 index 0000000..c905515 Binary files /dev/null and b/week07/app/src/main/res/drawable/discovery_banner_aos.jpg differ diff --git a/week07/app/src/main/res/drawable/ic_all_album_play.xml b/week07/app/src/main/res/drawable/ic_all_album_play.xml new file mode 100644 index 0000000..21f11cb --- /dev/null +++ b/week07/app/src/main/res/drawable/ic_all_album_play.xml @@ -0,0 +1,9 @@ + + + diff --git a/week07/app/src/main/res/drawable/ic_bottom_home_no_select.png b/week07/app/src/main/res/drawable/ic_bottom_home_no_select.png new file mode 100644 index 0000000..69a8ab6 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_bottom_home_no_select.png differ diff --git a/week07/app/src/main/res/drawable/ic_bottom_locker_no_select.png b/week07/app/src/main/res/drawable/ic_bottom_locker_no_select.png new file mode 100644 index 0000000..a67dec3 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_bottom_locker_no_select.png differ diff --git a/week07/app/src/main/res/drawable/ic_bottom_look_no_select.png b/week07/app/src/main/res/drawable/ic_bottom_look_no_select.png new file mode 100644 index 0000000..6c2f4f0 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_bottom_look_no_select.png differ diff --git a/week07/app/src/main/res/drawable/ic_bottom_search_no_select.png b/week07/app/src/main/res/drawable/ic_bottom_search_no_select.png new file mode 100644 index 0000000..a77b8c5 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_bottom_search_no_select.png differ diff --git a/week07/app/src/main/res/drawable/ic_check.xml b/week07/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..bec5bec --- /dev/null +++ b/week07/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,12 @@ + + + diff --git a/week07/app/src/main/res/drawable/ic_flo_logo.png b/week07/app/src/main/res/drawable/ic_flo_logo.png new file mode 100644 index 0000000..643224d Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_flo_logo.png differ diff --git a/week07/app/src/main/res/drawable/ic_launcher_background.xml b/week07/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/week07/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week07/app/src/main/res/drawable/ic_launcher_foreground.xml b/week07/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/week07/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/drawable/ic_main_facebook.png b/week07/app/src/main/res/drawable/ic_main_facebook.png new file mode 100644 index 0000000..83e9732 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_main_facebook.png differ diff --git a/week07/app/src/main/res/drawable/ic_main_instagram.png b/week07/app/src/main/res/drawable/ic_main_instagram.png new file mode 100644 index 0000000..398ce61 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_main_instagram.png differ diff --git a/week07/app/src/main/res/drawable/ic_main_twitter.png b/week07/app/src/main/res/drawable/ic_main_twitter.png new file mode 100644 index 0000000..6ddc68e Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_main_twitter.png differ diff --git a/week07/app/src/main/res/drawable/ic_main_youtube.png b/week07/app/src/main/res/drawable/ic_main_youtube.png new file mode 100644 index 0000000..0c4ec93 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_main_youtube.png differ diff --git a/week07/app/src/main/res/drawable/ic_my_like_off.png b/week07/app/src/main/res/drawable/ic_my_like_off.png new file mode 100644 index 0000000..c06e139 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_my_like_off.png differ diff --git a/week07/app/src/main/res/drawable/ic_my_like_on.png b/week07/app/src/main/res/drawable/ic_my_like_on.png new file mode 100644 index 0000000..22577c0 Binary files /dev/null and b/week07/app/src/main/res/drawable/ic_my_like_on.png differ diff --git a/week07/app/src/main/res/drawable/icon_browse_arrow_right.png b/week07/app/src/main/res/drawable/icon_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week07/app/src/main/res/drawable/icon_browse_arrow_right.png differ diff --git a/week07/app/src/main/res/drawable/img_album_exp.png b/week07/app/src/main/res/drawable/img_album_exp.png new file mode 100644 index 0000000..6e3f38a Binary files /dev/null and b/week07/app/src/main/res/drawable/img_album_exp.png differ diff --git a/week07/app/src/main/res/drawable/img_album_exp2.png b/week07/app/src/main/res/drawable/img_album_exp2.png new file mode 100644 index 0000000..28ea3ee Binary files /dev/null and b/week07/app/src/main/res/drawable/img_album_exp2.png differ diff --git a/week07/app/src/main/res/drawable/img_album_lp.png b/week07/app/src/main/res/drawable/img_album_lp.png new file mode 100644 index 0000000..29fb1b4 Binary files /dev/null and b/week07/app/src/main/res/drawable/img_album_lp.png differ diff --git a/week07/app/src/main/res/drawable/img_first_album_default.png b/week07/app/src/main/res/drawable/img_first_album_default.png new file mode 100644 index 0000000..926d34f Binary files /dev/null and b/week07/app/src/main/res/drawable/img_first_album_default.png differ diff --git a/week07/app/src/main/res/drawable/img_great_album_exp.jpg b/week07/app/src/main/res/drawable/img_great_album_exp.jpg new file mode 100644 index 0000000..33efe01 Binary files /dev/null and b/week07/app/src/main/res/drawable/img_great_album_exp.jpg differ diff --git a/week07/app/src/main/res/drawable/img_home_viewpager_exp.png b/week07/app/src/main/res/drawable/img_home_viewpager_exp.png new file mode 100644 index 0000000..da78032 Binary files /dev/null and b/week07/app/src/main/res/drawable/img_home_viewpager_exp.png differ diff --git a/week07/app/src/main/res/drawable/img_home_viewpager_exp2.png b/week07/app/src/main/res/drawable/img_home_viewpager_exp2.png new file mode 100644 index 0000000..50fa4be Binary files /dev/null and b/week07/app/src/main/res/drawable/img_home_viewpager_exp2.png differ diff --git a/week07/app/src/main/res/drawable/img_iris_album_exp.jpg b/week07/app/src/main/res/drawable/img_iris_album_exp.jpg new file mode 100644 index 0000000..040d531 Binary files /dev/null and b/week07/app/src/main/res/drawable/img_iris_album_exp.jpg differ diff --git a/week07/app/src/main/res/drawable/img_oort_album_exp.jpg b/week07/app/src/main/res/drawable/img_oort_album_exp.jpg new file mode 100644 index 0000000..d9b06ab Binary files /dev/null and b/week07/app/src/main/res/drawable/img_oort_album_exp.jpg differ diff --git a/week07/app/src/main/res/drawable/img_potcast_exp.png b/week07/app/src/main/res/drawable/img_potcast_exp.png new file mode 100644 index 0000000..50a46e0 Binary files /dev/null and b/week07/app/src/main/res/drawable/img_potcast_exp.png differ diff --git a/week07/app/src/main/res/drawable/img_video_exp.png b/week07/app/src/main/res/drawable/img_video_exp.png new file mode 100644 index 0000000..7f6b05f Binary files /dev/null and b/week07/app/src/main/res/drawable/img_video_exp.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_down.png b/week07/app/src/main/res/drawable/nugu_btn_down.png new file mode 100644 index 0000000..03a04c5 Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_down.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_pause_32.png b/week07/app/src/main/res/drawable/nugu_btn_pause_32.png new file mode 100644 index 0000000..9388aa3 Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_pause_32.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_play_32.png b/week07/app/src/main/res/drawable/nugu_btn_play_32.png new file mode 100644 index 0000000..b781e4c Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_play_32.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_random_inactive.png b/week07/app/src/main/res/drawable/nugu_btn_random_inactive.png new file mode 100644 index 0000000..fe4f880 Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_random_inactive.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_repeat_inactive.png b/week07/app/src/main/res/drawable/nugu_btn_repeat_inactive.png new file mode 100644 index 0000000..1e4044d Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_repeat_inactive.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_skip_next_32.png b/week07/app/src/main/res/drawable/nugu_btn_skip_next_32.png new file mode 100644 index 0000000..fc02f28 Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_skip_next_32.png differ diff --git a/week07/app/src/main/res/drawable/nugu_btn_skip_previous_32.png b/week07/app/src/main/res/drawable/nugu_btn_skip_previous_32.png new file mode 100644 index 0000000..03ec854 Binary files /dev/null and b/week07/app/src/main/res/drawable/nugu_btn_skip_previous_32.png differ diff --git a/week07/app/src/main/res/drawable/splash.xml b/week07/app/src/main/res/drawable/splash.xml new file mode 100644 index 0000000..da83aa4 --- /dev/null +++ b/week07/app/src/main/res/drawable/splash.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/drawable/textview_background_radius.xml b/week07/app/src/main/res/drawable/textview_background_radius.xml new file mode 100644 index 0000000..d250c1e --- /dev/null +++ b/week07/app/src/main/res/drawable/textview_background_radius.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/drawable/textview_background_select_color_radius.xml b/week07/app/src/main/res/drawable/textview_background_select_color_radius.xml new file mode 100644 index 0000000..8aaca4c --- /dev/null +++ b/week07/app/src/main/res/drawable/textview_background_select_color_radius.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/drawable/widget_black_play.png b/week07/app/src/main/res/drawable/widget_black_play.png new file mode 100644 index 0000000..0ec2700 Binary files /dev/null and b/week07/app/src/main/res/drawable/widget_black_play.png differ diff --git a/week07/app/src/main/res/layout/activity/activity_test.xml b/week07/app/src/main/res/layout/activity/activity_test.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/week07/app/src/main/res/layout/activity/activity_test.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/activity_main.xml b/week07/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..3f45054 --- /dev/null +++ b/week07/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/activity_song.xml b/week07/app/src/main/res/layout/activity_song.xml new file mode 100644 index 0000000..73a6cc4 --- /dev/null +++ b/week07/app/src/main/res/layout/activity_song.xml @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/activity_splash.xml b/week07/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 0000000..29ce312 --- /dev/null +++ b/week07/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_album.xml b/week07/app/src/main/res/layout/fragment_album.xml new file mode 100644 index 0000000..79aaf13 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_album.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_banner.xml b/week07/app/src/main/res/layout/fragment_banner.xml new file mode 100644 index 0000000..b7ef866 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_banner.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_detail.xml b/week07/app/src/main/res/layout/fragment_detail.xml new file mode 100644 index 0000000..151ebe6 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_detail.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_home.xml b/week07/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..90215e6 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_locker.xml b/week07/app/src/main/res/layout/fragment_locker.xml new file mode 100644 index 0000000..ebe1667 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_locker.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week07/app/src/main/res/layout/fragment_look.xml b/week07/app/src/main/res/layout/fragment_look.xml new file mode 100644 index 0000000..2d217e7 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_look.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_savedalbum.xml b/week07/app/src/main/res/layout/fragment_savedalbum.xml new file mode 100644 index 0000000..c395bf2 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_savedalbum.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/week07/app/src/main/res/layout/fragment_savedsong.xml b/week07/app/src/main/res/layout/fragment_savedsong.xml new file mode 100644 index 0000000..41fb837 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_savedsong.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_search.xml b/week07/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..301f760 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_song.xml b/week07/app/src/main/res/layout/fragment_song.xml new file mode 100644 index 0000000..439b6f3 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_song.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_songfile.xml b/week07/app/src/main/res/layout/fragment_songfile.xml new file mode 100644 index 0000000..05dca29 --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_songfile.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/fragment_video.xml b/week07/app/src/main/res/layout/fragment_video.xml new file mode 100644 index 0000000..70e650d --- /dev/null +++ b/week07/app/src/main/res/layout/fragment_video.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/item_album.xml b/week07/app/src/main/res/layout/item_album.xml new file mode 100644 index 0000000..99ae14e --- /dev/null +++ b/week07/app/src/main/res/layout/item_album.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/item_savedalbum.xml b/week07/app/src/main/res/layout/item_savedalbum.xml new file mode 100644 index 0000000..cabe757 --- /dev/null +++ b/week07/app/src/main/res/layout/item_savedalbum.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/item_savedsong.xml b/week07/app/src/main/res/layout/item_savedsong.xml new file mode 100644 index 0000000..fc292d7 --- /dev/null +++ b/week07/app/src/main/res/layout/item_savedsong.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/layout/item_song.xml b/week07/app/src/main/res/layout/item_song.xml new file mode 100644 index 0000000..bf9e8a2 --- /dev/null +++ b/week07/app/src/main/res/layout/item_song.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/menu/bottom_nav_menu.xml b/week07/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000..2b56b8c --- /dev/null +++ b/week07/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week07/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week07/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week07/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week07/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week07/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/week07/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/week07/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week07/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/week07/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/week07/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week07/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/week07/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/week07/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week07/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/week07/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/week07/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week07/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/week07/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/week07/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week07/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/week07/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/week07/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week07/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/week07/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/week07/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week07/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/week07/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/week07/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week07/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/week07/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/week07/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week07/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/week07/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/week07/app/src/main/res/raw/music_bboom.mp3 b/week07/app/src/main/res/raw/music_bboom.mp3 new file mode 100644 index 0000000..9b1e5db Binary files /dev/null and b/week07/app/src/main/res/raw/music_bboom.mp3 differ diff --git a/week07/app/src/main/res/raw/music_butter.mp3 b/week07/app/src/main/res/raw/music_butter.mp3 new file mode 100644 index 0000000..94ffc91 Binary files /dev/null and b/week07/app/src/main/res/raw/music_butter.mp3 differ diff --git a/week07/app/src/main/res/raw/music_irisout.mp3 b/week07/app/src/main/res/raw/music_irisout.mp3 new file mode 100644 index 0000000..7e40d8d Binary files /dev/null and b/week07/app/src/main/res/raw/music_irisout.mp3 differ diff --git a/week07/app/src/main/res/raw/music_lilac.mp3 b/week07/app/src/main/res/raw/music_lilac.mp3 new file mode 100644 index 0000000..7c85690 Binary files /dev/null and b/week07/app/src/main/res/raw/music_lilac.mp3 differ diff --git a/week07/app/src/main/res/raw/music_oortcloud.mp3 b/week07/app/src/main/res/raw/music_oortcloud.mp3 new file mode 100644 index 0000000..7e7cbf8 Binary files /dev/null and b/week07/app/src/main/res/raw/music_oortcloud.mp3 differ diff --git a/week07/app/src/main/res/values/colors.xml b/week07/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..71cd486 --- /dev/null +++ b/week07/app/src/main/res/values/colors.xml @@ -0,0 +1,24 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FFD3D3D3 + #FF0000FF + #3f3fff + + #9cbee2 + #062342 + #424242 + #6bb2ff + + #00ff0000 + #3f3fff + #a8a8a8 + #3f3fff + #a8a8a8 + \ No newline at end of file diff --git a/week07/app/src/main/res/values/strings.xml b/week07/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..63f5ff1 --- /dev/null +++ b/week07/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + FLO + + Hello blank fragment + \ No newline at end of file diff --git a/week07/app/src/main/res/values/themes.xml b/week07/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e76a4bf --- /dev/null +++ b/week07/app/src/main/res/values/themes.xml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/xml/backup_rules.xml b/week07/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..4df9255 --- /dev/null +++ b/week07/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/week07/app/src/main/res/xml/data_extraction_rules.xml b/week07/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/week07/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week07/app/src/test/java/com/example/flo/ExampleUnitTest.kt b/week07/app/src/test/java/com/example/flo/ExampleUnitTest.kt new file mode 100644 index 0000000..d39df20 --- /dev/null +++ b/week07/app/src/test/java/com/example/flo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.flo + +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/week07/build.gradle.kts b/week07/build.gradle.kts new file mode 100644 index 0000000..952b930 --- /dev/null +++ b/week07/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} \ No newline at end of file diff --git a/week07/gradle.properties b/week07/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/week07/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. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-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/week07/gradle/libs.versions.toml b/week07/gradle/libs.versions.toml new file mode 100644 index 0000000..339d205 --- /dev/null +++ b/week07/gradle/libs.versions.toml @@ -0,0 +1,36 @@ +[versions] +agp = "8.13.0" +kotlin = "2.0.21" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2024.09.00" +constraintlayout = "2.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version = "2.2.21" } + + diff --git a/week07/gradle/wrapper/gradle-wrapper.jar b/week07/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/week07/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week07/gradle/wrapper/gradle-wrapper.properties b/week07/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..af10ccc --- /dev/null +++ b/week07/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Sep 28 16:12:35 KST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week07/gradlew b/week07/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/week07/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/week07/gradlew.bat b/week07/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/week07/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/week07/settings.gradle.kts b/week07/settings.gradle.kts new file mode 100644 index 0000000..2a48c99 --- /dev/null +++ b/week07/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "FLO" +include(":app") + \ No newline at end of file diff --git a/week08/.gitignore b/week08/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/week08/.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/week08/.idea/.name b/week08/.idea/.name new file mode 100644 index 0000000..997352e --- /dev/null +++ b/week08/.idea/.name @@ -0,0 +1 @@ +FLO \ No newline at end of file diff --git a/week08/.idea/AndroidProjectSystem.xml b/week08/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/week08/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/week08/.idea/compiler.xml b/week08/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/week08/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week08/.idea/deploymentTargetSelector.xml b/week08/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..c716954 --- /dev/null +++ b/week08/.idea/deploymentTargetSelector.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/week08/.idea/deviceManager.xml b/week08/.idea/deviceManager.xml new file mode 100644 index 0000000..eebfe8e --- /dev/null +++ b/week08/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week08/.idea/gradle.xml b/week08/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/week08/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week08/.idea/inspectionProfiles/Project_Default.xml b/week08/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/week08/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/week08/.idea/migrations.xml b/week08/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/week08/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/week08/.idea/misc.xml b/week08/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/week08/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/week08/.idea/runConfigurations.xml b/week08/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/week08/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week08/.idea/vcs.xml b/week08/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/week08/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/.gitignore b/week08/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/week08/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/week08/app/build.gradle.kts b/week08/app/build.gradle.kts new file mode 100644 index 0000000..16ba0c1 --- /dev/null +++ b/week08/app/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + + id("kotlin-kapt") + +} + +android { + namespace = "com.example.flo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.flo" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("androidx.fragment:fragment:1.8.9") + implementation("com.google.android.material:material:1.13.0") + implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("com.tbuonomo:dotsindicator:5.1.0") + implementation("androidx.recyclerview:recyclerview:1.4.0") + implementation("com.google.code.gson:gson:2.13.2") + implementation("androidx.core:core-splashscreen:1.0.1") + + //roomDB + implementation("androidx.room:room-ktx:2.8.3") + implementation("androidx.room:room-runtime:2.8.3") + //implementation("androidx.room:room-compiler:2.8.3") + kapt("androidx.room:room-compiler:2.8.3") +} \ No newline at end of file diff --git a/week08/app/proguard-rules.pro b/week08/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/week08/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/week08/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt b/week08/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..6dfac89 --- /dev/null +++ b/week08/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.flo + +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.flo", appContext.packageName) + } +} \ No newline at end of file diff --git a/week08/app/src/main/AndroidManifest.xml b/week08/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..55bc47b --- /dev/null +++ b/week08/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/activities/LoginActivity.kt b/week08/app/src/main/java/com/example/flo/activities/LoginActivity.kt new file mode 100644 index 0000000..d271884 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/activities/LoginActivity.kt @@ -0,0 +1,70 @@ +package com.example.flo.activities + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.data.db.SongDatabase +import com.example.flo.databinding.ActivityLoginBinding + +class LoginActivity : AppCompatActivity() { + private lateinit var binding: ActivityLoginBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding.root) + + //회원가입액티비티로의 화면전환 + binding.loginSignUpTv.setOnClickListener { + startActivity(Intent(this, SignUpActivity::class.java)) + } + + binding.loginSignInBtn.setOnClickListener { + login() + } + } + + //로그인 처리 함수 + private fun login() { + //예외 처리 + if (binding.loginIdEt.text.toString().isEmpty() || binding.loginDirectInputEt.text.toString().isEmpty()) { + Toast.makeText(this, "이메일을 입력해주세요", Toast.LENGTH_SHORT).show() + return + } + if (binding.loginPasswordEt.text.toString().isEmpty()) { + Toast.makeText(this, "비밀번호를 입력해주세요", Toast.LENGTH_SHORT).show() + return + } + + val email : String = binding.loginIdEt.text.toString() + "@" + binding.loginDirectInputEt.text.toString() + val pwd: String = binding.loginPasswordEt.text.toString() + + val songDB = SongDatabase.getInstance(this)!! + val user = songDB.userDao().getUser(email, pwd) + + //user가 null이 아니면 다음을 실행하라 + user?.let { + Log.d("LOGIN_ACT/GET_USER", "userId : ${user.id}, $user") + saveJwt(user.id) + startMainActivity() + } + Toast.makeText(this, "회원 정보가 존재하지 않습니다.", Toast.LENGTH_SHORT).show() + } + + private fun saveJwt(jwt:Int) { + val spf = getSharedPreferences("auth", MODE_PRIVATE) + val editor = spf.edit() + + editor.putInt("jwt", jwt) + editor.apply() + } + private fun startMainActivity() { + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/activities/MainActivity.kt b/week08/app/src/main/java/com/example/flo/activities/MainActivity.kt new file mode 100644 index 0000000..7f36ec1 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/activities/MainActivity.kt @@ -0,0 +1,250 @@ +package com.example.flo.activities + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.home.HomeFragment +import com.example.flo.locker.LockerFragment +import com.example.flo.look.LookFragment +import com.example.flo.R +import com.example.flo.data.album.Album +import com.example.flo.search.SearchFragment +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase +import com.example.flo.databinding.ActivityMainBinding +import com.google.gson.Gson + +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + + private var song:Song = Song() + private var gson: Gson = Gson() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setTheme(R.style.Theme_FLO) + enableEdgeToEdge() + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + inputDummySongs() //더미 송 데이터 db에 삽입 + inputDummyAlbums() //더미 앨범 데이터 db에 삽입 + + //하단플레이어에 나오는 노래를 Song객체에 저장 -> roomDB로 대체 +// val song = Song( +// title = binding.mainMiniplayerTitleTv.text.toString(), +// singer = binding.mainMiniplayerSingerTv.text.toString(), +// second = 0, playTime = 60, isPlaying = false, music = "music_lilac" +// ) + + //하단의 플레이어를 누르면 송액티비티로 전환. 이때 sharedPreference에 노래의 id를 저장 + binding.mainPlayerCl.setOnClickListener { + //에디터를 만들고 + val editor = getSharedPreferences("song", MODE_PRIVATE).edit() + + //송의 id를 넣어준다. + editor.putInt("songId", song.id) + + //최종 커밋 + editor.apply() + + //인텐트는 단순 전환 기능만. sharedPrefernece와 DB가 알아서 해주니까. + val intent = Intent(this, SongActivity::class.java) + startActivity(intent) + } + + //실행 시 첫 화면 설정 -> 홈프래그먼트 + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + + //BottomNavigationView를 눌렀을 때 Fragment 변경하기 + binding.mainBnv.setOnItemSelectedListener { item -> + when (item.itemId) { + //매인 화면 + R.id.homeFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + true + } + //둘러보기 화면 + R.id.lookFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LookFragment()) + .commit() + true + } + //검색 화면 + R.id.searchFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, SearchFragment()) + .commit() + true + } + //보관함 화면 + R.id.lockerFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LockerFragment()) + .commit() + true + } + else -> false + } + } + } + + //메인 액티비티가 시작될 때-> sharedprference에서 id값을 가져와서 DB에서 해당 id에 해당하는 song을 가져옴 + override fun onStart() { + super.onStart() + //sharedprference에서 id값을 가져옴 + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId", 0) + + //DB인스턴스를 만들고 + val songDB = SongDatabase.getInstance(this)!! + + //DB에서 해당 id에 해당하는 song을 가져옴 + song = if (songId==0) { + songDB.songDao().getSong(1) + } else { + songDB.songDao().getSong(songId) + } + + Log.d("song ID", song.id.toString()) // 디버깅 + + //가져온 송 데이터를 뷰바인딩 + setMiniPlayer(song) + } + + private fun setMiniPlayer(song: Song){ + binding.mainMiniplayerTitleTv.text = song.title + binding.mainMiniplayerSingerTv.text = song.singer + binding.mainProgressSb.progress = (song.second*100000)/song.playTime + } + + //DB에 데이터가 없다면 더미 데이터를 넣는 작업 + private fun inputDummySongs() { + val songDB = SongDatabase.getInstance(this)!! + val songs = songDB.songDao().getSongs() + + //데이터가 있다면 종료 + if (songs.isNotEmpty()) return + + //데이터가 없을 경우 + songDB.songDao().insert( + Song( + title = "Lilac", + singer = "아이유 (IU)", + second = 0, + playTime = 230, + isPlaying = false, + music = "music_lilac", + coverImg = R.drawable.img_album_exp2, + isLike = false, + //albumIdx = 1 + ) + ) + + songDB.songDao().insert( + Song( + title = "BBoom BBoom", + singer = "모모랜드 (MOMOLAND)", + second = 0, + playTime = 240, + isPlaying = false, + music = "music_bboom", + coverImg = R.drawable.img_great_album_exp, + isLike = false, + //albumIdx = 2 + ) + ) + + songDB.songDao().insert( + Song( + title = "Butter", + singer = "방탄소년단 (BTS)", + second = 0, + playTime = 180, + isPlaying = false, + music = "music_butter", + coverImg = R.drawable.img_album_exp, + isLike = false, + //albumIdx = 3 + ) + ) + + songDB.songDao().insert( + Song( + title = "IRIS OUT", + singer = "요네즈 켄시 (Kenshi Yonezu)", + second = 0, + playTime = 155, + isPlaying = false, + music = "music_irisout", + coverImg = R.drawable.img_iris_album_exp, + isLike = false, + //albumIdx = 4 + ) + ) + + songDB.songDao().insert( + Song( + title = "Oort Cloud (오르트 구름)", + singer = "윤하 (YOUNHA)", + second = 0, + playTime = 210, + isPlaying = false, + music = "music_oortcloud", + coverImg = R.drawable.img_oort_album_exp, + isLike = false, + //albumIdx = 5 + ) + ) + //DB에 데이터가 잘 들어갔는지 로그로 확인 + val _songs = songDB.songDao().getSongs() //테이블의 모든 송을 가져옴 + Log.d("DB data", _songs.toString()) //DB에 데이터가 잘 들어갔는지 확인 + } + + //ROOM_DB + private fun inputDummyAlbums() { + val songDB = SongDatabase.getInstance(this)!! + val albums = songDB.albumDao().getAlbums() + + if (albums.isNotEmpty()) return + + songDB.albumDao().insert( + Album( + 0, + "IU 5th Album 'LILAC'", "아이유 (IU)", coverImg = R.drawable.img_album_exp2 + ) + ) + songDB.albumDao().insert( + Album( + 1, + "GREAT!", "모모랜드 (MOMOLAND)", coverImg = R.drawable.img_great_album_exp + ) + ) + songDB.albumDao().insert( + Album( + 2, + "Butter", "방탄소년단 (BTS)", coverImg = R.drawable.img_album_exp + ) + ) + songDB.albumDao().insert( + Album( + 3, + "LOST CORNER", "요네즈 켄시 (Kenshi Yonezu)", coverImg = R.drawable.img_iris_album_exp + ) + ) + songDB.albumDao().insert( + Album( + 4, + "END THEORY", "윤하 (YOUNHA)", coverImg = R.drawable.img_oort_album_exp + ) + ) + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/activities/SignUpActivity.kt b/week08/app/src/main/java/com/example/flo/activities/SignUpActivity.kt new file mode 100644 index 0000000..33c1a08 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/activities/SignUpActivity.kt @@ -0,0 +1,57 @@ +package com.example.flo.activities + +import android.os.Bundle +import android.util.Log + +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.data.db.SongDatabase + +import com.example.flo.data.user.User +import com.example.flo.databinding.ActivitySignupBinding + +class SignUpActivity : AppCompatActivity() { + private lateinit var binding: ActivitySignupBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySignupBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.signUpSignUpBtn.setOnClickListener { + signUp() //회원가입 + finish() //로그인액티비티로 이동 + } + } + + //유저 정보를 가져오는 메서드 + private fun getUser(): User { + val email : String = binding.signUpIdEt.text.toString() + "@" + binding.signUpDirectInputEt.text.toString() + val pwd: String = binding.signUpPasswordEt.text.toString() + + return User(email, pwd) + } + + //회원가입 메서드 + private fun signUp() { + //예외 처리 + if (binding.signUpIdEt.text.toString().isEmpty() || binding.signUpDirectInputEt.text.toString().isEmpty()) { + Toast.makeText(this, "이메일 형식이 잘못되었습니다.", Toast.LENGTH_SHORT).show() + return + } + if (binding.signUpPasswordEt.text.toString() != binding.signUpPasswordCheckEt.text.toString()) { + Toast.makeText(this, "비밀번호가 일치하지 않습니다.", Toast.LENGTH_SHORT).show() + return + } + + //입력한 정보를 DB에 저장 + val userDB = SongDatabase.getInstance(this)!! + userDB.userDao().insert(getUser()) + + //디버깅 + val user = userDB.userDao().getUsers() + Log.d("SIGNUPACT", user.toString()) + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/activities/SongActivity.kt b/week08/app/src/main/java/com/example/flo/activities/SongActivity.kt new file mode 100644 index 0000000..08f4572 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/activities/SongActivity.kt @@ -0,0 +1,262 @@ +package com.example.flo.activities + +import android.graphics.Color +import android.graphics.PorterDuff +import android.media.MediaPlayer +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.databinding.ActivitySongBinding +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase +import com.google.gson.Gson +import com.example.flo.R + +class SongActivity : AppCompatActivity() { + private lateinit var binding: ActivitySongBinding + //lateinit var song: Song // 첫 isPlaying은 False + + lateinit var timer: Timer + private var mediaPlayer: MediaPlayer? = null + private var gson: Gson = Gson() + + // 재생할 "노래 목록(플레이리스트)"을 담기 위한 리스트. + // 여러 곡을 담고 이전곡/다음곡으로 이동할 수 있게 하기 위해 존재 + val songs = arrayListOf() + lateinit var songDB: SongDatabase // DB인스턴스 선언. DB CRUD작업을 할 때는 필수인 것 같다. + var nowPos = 0 //현재 곡을 가리키는 전역변수 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySongBinding.inflate(layoutInflater) + setContentView(binding.root) + initPlayList() //DB에서 모든 송들을 가져와 songs에 저장 + initSong() //송 데이터 받아와 실행 + initClickListener() + //setPlayer(songs[nowPos]) + + //반복재생 + var isRoop = false + binding.songRepeatIv.setOnClickListener { + if (!isRoop) { + binding.songRepeatIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + isRoop = true + } else { + binding.songRepeatIv.clearColorFilter() + isRoop = false + } + } + //전체재생(랜덤재생인듯?) + var willPlayAll = false + binding.songRandomIv.setOnClickListener { + if (!willPlayAll) { + binding.songRandomIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + willPlayAll = true + } else { + binding.songRandomIv.clearColorFilter() + willPlayAll = false + } + } + } + + // 사용자가 포커스를 잃었을 때 음악 중지 + override fun onPause() { + super.onPause() + setPlayerStatus(false) + songs[nowPos].second = ((binding.songProgressSb.progress * songs[nowPos].playTime) / 100) / 1000 + val sharedPreferences = getSharedPreferences("song", MODE_PRIVATE) + val editor = sharedPreferences.edit() //에디터 + + editor.putInt("songId", songs[nowPos].id) + + editor.apply() //꼭 쓰기!! 깃에서 push와 같음 + } + + //앱이 꺼질때 스레드 종료 + override fun onDestroy() { + super.onDestroy() + timer.interrupt() +// mediaPlayer?.release() // 미디어플레이어가 갖고 있던 리소스 해제 +// mediaPlayer? = null //미디어 플레이어 해제 + } + + //DB에서 모든 송들을 가져와 songs에 저장 + private fun initPlayList(){ + songDB = SongDatabase.getInstance(this)!! + songs.addAll(songDB.songDao().getSongs()) + } + + private fun initClickListener()= with(binding){ + //우측 상단 버튼 누르면 액티비티 종료 + songDownIb.setOnClickListener{ + finish() + } + //재생, 일시정지 + songMiniplayerIv.setOnClickListener { + setPlayerStatus(true) + } + songPauseIv.setOnClickListener { + setPlayerStatus(false) + } + + //이전곡/다음곡 + songPreviousIv.setOnClickListener { + moveSong(-1) + } + songNextIv.setOnClickListener { + moveSong(+1) + } + + songLikeIv.setOnClickListener { + setLike(songs[nowPos].isLike) + } + } + + //SharedPreference에서 id값을 받아와서 songid를 통해서 songs와 비교해서 index값을 구하는 함수 + private fun initSong() { + //sharedpreference에서 id를 받아옴 + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId", 0) + + //송의 id를 nowPos에 저장 + nowPos = getPlayingSongPosition(songId) + Log.d("now Song ID", songs[nowPos].id.toString()) + startTimer() //타이머 시작 + //뷰 렌더링, 미디어플레이어 시작 + setPlayer(songs[nowPos]) + } + + // + private fun getPlayingSongPosition(songId: Int): Int { + for(i in 0 until songs.size) { + if(songs[i].id==songId) { + return i + } + } + return 0 + } + + //좋아요 버튼 이벤트 + private fun setLike(isLike: Boolean) { + songs[nowPos].isLike = !isLike + songDB.songDao().updateIsLikeById(!isLike,songs[nowPos].id) + + if (!isLike) { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_on) + }else { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + } + + private fun moveSong(direct: Int) { + if (nowPos + direct<0) { + Toast.makeText(this, "first song", Toast.LENGTH_SHORT).show() + return + } + if (nowPos+direct >= songs.size) { + Toast.makeText(this, "last song", Toast.LENGTH_SHORT).show() + return + } + nowPos += direct + timer.interrupt() + + mediaPlayer?.release() + mediaPlayer = null + + setPlayer(songs[nowPos]) //뷰렌더링, 노래 시작 + startTimer() // ✅ 새 MediaPlayer로 세팅된 후 타이머 시작 + Log.d("현재 곡", songs[nowPos].music) + + } + + //송 데이터를 뷰에 렌더링하는 함수 + private fun setPlayer(song: Song) { + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + binding.songStartTimeTv.text = String.format("%02d:%02d", song.second / 60, song.second % 60) + binding.songEndTimeTv.text = String.format("%02d:%02d", song.playTime / 60, song.playTime % 60) + binding.songAlbumIv.setImageResource(song.coverImg!!) + binding.songProgressSb.progress = (song.second * 1000 / song.playTime) + + val music = resources.getIdentifier(song.music, "raw", this.packageName) + mediaPlayer = MediaPlayer.create(this, music) + + //좋아요 + if (song.isLike) { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_on) + }else { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + setPlayerStatus(song.isPlaying) + } + + //재생, 일시정지 버튼 로직 구현 함수 + private fun setPlayerStatus(isPlaying: Boolean) { + songs[nowPos].isPlaying = isPlaying + timer.isPlaying = isPlaying + if (isPlaying) { + binding.songMiniplayerIv.visibility = View.GONE + binding.songPauseIv.visibility = View.VISIBLE + mediaPlayer?.start() + } else { + binding.songMiniplayerIv.visibility = View.VISIBLE + binding.songPauseIv.visibility = View.GONE + if(mediaPlayer?.isPlaying==true) { // + mediaPlayer?.pause() + } + } + } + + //타이머 시작 함수 + private fun startTimer() { + timer = Timer(songs[nowPos].playTime, songs[nowPos].isPlaying) + timer.start() + } + + //재시작 함수 + private fun restart() { + timer.interrupt() // 기존 타이머 스레드 종료 + songs[nowPos].second = 0 // 곡 시간 초기화 + songs[nowPos].isPlaying = true // 재생 상태 설정 + setPlayer(songs[nowPos]) // 송 데이터를 다시 세팅 -> setPlayerStatus함수 호출 -> true이므로 ||버튼이 나옴 + startTimer() // 새로운 타이머 스레드를 생성하고 실행 + } + inner class Timer(private val playTime: Int, var isPlaying: Boolean = true) : Thread() { + private var second: Int = 0 // 타이머 텍스트뷰에 사용할 용도 + private var mills: Float = 0f // 경과된 시간 누적용, 시크바에 사용할 용도 + override fun run() { + super.run() + try { + while (true) { + if (second >= playTime) { + break + } + //노래가 재생중일동안 실행 + if (isPlaying) { + sleep(50) + mills += 50 + //시크바 갱신 + runOnUiThread { + binding.songProgressSb.progress = ((mills / playTime) * 100).toInt() + } + //타이머 텍스트뷰 갱신 + if (mills % 1000 == 0f) { + runOnUiThread { + binding.songStartTimeTv.text = + String.format("%02d:%02d", second / 60, second % 60) + } + second++ + } + } + } + } catch (e: InterruptedException) { //액티비티가 종료되었을 경우 스레드 종료 + Log.d("Song", "스레드가 죽었습니다. ${e.message}") + } + } + } + +} diff --git a/week08/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt b/week08/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt new file mode 100644 index 0000000..4e3e96d --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt @@ -0,0 +1,123 @@ +package com.example.flo.albumfrag + +import android.content.Context.MODE_PRIVATE +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.R +import com.example.flo.activities.MainActivity +import com.example.flo.databinding.FragmentAlbumBinding +import com.example.flo.data.album.Album +import com.example.flo.data.db.SongDatabase +import com.example.flo.data.like.Like +import com.example.flo.home.HomeFragment +import com.google.android.material.tabs.TabLayoutMediator +import com.google.gson.Gson + +class AlbumFragment : Fragment() { + lateinit var binding: FragmentAlbumBinding + private var gson: Gson = Gson() + + private val information = arrayListOf("수록곡", "상세정보", "영상") + private var isLiked: Boolean = false + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentAlbumBinding.inflate(inflater, container, false) + + //Home에서 넘어온 데이터 받아오기 + val albumData = arguments?.getString("album") + val album = gson.fromJson(albumData, Album::class.java) + + //Home에서 넘어온 데이터 반영 + isLiked = isLikedAlbum(album.id) + setInit(album) //앨범 정보 뷰바인딩 + setOnClickListeners(album) + + //홈프래그먼트로의 화면전환 + binding.albumBackIv.setOnClickListener { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commitAllowingStateLoss() + } + + //뷰페이저 어댑터 객체 생성시 앨범 id를 넘겨줌 -> 송프래그먼트(수록곡) 정보를 넘겨줌 + val albumAdapter = AlbumVPAdapter(this, album.id) + binding.albumContentVp.adapter = albumAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.albumContentTb, binding.albumContentVp) { tap, position -> + tap.text = information[position] + }.attach() + + return binding.root + + } + + //리팩토링 중. 일단 사용 x + private fun getAlbumDatas(): Album { + // 1. arguments로 전달받은 albumId 꺼내기 + val albumId = arguments?.getInt("albumId", 0) ?: 0 + // 2. DB에서 앨범 조회 + val songDB = SongDatabase.getInstance(requireContext())!! + val album = songDB.albumDao().getAlbum(albumId) + return album + } + + //앨범 정보 뷰바인딩 + private fun setInit(album: Album) { + binding.albumAlbumIv.setImageResource(album.coverImg!!) + binding.albumMusicTitleTv.text = album.title.toString() + binding.albumSingerNameTv.text = album.singer.toString() + if (isLiked) { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_on) + } else { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + } + + //SharedPreferences에서 JWT를 가져오는 메서드 + private fun getJwt(): Int { + val spf = activity?.getSharedPreferences("auth", MODE_PRIVATE) //activity?->프래그먼트에서의 작성방법 + return spf!!.getInt("jwt", 0) + } + + private fun likeAlbum(userId:Int, albumId:Int) { + val songDB = SongDatabase.getInstance(requireContext())!! + val like = Like(userId, albumId) + + songDB.albumDao().likeAlbum(like) + } + + private fun isLikedAlbum(albumId: Int): Boolean { + val songDB = SongDatabase.getInstance(requireContext())!! + val userId = getJwt() + + val likeId: Int? = songDB.albumDao().isLikedAlbum(userId, albumId) + return likeId != null //유저가 좋아요를 했으면 null이 아님 + } + + private fun disLikedAlbum(userId: Int, albumId: Int) { + val songDB = SongDatabase.getInstance(requireContext())!! + songDB.albumDao().disLikedAlbum(userId, albumId) + } + + private fun setOnClickListeners(album: Album) { + val userId = getJwt() + binding.albumLikeIv.setOnClickListener { + if (isLiked) { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_off) + disLikedAlbum(userId, album.id) + }else { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_on) + likeAlbum(userId, album.id) + } + } + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt b/week08/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt new file mode 100644 index 0000000..9abae00 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt @@ -0,0 +1,24 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class AlbumVPAdapter(fragment: Fragment, private val albumId: Int) : FragmentStateAdapter(fragment){ + + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + val bundle = Bundle().apply { + putInt("albumId", albumId+1) //이 방식이 맞나... + } + + return when (position) { + 0 -> SongFragment().apply { arguments = bundle } + 1 -> DetailFragment().apply { arguments = bundle } + else -> VideoFragment().apply { arguments = bundle } + } + + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt b/week08/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt new file mode 100644 index 0000000..cea0ae4 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt @@ -0,0 +1,37 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentDetailBinding + +class DetailFragment : Fragment() { + lateinit var binding : FragmentDetailBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailBinding.inflate(inflater, container, false) + + //앨범프래그먼트에서 전달한 데이터를 받음 + val singerName = arguments?.getString("singerName") + val albumTitle = arguments?.getString("albumTitle") + + Log.d("DetailFragment", "받은 가수 이름: $singerName") + Log.d("DetailFragment", "받은 앨범 제목: $albumTitle") + + + binding.singerNameTv.text = singerName + binding.albumNameTv.text = albumTitle + + + return binding.root + } + + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt b/week08/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt new file mode 100644 index 0000000..26d8ae3 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt @@ -0,0 +1,47 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.R +import com.example.flo.databinding.FragmentSongBinding +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase + +class SongFragment : Fragment() { + lateinit var binding: FragmentSongBinding + private var songDatas = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentSongBinding.inflate(inflater, container, false) + + // 전달받은 albumId 꺼내기 + val albumId = arguments?.getInt("albumId", 0) ?: 0 + + // DB에서 수록곡 조회 + val songDB = SongDatabase.getInstance(requireContext())!! + songDatas = ArrayList(songDB.songDao().getSongsInAlbum(albumId)) + + // 리사이클러뷰 어댑터 등록 + val songRVAdapter = SongRVAdapter(songDatas) + binding.albumTrackRv.adapter = songRVAdapter + binding.albumTrackRv.layoutManager = LinearLayoutManager(context) + + // 믹스 토글 버튼 + var isON = false + binding.songMixoffTg.setOnClickListener { + isON = !isON + binding.songMixoffTg.setImageResource( + if (isON) R.drawable.btn_toggle_on else R.drawable.btn_toggle_off + ) + } + return binding.root + } +} diff --git a/week08/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt b/week08/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt new file mode 100644 index 0000000..e435166 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt @@ -0,0 +1,40 @@ +package com.example.flo.albumfrag + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSongBinding +import com.example.flo.data.song.Song + +class SongRVAdapter(private var songList: ArrayList): RecyclerView.Adapter(){ + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSongBinding = ItemSongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songList[position]) + } + + override fun getItemCount():Int = songList.size + + inner class ViewHolder(var binding: ItemSongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListOrderTv.text = song.num + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt b/week08/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt new file mode 100644 index 0000000..d337c6a --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt @@ -0,0 +1,23 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentVideoBinding + +class VideoFragment : Fragment() { + lateinit var binding : FragmentVideoBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentVideoBinding.inflate(inflater, container, false) + + return binding.root + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/data/album/Album.kt b/week08/app/src/main/java/com/example/flo/data/album/Album.kt new file mode 100644 index 0000000..3cb2b1b --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/album/Album.kt @@ -0,0 +1,13 @@ +package com.example.flo.data.album + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "AlbumTable") +data class Album ( + @PrimaryKey(autoGenerate = false) var id: Int = 0, //이렇게 하는 의도가 정확히 뭘까..? + var title: String = "", + var singer: String = "", + var isLike: Boolean = false, + var coverImg: Int? = null, +) \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/data/album/AlbumDao.kt b/week08/app/src/main/java/com/example/flo/data/album/AlbumDao.kt new file mode 100644 index 0000000..e54354d --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/album/AlbumDao.kt @@ -0,0 +1,43 @@ +package com.example.flo.data.album + +import androidx.room.* +import com.example.flo.data.like.Like + +@Dao +interface AlbumDao { + @Insert + fun insert(album: Album) + + @Update + fun update(album: Album) + + @Delete + fun delete(album: Album) + + @Query("SELECT * FROM AlbumTable") // 테이블의 모든 값을 가져와라 + fun getAlbums(): List + + //WHERE을 조건문처럼 사용, id값으로 해당하는 앨범을 받아옴 + @Query("SELECT*FROM AlbumTable WHERE id=:id") + fun getAlbum(id: Int): Album + + //LikeTable 사용 + + @Insert + fun likeAlbum(like: Like) + + //좋아요 했는지 안했는지 확인 + @Query("SELECT id FROM LikeTable WHERE userId = :userId AND albumId =:albumId") + fun isLikedAlbum(userId:Int, albumId:Int): Int? + + //앨범 좋아요 취소 + @Query("DELETE FROM LikeTable WHERE userId = :userId AND albumId =:albumId") + fun disLikedAlbum(userId:Int, albumId:Int): Int? + + //LikeTable, AlbumTable을 각각 LT, AT로 대신 사용하겠다 + //LEFT JOIN on : 왼쪽에 있는 LT를 기준으로 조인을 시켜주겠다. 즉 테이블을 붙임 -> LT.albumID=AT.id가 되도록! + //현재 사용자와 LT에 있는 userId가 같은 것들의 정보만 모두 가져와라 + @Query("SELECT AT.* FROM LikeTable as LT LEFT JOIN AlbumTable as AT on LT.albumId = AT.id WHERE LT.userId = :userId") + fun getLikedAlbums(userId:Int) : List + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/data/db/SongDatabase.kt b/week08/app/src/main/java/com/example/flo/data/db/SongDatabase.kt new file mode 100644 index 0000000..7af4b00 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/db/SongDatabase.kt @@ -0,0 +1,39 @@ +package com.example.flo.data.db + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.example.flo.data.album.Album +import com.example.flo.data.album.AlbumDao +import com.example.flo.data.like.Like +import com.example.flo.data.song.Song +import com.example.flo.data.song.SongDao +import com.example.flo.data.user.User +import com.example.flo.data.user.UserDao + +@Database(entities = [Song::class, Album::class, User::class, Like::class], version = 4) +abstract class SongDatabase: RoomDatabase() { + abstract fun songDao(): SongDao + abstract fun albumDao(): AlbumDao + abstract fun userDao(): UserDao + + companion object { + private var instance: SongDatabase? = null + + @Synchronized + fun getInstance(context: Context): SongDatabase? { + if (instance==null) { + synchronized(SongDatabase::class){ + instance = Room.databaseBuilder( + context.applicationContext, + SongDatabase::class.java, + name = "song-database" //다른 데이터 베이스랑 이름 겹치면 꼬임 + ).fallbackToDestructiveMigration().allowMainThreadQueries().build() //원래는 메인 스레드로 하는 게 아님 + } + } + return instance + } + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/data/like/Like.kt b/week08/app/src/main/java/com/example/flo/data/like/Like.kt new file mode 100644 index 0000000..6567454 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/like/Like.kt @@ -0,0 +1,12 @@ +package com.example.flo.data.like + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "LikeTable") +data class Like( + var userId: Int, + var albumId: Int +){ + @PrimaryKey(autoGenerate = true) var id:Int = 0 +} diff --git a/week08/app/src/main/java/com/example/flo/data/song/Song.kt b/week08/app/src/main/java/com/example/flo/data/song/Song.kt new file mode 100644 index 0000000..f9405d1 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/song/Song.kt @@ -0,0 +1,22 @@ +package com.example.flo.data.song + +import androidx.room.Entity +import androidx.room.PrimaryKey + +//제목, 가수, 사진, 재생시간, 현재 재생시간, isPlaying(재생 되고 있는지) + +@Entity(tableName = "SongTable") +data class Song( + val num : String? = "01", + var title: String = "", + var singer: String = "", + var second: Int = 0, + var playTime: Int = 0, + var isPlaying: Boolean = false, + var music: String = "", + var coverImg: Int? = null, + var isLike: Boolean = false, + var albumIdx: Int? = 0 +){ + @PrimaryKey(autoGenerate = true) var id: Int = 0 +} diff --git a/week08/app/src/main/java/com/example/flo/data/song/SongDao.kt b/week08/app/src/main/java/com/example/flo/data/song/SongDao.kt new file mode 100644 index 0000000..bbd4753 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/song/SongDao.kt @@ -0,0 +1,38 @@ +package com.example.flo.data.song + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update + +@Dao +interface SongDao { + @Insert + fun insert(song: Song) + @Update + fun update(song: Song) + + @Delete + fun delete(song: Song) + + //SELECT:데이터를 선택해서 가져와라, *: 모든 데이터를, FROM: 어디서 가져올지 + @Query("SELECT*FROM SongTable") + fun getSongs(): List + + //WHERE을 조건문처럼 사용, id값으로 해당하는 송을 받아옴 + @Query("SELECT*FROM SongTable WHERE id=:id") + fun getSong(id: Int): Song + + //좋아요를 했을 때 DB에 곡의 id를 추가하는 함수 + @Query("UPDATE SongTable SET isLike= :isLike WHERE id = :id") + fun updateIsLikeById(isLike: Boolean, id: Int) + + //DB에서 좋아요 된 곡들을 가져오는 함수 + @Query("SELECT*FROM SongTable WHERE isLike = :isLike") + fun getLikedSongs(isLike: Boolean): List + + @Query("SELECT * FROM SongTable WHERE albumIdx = :albumIdx") + fun getSongsInAlbum(albumIdx: Int): List + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/data/user/User.kt b/week08/app/src/main/java/com/example/flo/data/user/User.kt new file mode 100644 index 0000000..5bb37e9 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/user/User.kt @@ -0,0 +1,12 @@ +package com.example.flo.data.user + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "UserTable") +data class User( + var email: String, + var password: String +){ + @PrimaryKey(autoGenerate = true) var id: Int = 0 +} diff --git a/week08/app/src/main/java/com/example/flo/data/user/UserDao.kt b/week08/app/src/main/java/com/example/flo/data/user/UserDao.kt new file mode 100644 index 0000000..1732aa8 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/data/user/UserDao.kt @@ -0,0 +1,20 @@ +package com.example.flo.data.user + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query + +@Dao +interface UserDao { + + @Insert + fun insert(user: User) + + //모든 유저들의 정보를 가져옴 + @Query("SELECT*FROM UserTable") + fun getUsers(): List + + //유저 한 명의 정보를 가져옴 + @Query("SELECT*FROM UserTable WHERE email= :email AND password = :password") + fun getUser(email:String, password:String) : User? //정보가 있을수도 있고 없을수도 있으니 nullable처리 +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt b/week08/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt new file mode 100644 index 0000000..5558800 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt @@ -0,0 +1,63 @@ +package com.example.flo.home + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemAlbumBinding +import com.example.flo.data.album.Album + +class AlbumRVAdapter(private var albumList: ArrayList): RecyclerView.Adapter() { + + //리스너 인터페이스 정의 + interface MyItemClickListener { + fun onItemClick(album: Album) +// fun onRemoveAlbum(position: Int) + } + private lateinit var myItemClickListener: MyItemClickListener + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun addItem(album: Album) { + albumList.add(album) + notifyDataSetChanged() + } + +// fun removeItem(position: Int) { +// albumList.removeAt(position) +// notifyDataSetChanged() +// } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemAlbumBinding = ItemAlbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + //아이템 뷰 객체를 던져줌 + return ViewHolder(binding) + } + + // 뷰홀더에 데이터를 바인딩해줄때마다 호출, 클릭 이벤트 작성 + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.itemView.setOnClickListener { myItemClickListener.onItemClick(albumList[position]) } + //holder.binding.itemAlbumTitleTv.setOnClickListener { myItemClickListener.onRemoveAlbum(position) } + } + + //데이터 세트 크기를 알려줌. 리사이클러뷰의 끝이 어딘지 + override fun getItemCount(): Int = albumList.size + + //뷰홀더 클래스 + inner class ViewHolder(var binding: ItemAlbumBinding): RecyclerView.ViewHolder(binding.root) { + + fun bind(album: Album) { + binding.itemAlbumTitleTv.text = album.title + binding.itemAlbumSingerTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImg!!) + } + + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/home/BannerFragment.kt b/week08/app/src/main/java/com/example/flo/home/BannerFragment.kt new file mode 100644 index 0000000..145a504 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/home/BannerFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentBannerBinding + +//인자를 넣어서 새로운 배너 프래그먼트 추가 +class BannerFragment(val imgRes : Int) : Fragment() { + lateinit var binding : FragmentBannerBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBannerBinding.inflate(inflater, container, false) + + binding.bannerImageIv.setImageResource(imgRes) + + return binding.root + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt b/week08/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt new file mode 100644 index 0000000..e406726 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt @@ -0,0 +1,23 @@ +package com.example.flo.home + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class BannerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + + private val fragmentlist : ArrayList = ArrayList() + + override fun getItemCount(): Int { // 데이터를 몇개를 전달할 것이냐 + return fragmentlist.size + } + + override fun createFragment(position: Int): Fragment = fragmentlist[position] + + //리스트에 추가하는 함수 + fun addFragment(fragment: Fragment) { + fragmentlist.add(fragment) + notifyItemInserted(fragmentlist.size - 1) //뷰페이저에게 새로운 값이 추가가 됐다고 알림 + } + + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/home/HomeFragment.kt b/week08/app/src/main/java/com/example/flo/home/HomeFragment.kt new file mode 100644 index 0000000..fa97565 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/home/HomeFragment.kt @@ -0,0 +1,116 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.viewpager2.widget.ViewPager2 +import com.example.flo.albumfrag.AlbumFragment +import com.example.flo.R +import com.example.flo.databinding.FragmentHomeBinding +import com.example.flo.data.album.Album +import com.example.flo.activities.MainActivity +import com.example.flo.data.db.SongDatabase +import com.google.gson.Gson + +class HomeFragment : Fragment() { + lateinit var binding: FragmentHomeBinding + private var albumDatas = ArrayList() // 오늘의 앨범에 나올 앨범들을 위함 + + private lateinit var songDB: SongDatabase + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentHomeBinding.inflate(inflater, container, false) + + //데이터 리스트 생성 더미 데이터 + songDB = SongDatabase.getInstance(requireContext())!! + albumDatas.addAll(songDB.albumDao().getAlbums()) + + //inputDummyAlbums() //DB에 앨범데이터 삽입(초기설정용) + + //albumDatas = getTodayAlbumDatas() //DB에서 앨범 리스트 가져오기 + + //리사이클러뷰 어댑터 등록 (앨범 나열) + val albumRVAdapter = AlbumRVAdapter(albumDatas) + binding.homeTodayMusicAlbumRv.adapter = albumRVAdapter + + //리사이클러뷰의 레이아웃 매니저 설정 + binding.homeTodayMusicAlbumRv.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, false + ) + + //등록한 리사이클러뷰 어댑터 객체에 클릭리스너 세팅 + albumRVAdapter.setMyItemClickListener(object : AlbumRVAdapter.MyItemClickListener { + override fun onItemClick(album: Album) { + changeAlbumFragment(album) //앨범프래그먼트로 전환 시 클릭한 앨범의 id 전달 + } + +// override fun onRemoveAlbum(position: Int) { +// albumRVAdapter.removeItem(position) +// } + }) + + //뷰페이저2에 광고 배너들 연결 + val bannerAdapter = BannerVPAdapter(this) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + binding.homeBannerVp.adapter = bannerAdapter + + //광고 뷰 페이저가 좌우로 스크롤 될수 있도록 지정 + binding.homeBannerVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + return binding.root + } + + //앨범프래그먼트로 전환 시 클릭한 앨범 데이터를 JSON으로 전달 + private fun changeAlbumFragment(album: Album) { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, AlbumFragment().apply { + arguments = Bundle().apply { + val gson = Gson() + val albumJson = gson.toJson(album) + putString("album", albumJson) + } + }) + .commitAllowingStateLoss() + } + + //리팩토링 중, 일단 사용 X + private fun inputDummyAlbums() { + //DB인스턴스를 만든다 + val songDB = SongDatabase.getInstance(requireContext())!! + val albums = songDB.albumDao().getAlbums() + + //앨범 데이터가 있다면 종료 + if (albums.isNotEmpty()) return + + //데이터가 없을 경우 -> 앨범 데이터 삽입 + songDB.albumDao().apply { + insert(Album(1, "LILAC", "아이유 (IU)", false, R.drawable.img_album_exp2)) + insert(Album(2, "GREAT!", "모모랜드 (MOMOLAND)", false, R.drawable.img_great_album_exp)) + insert(Album(3, "Butter", "방탄소년단 (BTS)", false, R.drawable.img_album_exp)) + insert(Album(4, "LOST CORNER", "요네즈 켄시 (Kenshi Yonezu)", false, R.drawable.img_iris_album_exp)) + insert(Album(5, "END THEORY", "윤하 (YOUNHA)", false, R.drawable.img_oort_album_exp)) + } + } + + //리팩토링 중, 일단 사용 X + private fun getTodayAlbumDatas(): ArrayList { + val songDB = SongDatabase.getInstance(requireContext())!! + albumDatas = ArrayList(songDB.albumDao().getAlbums()) // DB에서 앨범 리스트 가져오기 + return albumDatas + } + + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/LockerFragment.kt b/week08/app/src/main/java/com/example/flo/locker/LockerFragment.kt new file mode 100644 index 0000000..b25ed1f --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/LockerFragment.kt @@ -0,0 +1,85 @@ +package com.example.flo.locker + +import android.content.Context.MODE_PRIVATE +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import com.example.flo.activities.LoginActivity +import com.example.flo.activities.MainActivity +import com.example.flo.databinding.FragmentLockerBinding +import com.google.android.material.tabs.TabLayoutMediator + +class LockerFragment : Fragment() { + lateinit var binding: FragmentLockerBinding +// private var songDatas = ArrayList< SavedSong>() + + private val information = arrayListOf("저장한 곡", "음악피일", "저장앨범") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLockerBinding.inflate(inflater, container, false) + + //뷰페이저 어댑터 등록 + val lockerAdapter = LockerVPAdapter(this) + binding.lockerContentVp.adapter = lockerAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.lockerContentTb, binding.lockerContentVp) { tap, position -> + tap.text = information[position] + + }.attach() + + //로그인 액티비티로 화면전환 +// binding.login.setOnClickListener { +// startActivity(Intent(activity, LoginActivity::class.java)) +// } + return binding.root + } + + override fun onStart() { + super.onStart() + initView() + } + + //SharedPreferences에서 JWT를 가져오는 메서드 + private fun getJwt(): Int { + val spf = activity?.getSharedPreferences("auth", MODE_PRIVATE) //activity?->프래그먼트에서의 작성방법 + return spf!!.getInt("jwt", 0) + } + + //로그인으로 할지 로그아웃으로 할지 뷰를 결정, 클릭리스너도 담당 + private fun initView() { + val jwt: Int = getJwt() + if (jwt == 0) { + binding.login.text = "로그인" + binding.login.setOnClickListener { + startActivity(Intent(activity, LoginActivity::class.java)) + } + } + + else { + binding.login.text = "로그아웃" + binding.login.setOnClickListener { + //로그아웃 진행 + logout() + startActivity(Intent(activity, MainActivity::class.java)) + } + } + } + + //로그아웃 함수. SharedPreferences에서 jwt를 제거한다 + private fun logout() { + val spf = activity?.getSharedPreferences("auth", AppCompatActivity.MODE_PRIVATE) + val editor = spf!!.edit() + editor.remove("jwt") + editor.apply() + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt b/week08/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt new file mode 100644 index 0000000..4d1c8ae --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt @@ -0,0 +1,42 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.data.song.Song + +class LockerRVAdapter(private var songs: ArrayList) : RecyclerView.Adapter() + { + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.itemView.setOnClickListener { + + } + } + + override fun getItemCount(): Int = songs.size + + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt b/week08/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt new file mode 100644 index 0000000..1351ad8 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt @@ -0,0 +1,29 @@ +package com.example.flo.locker + +import android.util.Log +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class LockerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + Log.d("FragmentCheck2", "createfrag") + + return when(position) { + 0 -> { + SavedsongFragment() + + } + 1 -> { + SongfileFragment() + } + else -> { + SavedalbumFragment() + } + } + + } + + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt b/week08/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt new file mode 100644 index 0000000..ba9d2a1 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt @@ -0,0 +1,68 @@ +package com.example.flo.locker + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedalbumBinding +import com.example.flo.data.album.Album + +class SavedAlbumRVAdapter(): + RecyclerView.Adapter() { + + private val albums = ArrayList() + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveAlbum(albumId: Int) + } + + private lateinit var myItemClickListener: SavedAlbumRVAdapter.MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): SavedAlbumRVAdapter.ViewHolder { + val binding = ItemSavedalbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: SavedAlbumRVAdapter.ViewHolder, position: Int) { + holder.bind(albums[position]) + holder.binding.albumCrudIv.setOnClickListener { + myItemClickListener.onRemoveAlbum(albums[position].id) + removeAlbum(position) + } + } + + override fun getItemCount(): Int = albums.size + + @SuppressLint("NotifyDataSetChanged") + fun addAlbums(albumList: ArrayList) { + albums.clear() // 기존 리스트 비우고 + albums.addAll(albumList) // 새 리스트 추가 + notifyDataSetChanged() // 리사이클러뷰 갱신 + } + + @SuppressLint("NotifyDataSetChanged") + fun removeAlbum(position: Int) { + albums.removeAt(position) + notifyDataSetChanged() + } + inner class ViewHolder(var binding: ItemSavedalbumBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(album: Album) { + binding.albumTitleTv.text = album.title + binding.albumSingerNameTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImg!!) + //binding.albumInformationTv.text = album.information + } + + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt b/week08/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt new file mode 100644 index 0000000..f1f821c --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt @@ -0,0 +1,64 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.databinding.FragmentSavedalbumBinding +import com.example.flo.data.album.Album +import com.example.flo.data.db.SongDatabase + +class SavedalbumFragment : Fragment() { + + //갱신 + lateinit var binding : FragmentSavedalbumBinding + lateinit var albumDB: SongDatabase + + override fun onCreateView( + + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedalbumBinding.inflate(inflater, container, false) + albumDB = SongDatabase.getInstance(requireContext())!! + + return binding.root + } + + override fun onStart() { + super.onStart() + initRecyclerview() + } + + private fun initRecyclerview(){ + binding.savedAlbumRv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + + val savedAlbumRVAdapter = SavedAlbumRVAdapter() + + //이거 강사가 이상하게 한 것 같은데 내가 나중에 다시 해야겠다. + savedAlbumRVAdapter.setMyItemClickListener(object : SavedAlbumRVAdapter.MyItemClickListener{ + override fun onRemoveAlbum(albumId: Int) { + albumDB.albumDao().getLikedAlbums(getJwt()) + } + }) + + binding.savedAlbumRv.adapter = savedAlbumRVAdapter + + //리사이클러뷰에 좋아요한 앨범을 불러옴 + savedAlbumRVAdapter.addAlbums(albumDB.albumDao().getLikedAlbums(getJwt()) as ArrayList) + } + + private fun getJwt() : Int { + val spf = activity?.getSharedPreferences("auth" , AppCompatActivity.MODE_PRIVATE) + val jwt = spf!!.getInt("jwt", 0) + Log.d("MAIN_ACT/GET_JWT", "jwt_token: $jwt") + + return jwt + } + +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt b/week08/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt new file mode 100644 index 0000000..fed382e --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt @@ -0,0 +1,67 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSavedsongBinding +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase + +class SavedsongFragment : Fragment() { + + lateinit var binding : FragmentSavedsongBinding + lateinit var songDB: SongDatabase + //private var savedSongList = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedsongBinding.inflate(inflater, container, false) + songDB = SongDatabase.getInstance(requireContext())!! + + // 곡 리스트 더미 데이터 생성 +// savedSongList.apply { +// add(SavedSong(R.drawable.img_album_exp, "Butter", "방탄소년단 (BTS)")) +// add(SavedSong(R.drawable.img_album_exp2, "아이와 나의 바다", "아이유 (IU)")) +// add(SavedSong(R.drawable.img_first_album_default, "운명 교향곡", "베토벤 (Beethoven)")) +// } + + //리사이클러뷰 어댑터 등록 +// val savedsongRVAdapter = SavedsongRVAdapter() +// binding.savedSongRv.adapter = savedsongRVAdapter + + + //등록한 리사이클러뷰 어댑터 객체에 리스너 세팅 +// savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { +// override fun onRemoveSong(position: Int) { +// savedsongRVAdapter.removeItem(position) +// } +// }) + + return binding.root + } + + override fun onStart() { + super.onStart() + initRecyclerView() + } + + private fun initRecyclerView() { + //리사이클러뷰 어댑터 등록 + val savedsongRVAdapter = SavedsongRVAdapter() + savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { + override fun onRemoveSong(songId: Int) { + songDB.songDao().updateIsLikeById(false, songId) + } + }) + + binding.savedSongRv.adapter = savedsongRVAdapter + + savedsongRVAdapter.addSongs(songDB.songDao().getLikedSongs(true) as ArrayList) + + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt b/week08/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt new file mode 100644 index 0000000..bc73b13 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt @@ -0,0 +1,71 @@ +package com.example.flo.locker + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.data.song.Song + +class SavedsongRVAdapter(): RecyclerView.Adapter() { + private var songs = ArrayList() + + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveSong(songId: Int) + } + + private lateinit var myItemClickListener: MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.binding.songMoreIv.setOnClickListener { + myItemClickListener.onRemoveSong(songs[position].id) + removeSong(position) //리사이클러뷰에서 삭제 + } + + } + + override fun getItemCount():Int = songs.size + + @SuppressLint("NotifyDataSetChanged") + fun addSongs(songs: ArrayList) { + this.songs.clear() + this.songs.addAll(songs) + + notifyDataSetChanged() + } + + @SuppressLint("NotifyDataSetChanged") + fun removeSong(position: Int) { + songs.removeAt(position) + notifyDataSetChanged() + } + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListAlbumImgIv.setImageResource(song.coverImg!!) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/locker/SongfileFragment.kt b/week08/app/src/main/java/com/example/flo/locker/SongfileFragment.kt new file mode 100644 index 0000000..720d1b9 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/locker/SongfileFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSongfileBinding + +class SongfileFragment : Fragment() { + + lateinit var binding : FragmentSongfileBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongfileBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SongfileFragment onCreateView") + + return binding.root + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/look/LookFragment.kt b/week08/app/src/main/java/com/example/flo/look/LookFragment.kt new file mode 100644 index 0000000..d129ef6 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/look/LookFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.look + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentLookBinding + +class LookFragment : Fragment() { + lateinit var binding: FragmentLookBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLookBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/search/SearchFragment.kt b/week08/app/src/main/java/com/example/flo/search/SearchFragment.kt new file mode 100644 index 0000000..4ad6136 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/search/SearchFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.search + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSearchBinding + +class SearchFragment : Fragment() { + lateinit var binding: FragmentSearchBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSearchBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/services/Foreground.kt b/week08/app/src/main/java/com/example/flo/services/Foreground.kt new file mode 100644 index 0000000..06e86f6 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/services/Foreground.kt @@ -0,0 +1,48 @@ +package com.example.flo.services + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class Foreground : Service() { + + val CHANNEL_ID = "Foreground" + val NOTI_ID = 713 + fun createNotificationChannel() { + //API 26이상에서는 사전에 채널을 등록해야 함. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = + NotificationChannel(CHANNEL_ID, "FOREGROUND", NotificationManager.IMPORTANCE_HIGH) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + createNotificationChannel() + //내가 띄울 Notification을 띄운다. + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher_round) + .setContentTitle("ForegroundService") + .setContentText("Hello World!") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + startForeground(NOTI_ID, notification) + + return super.onStartCommand(intent, flags, startId) + } + + override fun onBind(intent: Intent): IBinder { + return Binder() + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/services/MusicService.kt b/week08/app/src/main/java/com/example/flo/services/MusicService.kt new file mode 100644 index 0000000..4184776 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/services/MusicService.kt @@ -0,0 +1,128 @@ +package com.example.flo.services + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Intent +import android.media.MediaPlayer +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class MusicService : Service() { + + //채널 ID와 Notificiation ID는 자유롭게! + private val CHANNEL_ID = "ForegroundMusicService" + private val NOTI_ID = 713 + + private var mediaPlayer: MediaPlayer? = null + private val binder = MusicBinder() + + //현재 재생 중인 노래 정보를 저장할 변수 + private var currentSongTitle: String = "Unknown Title" + private var currentSongArtist: String = "Unknown Artist" + + //Activity에 Service 인스턴스를 전달 + inner class MusicBinder : Binder() { + fun getService(): MusicService = this@MusicService + } + + //서비스 시작 시 초기화 + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + //Notification 활성화 + createNotificationChannel() + + //Intent로 받은 정보들을 파싱 + val initialTitle = intent?.getStringExtra("songTitle") ?: "Unknown Title" + val initialArtist = intent?.getStringExtra("songArtist") ?: "Unknown Artist" + val isPlaying = intent?.getBooleanExtra("isPlaying", false) ?: false + + //MediaPlayer 및 변수 초기화 (임의로 노래를 연결) + if (mediaPlayer == null) { + mediaPlayer = MediaPlayer.create(this, R.raw.music_lilac) + currentSongTitle = initialTitle + currentSongArtist = initialArtist + if (isPlaying) { + mediaPlayer?.start() + } + } + + //알람도 같이 설정 + val notification = createNotification() + startForeground(NOTI_ID, notification) + + return START_STICKY + } + + override fun onBind(intent: Intent): IBinder { + return binder + } + + //알람 채널 설정(CHANNEL_ID와 name은 자유롭게 설정!) + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + "Foreground Music Service Channel", + NotificationManager.IMPORTANCE_HIGH + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + } + + //알람으로 노래가 재생중임을 표시 + private fun createNotification(): Notification { + val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle("음악 재생 중") + .setContentText("$currentSongTitle 이/가 재생 중입니다.") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setOngoing(true) + .setOnlyAlertOnce(true) + + return notificationBuilder.build() + } + + //외부에서 서비스에 접근 가능한 함수들 + //음악 재생 + fun playMusic() { + mediaPlayer?.start() + } + //음악 멈춤 + fun pauseMusic() { + mediaPlayer?.pause() + } + //인자로 받은 위치로 곡의 재생 위치 이동 + fun seekTo(position: Int) { + mediaPlayer?.seekTo(position) + } + //현재 재생중인 노래 정보 업데이트 + fun updateCurrentSongInfo(title: String, artist: String) { + currentSongTitle = title + currentSongArtist = artist + } + //현재 재생중인 노래의 길이 리턴 + fun getDuration(): Int { + return mediaPlayer?.duration ?: 0 + } + //현재 노래의 위치 리턴(SeekBar에 넣을 거) + fun getCurrentPosition(): Int { + return mediaPlayer?.currentPosition ?: 0 + } + //재생 중임? + fun isPlaying(): Boolean { + return mediaPlayer?.isPlaying ?: false + } + + override fun onDestroy() { + mediaPlayer?.stop() + mediaPlayer?.release() + mediaPlayer = null + super.onDestroy() + } +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/ui/theme/Color.kt b/week08/app/src/main/java/com/example/flo/ui/theme/Color.kt new file mode 100644 index 0000000..6b31678 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.flo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/ui/theme/Theme.kt b/week08/app/src/main/java/com/example/flo/ui/theme/Theme.kt new file mode 100644 index 0000000..cc69550 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.flo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FLOTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/week08/app/src/main/java/com/example/flo/ui/theme/Type.kt b/week08/app/src/main/java/com/example/flo/ui/theme/Type.kt new file mode 100644 index 0000000..9a198f8 --- /dev/null +++ b/week08/app/src/main/java/com/example/flo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.flo.ui.theme + +import androidx.compose.material3.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( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/apple_44.png b/week08/app/src/main/res/drawable/apple_44.png new file mode 100644 index 0000000..f365d20 Binary files /dev/null and b/week08/app/src/main/res/drawable/apple_44.png differ diff --git a/week08/app/src/main/res/drawable/btn_actionbar_close.png b/week08/app/src/main/res/drawable/btn_actionbar_close.png new file mode 100644 index 0000000..b6cc3cc Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_actionbar_close.png differ diff --git a/week08/app/src/main/res/drawable/btn_actionbar_instagram.png b/week08/app/src/main/res/drawable/btn_actionbar_instagram.png new file mode 100644 index 0000000..90bc027 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_actionbar_instagram.png differ diff --git a/week08/app/src/main/res/drawable/btn_arrow_black.png b/week08/app/src/main/res/drawable/btn_arrow_black.png new file mode 100644 index 0000000..cc38ca8 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_arrow_black.png differ diff --git a/week08/app/src/main/res/drawable/btn_arrow_more.png b/week08/app/src/main/res/drawable/btn_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_arrow_more.png differ diff --git a/week08/app/src/main/res/drawable/btn_color_selector.xml b/week08/app/src/main/res/drawable/btn_color_selector.xml new file mode 100644 index 0000000..3ecf8a7 --- /dev/null +++ b/week08/app/src/main/res/drawable/btn_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/btn_input_password.png b/week08/app/src/main/res/drawable/btn_input_password.png new file mode 100644 index 0000000..8c2eb18 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_input_password.png differ diff --git a/week08/app/src/main/res/drawable/btn_input_password_off.png b/week08/app/src/main/res/drawable/btn_input_password_off.png new file mode 100644 index 0000000..8234f53 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_input_password_off.png differ diff --git a/week08/app/src/main/res/drawable/btn_main_arrow_more.png b/week08/app/src/main/res/drawable/btn_main_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_main_arrow_more.png differ diff --git a/week08/app/src/main/res/drawable/btn_main_mike.png b/week08/app/src/main/res/drawable/btn_main_mike.png new file mode 100644 index 0000000..9bddec6 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_main_mike.png differ diff --git a/week08/app/src/main/res/drawable/btn_main_setting.png b/week08/app/src/main/res/drawable/btn_main_setting.png new file mode 100644 index 0000000..7a8d5d6 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_main_setting.png differ diff --git a/week08/app/src/main/res/drawable/btn_main_ticket.png b/week08/app/src/main/res/drawable/btn_main_ticket.png new file mode 100644 index 0000000..52b6d64 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_main_ticket.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplay_mvpause.png b/week08/app/src/main/res/drawable/btn_miniplay_mvpause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplay_mvpause.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplay_mvplay.png b/week08/app/src/main/res/drawable/btn_miniplay_mvplay.png new file mode 100644 index 0000000..d118677 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplay_mvplay.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplay_pause.png b/week08/app/src/main/res/drawable/btn_miniplay_pause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplay_pause.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplayer_go_list.png b/week08/app/src/main/res/drawable/btn_miniplayer_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplayer_go_list.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplayer_next.png b/week08/app/src/main/res/drawable/btn_miniplayer_next.png new file mode 100644 index 0000000..3aedba3 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplayer_next.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplayer_play.png b/week08/app/src/main/res/drawable/btn_miniplayer_play.png new file mode 100644 index 0000000..f619072 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplayer_play.png differ diff --git a/week08/app/src/main/res/drawable/btn_miniplayer_previous.png b/week08/app/src/main/res/drawable/btn_miniplayer_previous.png new file mode 100644 index 0000000..d0bf1f6 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_miniplayer_previous.png differ diff --git a/week08/app/src/main/res/drawable/btn_panel_play_large.png b/week08/app/src/main/res/drawable/btn_panel_play_large.png new file mode 100644 index 0000000..4ac7103 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_panel_play_large.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_eq_off.png b/week08/app/src/main/res/drawable/btn_player_eq_off.png new file mode 100644 index 0000000..f23d9c6 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_eq_off.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_go_list.png b/week08/app/src/main/res/drawable/btn_player_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_go_list.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_more.png b/week08/app/src/main/res/drawable/btn_player_more.png new file mode 100644 index 0000000..a8ad9e6 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_more.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_play.png b/week08/app/src/main/res/drawable/btn_player_play.png new file mode 100644 index 0000000..f6c3201 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_play.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_related.png b/week08/app/src/main/res/drawable/btn_player_related.png new file mode 100644 index 0000000..9026fe5 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_related.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_setting.png b/week08/app/src/main/res/drawable/btn_player_setting.png new file mode 100644 index 0000000..0df8f69 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_setting.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_unlike_off.png b/week08/app/src/main/res/drawable/btn_player_unlike_off.png new file mode 100644 index 0000000..b539504 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_unlike_off.png differ diff --git a/week08/app/src/main/res/drawable/btn_player_unlike_on.png b/week08/app/src/main/res/drawable/btn_player_unlike_on.png new file mode 100644 index 0000000..45a43ca Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_player_unlike_on.png differ diff --git a/week08/app/src/main/res/drawable/btn_playlist_select_off.png b/week08/app/src/main/res/drawable/btn_playlist_select_off.png new file mode 100644 index 0000000..62ef45c Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_playlist_select_off.png differ diff --git a/week08/app/src/main/res/drawable/btn_playlist_select_on.png b/week08/app/src/main/res/drawable/btn_playlist_select_on.png new file mode 100644 index 0000000..2d3b6af Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_playlist_select_on.png differ diff --git a/week08/app/src/main/res/drawable/btn_setting_phone.png b/week08/app/src/main/res/drawable/btn_setting_phone.png new file mode 100644 index 0000000..d6de4c6 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_setting_phone.png differ diff --git a/week08/app/src/main/res/drawable/btn_textbox_close.png b/week08/app/src/main/res/drawable/btn_textbox_close.png new file mode 100644 index 0000000..10f1f63 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_textbox_close.png differ diff --git a/week08/app/src/main/res/drawable/btn_titlebar_close.png b/week08/app/src/main/res/drawable/btn_titlebar_close.png new file mode 100644 index 0000000..6615def Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_titlebar_close.png differ diff --git a/week08/app/src/main/res/drawable/btn_toggle_off.png b/week08/app/src/main/res/drawable/btn_toggle_off.png new file mode 100644 index 0000000..983360d Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_toggle_off.png differ diff --git a/week08/app/src/main/res/drawable/btn_toggle_on.png b/week08/app/src/main/res/drawable/btn_toggle_on.png new file mode 100644 index 0000000..fb609f4 Binary files /dev/null and b/week08/app/src/main/res/drawable/btn_toggle_on.png differ diff --git a/week08/app/src/main/res/drawable/button_background_black_color.xml b/week08/app/src/main/res/drawable/button_background_black_color.xml new file mode 100644 index 0000000..a4afe1d --- /dev/null +++ b/week08/app/src/main/res/drawable/button_background_black_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/button_background_flo_color.xml b/week08/app/src/main/res/drawable/button_background_flo_color.xml new file mode 100644 index 0000000..046ded6 --- /dev/null +++ b/week08/app/src/main/res/drawable/button_background_flo_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/button_background_gray_color.xml b/week08/app/src/main/res/drawable/button_background_gray_color.xml new file mode 100644 index 0000000..3406c73 --- /dev/null +++ b/week08/app/src/main/res/drawable/button_background_gray_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/button_background_white_color.xml b/week08/app/src/main/res/drawable/button_background_white_color.xml new file mode 100644 index 0000000..679a1fd --- /dev/null +++ b/week08/app/src/main/res/drawable/button_background_white_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/discovery_banner_aos.jpg b/week08/app/src/main/res/drawable/discovery_banner_aos.jpg new file mode 100644 index 0000000..c905515 Binary files /dev/null and b/week08/app/src/main/res/drawable/discovery_banner_aos.jpg differ diff --git a/week08/app/src/main/res/drawable/fragment_look_chart_background.xml b/week08/app/src/main/res/drawable/fragment_look_chart_background.xml new file mode 100644 index 0000000..aae5110 --- /dev/null +++ b/week08/app/src/main/res/drawable/fragment_look_chart_background.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/fragment_look_chip_off_background.xml b/week08/app/src/main/res/drawable/fragment_look_chip_off_background.xml new file mode 100644 index 0000000..283cbe9 --- /dev/null +++ b/week08/app/src/main/res/drawable/fragment_look_chip_off_background.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/fragment_look_chip_on_background.xml b/week08/app/src/main/res/drawable/fragment_look_chip_on_background.xml new file mode 100644 index 0000000..e77b352 --- /dev/null +++ b/week08/app/src/main/res/drawable/fragment_look_chip_on_background.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/ic_all_album_play.xml b/week08/app/src/main/res/drawable/ic_all_album_play.xml new file mode 100644 index 0000000..21f11cb --- /dev/null +++ b/week08/app/src/main/res/drawable/ic_all_album_play.xml @@ -0,0 +1,9 @@ + + + diff --git a/week08/app/src/main/res/drawable/ic_bottom_home_no_select.png b/week08/app/src/main/res/drawable/ic_bottom_home_no_select.png new file mode 100644 index 0000000..69a8ab6 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_bottom_home_no_select.png differ diff --git a/week08/app/src/main/res/drawable/ic_bottom_locker_no_select.png b/week08/app/src/main/res/drawable/ic_bottom_locker_no_select.png new file mode 100644 index 0000000..a67dec3 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_bottom_locker_no_select.png differ diff --git a/week08/app/src/main/res/drawable/ic_bottom_look_no_select.png b/week08/app/src/main/res/drawable/ic_bottom_look_no_select.png new file mode 100644 index 0000000..6c2f4f0 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_bottom_look_no_select.png differ diff --git a/week08/app/src/main/res/drawable/ic_bottom_search_no_select.png b/week08/app/src/main/res/drawable/ic_bottom_search_no_select.png new file mode 100644 index 0000000..a77b8c5 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_bottom_search_no_select.png differ diff --git a/week08/app/src/main/res/drawable/ic_browse_arrow_right.png b/week08/app/src/main/res/drawable/ic_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_browse_arrow_right.png differ diff --git a/week08/app/src/main/res/drawable/ic_check.xml b/week08/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..bec5bec --- /dev/null +++ b/week08/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,12 @@ + + + diff --git a/week08/app/src/main/res/drawable/ic_flo_logo.png b/week08/app/src/main/res/drawable/ic_flo_logo.png new file mode 100644 index 0000000..643224d Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_flo_logo.png differ diff --git a/week08/app/src/main/res/drawable/ic_launcher_background.xml b/week08/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/week08/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week08/app/src/main/res/drawable/ic_launcher_foreground.xml b/week08/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/week08/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/ic_main_facebook.png b/week08/app/src/main/res/drawable/ic_main_facebook.png new file mode 100644 index 0000000..83e9732 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_main_facebook.png differ diff --git a/week08/app/src/main/res/drawable/ic_main_instagram.png b/week08/app/src/main/res/drawable/ic_main_instagram.png new file mode 100644 index 0000000..398ce61 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_main_instagram.png differ diff --git a/week08/app/src/main/res/drawable/ic_main_twitter.png b/week08/app/src/main/res/drawable/ic_main_twitter.png new file mode 100644 index 0000000..6ddc68e Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_main_twitter.png differ diff --git a/week08/app/src/main/res/drawable/ic_main_youtube.png b/week08/app/src/main/res/drawable/ic_main_youtube.png new file mode 100644 index 0000000..0c4ec93 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_main_youtube.png differ diff --git a/week08/app/src/main/res/drawable/ic_my_like_off.png b/week08/app/src/main/res/drawable/ic_my_like_off.png new file mode 100644 index 0000000..c06e139 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_my_like_off.png differ diff --git a/week08/app/src/main/res/drawable/ic_my_like_on.png b/week08/app/src/main/res/drawable/ic_my_like_on.png new file mode 100644 index 0000000..22577c0 Binary files /dev/null and b/week08/app/src/main/res/drawable/ic_my_like_on.png differ diff --git a/week08/app/src/main/res/drawable/ico_20_logo_tid_white.png b/week08/app/src/main/res/drawable/ico_20_logo_tid_white.png new file mode 100644 index 0000000..c6f4d4f Binary files /dev/null and b/week08/app/src/main/res/drawable/ico_20_logo_tid_white.png differ diff --git a/week08/app/src/main/res/drawable/icon_browse_arrow_right.png b/week08/app/src/main/res/drawable/icon_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week08/app/src/main/res/drawable/icon_browse_arrow_right.png differ diff --git a/week08/app/src/main/res/drawable/img_album_exp.png b/week08/app/src/main/res/drawable/img_album_exp.png new file mode 100644 index 0000000..6e3f38a Binary files /dev/null and b/week08/app/src/main/res/drawable/img_album_exp.png differ diff --git a/week08/app/src/main/res/drawable/img_album_exp2.png b/week08/app/src/main/res/drawable/img_album_exp2.png new file mode 100644 index 0000000..28ea3ee Binary files /dev/null and b/week08/app/src/main/res/drawable/img_album_exp2.png differ diff --git a/week08/app/src/main/res/drawable/img_album_lp.png b/week08/app/src/main/res/drawable/img_album_lp.png new file mode 100644 index 0000000..29fb1b4 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_album_lp.png differ diff --git a/week08/app/src/main/res/drawable/img_first_album_default.png b/week08/app/src/main/res/drawable/img_first_album_default.png new file mode 100644 index 0000000..926d34f Binary files /dev/null and b/week08/app/src/main/res/drawable/img_first_album_default.png differ diff --git a/week08/app/src/main/res/drawable/img_great_album_exp.jpg b/week08/app/src/main/res/drawable/img_great_album_exp.jpg new file mode 100644 index 0000000..33efe01 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_great_album_exp.jpg differ diff --git a/week08/app/src/main/res/drawable/img_home_viewpager_exp.png b/week08/app/src/main/res/drawable/img_home_viewpager_exp.png new file mode 100644 index 0000000..da78032 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_home_viewpager_exp.png differ diff --git a/week08/app/src/main/res/drawable/img_home_viewpager_exp2.png b/week08/app/src/main/res/drawable/img_home_viewpager_exp2.png new file mode 100644 index 0000000..50fa4be Binary files /dev/null and b/week08/app/src/main/res/drawable/img_home_viewpager_exp2.png differ diff --git a/week08/app/src/main/res/drawable/img_iris_album_exp.jpg b/week08/app/src/main/res/drawable/img_iris_album_exp.jpg new file mode 100644 index 0000000..040d531 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_iris_album_exp.jpg differ diff --git a/week08/app/src/main/res/drawable/img_jenre_exp_1.png b/week08/app/src/main/res/drawable/img_jenre_exp_1.png new file mode 100644 index 0000000..0d43e8e Binary files /dev/null and b/week08/app/src/main/res/drawable/img_jenre_exp_1.png differ diff --git a/week08/app/src/main/res/drawable/img_jenre_exp_2.png b/week08/app/src/main/res/drawable/img_jenre_exp_2.png new file mode 100644 index 0000000..f03efb2 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_jenre_exp_2.png differ diff --git a/week08/app/src/main/res/drawable/img_jenre_exp_3.png b/week08/app/src/main/res/drawable/img_jenre_exp_3.png new file mode 100644 index 0000000..51de684 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_jenre_exp_3.png differ diff --git a/week08/app/src/main/res/drawable/img_oort_album_exp.jpg b/week08/app/src/main/res/drawable/img_oort_album_exp.jpg new file mode 100644 index 0000000..d9b06ab Binary files /dev/null and b/week08/app/src/main/res/drawable/img_oort_album_exp.jpg differ diff --git a/week08/app/src/main/res/drawable/img_potcast_exp.png b/week08/app/src/main/res/drawable/img_potcast_exp.png new file mode 100644 index 0000000..50a46e0 Binary files /dev/null and b/week08/app/src/main/res/drawable/img_potcast_exp.png differ diff --git a/week08/app/src/main/res/drawable/img_video_exp.png b/week08/app/src/main/res/drawable/img_video_exp.png new file mode 100644 index 0000000..7f6b05f Binary files /dev/null and b/week08/app/src/main/res/drawable/img_video_exp.png differ diff --git a/week08/app/src/main/res/drawable/kakako_44.png b/week08/app/src/main/res/drawable/kakako_44.png new file mode 100644 index 0000000..243298e Binary files /dev/null and b/week08/app/src/main/res/drawable/kakako_44.png differ diff --git a/week08/app/src/main/res/drawable/naver_44.png b/week08/app/src/main/res/drawable/naver_44.png new file mode 100644 index 0000000..d984487 Binary files /dev/null and b/week08/app/src/main/res/drawable/naver_44.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_down.png b/week08/app/src/main/res/drawable/nugu_btn_down.png new file mode 100644 index 0000000..03a04c5 Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_down.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_pause_32.png b/week08/app/src/main/res/drawable/nugu_btn_pause_32.png new file mode 100644 index 0000000..9388aa3 Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_pause_32.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_play_32.png b/week08/app/src/main/res/drawable/nugu_btn_play_32.png new file mode 100644 index 0000000..b781e4c Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_play_32.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_random_inactive.png b/week08/app/src/main/res/drawable/nugu_btn_random_inactive.png new file mode 100644 index 0000000..fe4f880 Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_random_inactive.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_repeat_inactive.png b/week08/app/src/main/res/drawable/nugu_btn_repeat_inactive.png new file mode 100644 index 0000000..1e4044d Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_repeat_inactive.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_skip_next_32.png b/week08/app/src/main/res/drawable/nugu_btn_skip_next_32.png new file mode 100644 index 0000000..fc02f28 Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_skip_next_32.png differ diff --git a/week08/app/src/main/res/drawable/nugu_btn_skip_previous_32.png b/week08/app/src/main/res/drawable/nugu_btn_skip_previous_32.png new file mode 100644 index 0000000..03ec854 Binary files /dev/null and b/week08/app/src/main/res/drawable/nugu_btn_skip_previous_32.png differ diff --git a/week08/app/src/main/res/drawable/splash.xml b/week08/app/src/main/res/drawable/splash.xml new file mode 100644 index 0000000..da83aa4 --- /dev/null +++ b/week08/app/src/main/res/drawable/splash.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/textview_background_radius.xml b/week08/app/src/main/res/drawable/textview_background_radius.xml new file mode 100644 index 0000000..d250c1e --- /dev/null +++ b/week08/app/src/main/res/drawable/textview_background_radius.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/textview_background_select_color_radius.xml b/week08/app/src/main/res/drawable/textview_background_select_color_radius.xml new file mode 100644 index 0000000..8aaca4c --- /dev/null +++ b/week08/app/src/main/res/drawable/textview_background_select_color_radius.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/drawable/widget_black_play.png b/week08/app/src/main/res/drawable/widget_black_play.png new file mode 100644 index 0000000..0ec2700 Binary files /dev/null and b/week08/app/src/main/res/drawable/widget_black_play.png differ diff --git a/week08/app/src/main/res/layout/activity/activity_test.xml b/week08/app/src/main/res/layout/activity/activity_test.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/week08/app/src/main/res/layout/activity/activity_test.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/activity_login.xml b/week08/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..7a3b16f --- /dev/null +++ b/week08/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/activity_main.xml b/week08/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..3f45054 --- /dev/null +++ b/week08/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/activity_signup.xml b/week08/app/src/main/res/layout/activity_signup.xml new file mode 100644 index 0000000..7a0c00b --- /dev/null +++ b/week08/app/src/main/res/layout/activity_signup.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/activity_song.xml b/week08/app/src/main/res/layout/activity_song.xml new file mode 100644 index 0000000..73a6cc4 --- /dev/null +++ b/week08/app/src/main/res/layout/activity_song.xml @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/activity_splash.xml b/week08/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 0000000..29ce312 --- /dev/null +++ b/week08/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_album.xml b/week08/app/src/main/res/layout/fragment_album.xml new file mode 100644 index 0000000..79aaf13 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_album.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_banner.xml b/week08/app/src/main/res/layout/fragment_banner.xml new file mode 100644 index 0000000..b7ef866 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_banner.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_detail.xml b/week08/app/src/main/res/layout/fragment_detail.xml new file mode 100644 index 0000000..151ebe6 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_detail.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_home.xml b/week08/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..90215e6 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_locker.xml b/week08/app/src/main/res/layout/fragment_locker.xml new file mode 100644 index 0000000..c37d43c --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_locker.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week08/app/src/main/res/layout/fragment_look.xml b/week08/app/src/main/res/layout/fragment_look.xml new file mode 100644 index 0000000..31b020c --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_look.xml @@ -0,0 +1,516 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_savedalbum.xml b/week08/app/src/main/res/layout/fragment_savedalbum.xml new file mode 100644 index 0000000..c395bf2 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_savedalbum.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/week08/app/src/main/res/layout/fragment_savedsong.xml b/week08/app/src/main/res/layout/fragment_savedsong.xml new file mode 100644 index 0000000..41fb837 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_savedsong.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_search.xml b/week08/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..301f760 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_song.xml b/week08/app/src/main/res/layout/fragment_song.xml new file mode 100644 index 0000000..439b6f3 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_song.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_songfile.xml b/week08/app/src/main/res/layout/fragment_songfile.xml new file mode 100644 index 0000000..05dca29 --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_songfile.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/fragment_video.xml b/week08/app/src/main/res/layout/fragment_video.xml new file mode 100644 index 0000000..70e650d --- /dev/null +++ b/week08/app/src/main/res/layout/fragment_video.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/item_album.xml b/week08/app/src/main/res/layout/item_album.xml new file mode 100644 index 0000000..99ae14e --- /dev/null +++ b/week08/app/src/main/res/layout/item_album.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/item_savedalbum.xml b/week08/app/src/main/res/layout/item_savedalbum.xml new file mode 100644 index 0000000..cabe757 --- /dev/null +++ b/week08/app/src/main/res/layout/item_savedalbum.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/item_savedsong.xml b/week08/app/src/main/res/layout/item_savedsong.xml new file mode 100644 index 0000000..fc292d7 --- /dev/null +++ b/week08/app/src/main/res/layout/item_savedsong.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/layout/item_song.xml b/week08/app/src/main/res/layout/item_song.xml new file mode 100644 index 0000000..bf9e8a2 --- /dev/null +++ b/week08/app/src/main/res/layout/item_song.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/menu/bottom_nav_menu.xml b/week08/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000..2b56b8c --- /dev/null +++ b/week08/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week08/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week08/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week08/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week08/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week08/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/week08/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/week08/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week08/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/week08/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/week08/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week08/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/week08/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/week08/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week08/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/week08/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/week08/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week08/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/week08/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/week08/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week08/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/week08/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/week08/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week08/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/week08/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/week08/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week08/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/week08/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/week08/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week08/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/week08/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/week08/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week08/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/week08/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/week08/app/src/main/res/raw/music_bboom.mp3 b/week08/app/src/main/res/raw/music_bboom.mp3 new file mode 100644 index 0000000..9b1e5db Binary files /dev/null and b/week08/app/src/main/res/raw/music_bboom.mp3 differ diff --git a/week08/app/src/main/res/raw/music_butter.mp3 b/week08/app/src/main/res/raw/music_butter.mp3 new file mode 100644 index 0000000..94ffc91 Binary files /dev/null and b/week08/app/src/main/res/raw/music_butter.mp3 differ diff --git a/week08/app/src/main/res/raw/music_irisout.mp3 b/week08/app/src/main/res/raw/music_irisout.mp3 new file mode 100644 index 0000000..7e40d8d Binary files /dev/null and b/week08/app/src/main/res/raw/music_irisout.mp3 differ diff --git a/week08/app/src/main/res/raw/music_lilac.mp3 b/week08/app/src/main/res/raw/music_lilac.mp3 new file mode 100644 index 0000000..7c85690 Binary files /dev/null and b/week08/app/src/main/res/raw/music_lilac.mp3 differ diff --git a/week08/app/src/main/res/raw/music_oortcloud.mp3 b/week08/app/src/main/res/raw/music_oortcloud.mp3 new file mode 100644 index 0000000..7e7cbf8 Binary files /dev/null and b/week08/app/src/main/res/raw/music_oortcloud.mp3 differ diff --git a/week08/app/src/main/res/values/colors.xml b/week08/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..71cd486 --- /dev/null +++ b/week08/app/src/main/res/values/colors.xml @@ -0,0 +1,24 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FFD3D3D3 + #FF0000FF + #3f3fff + + #9cbee2 + #062342 + #424242 + #6bb2ff + + #00ff0000 + #3f3fff + #a8a8a8 + #3f3fff + #a8a8a8 + \ No newline at end of file diff --git a/week08/app/src/main/res/values/strings.xml b/week08/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..63f5ff1 --- /dev/null +++ b/week08/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + FLO + + Hello blank fragment + \ No newline at end of file diff --git a/week08/app/src/main/res/values/themes.xml b/week08/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e76a4bf --- /dev/null +++ b/week08/app/src/main/res/values/themes.xml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/xml/backup_rules.xml b/week08/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..4df9255 --- /dev/null +++ b/week08/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/week08/app/src/main/res/xml/data_extraction_rules.xml b/week08/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/week08/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week08/app/src/test/java/com/example/flo/ExampleUnitTest.kt b/week08/app/src/test/java/com/example/flo/ExampleUnitTest.kt new file mode 100644 index 0000000..d39df20 --- /dev/null +++ b/week08/app/src/test/java/com/example/flo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.flo + +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/week08/build.gradle.kts b/week08/build.gradle.kts new file mode 100644 index 0000000..952b930 --- /dev/null +++ b/week08/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} \ No newline at end of file diff --git a/week08/gradle.properties b/week08/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/week08/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. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-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/week08/gradle/libs.versions.toml b/week08/gradle/libs.versions.toml new file mode 100644 index 0000000..339d205 --- /dev/null +++ b/week08/gradle/libs.versions.toml @@ -0,0 +1,36 @@ +[versions] +agp = "8.13.0" +kotlin = "2.0.21" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2024.09.00" +constraintlayout = "2.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version = "2.2.21" } + + diff --git a/week08/gradle/wrapper/gradle-wrapper.jar b/week08/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/week08/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week08/gradle/wrapper/gradle-wrapper.properties b/week08/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..af10ccc --- /dev/null +++ b/week08/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Sep 28 16:12:35 KST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week08/gradlew b/week08/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/week08/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/week08/gradlew.bat b/week08/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/week08/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/week08/settings.gradle.kts b/week08/settings.gradle.kts new file mode 100644 index 0000000..2a48c99 --- /dev/null +++ b/week08/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "FLO" +include(":app") + \ No newline at end of file diff --git a/week09/.gitignore b/week09/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/week09/.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/week09/.idea/.name b/week09/.idea/.name new file mode 100644 index 0000000..997352e --- /dev/null +++ b/week09/.idea/.name @@ -0,0 +1 @@ +FLO \ No newline at end of file diff --git a/week09/.idea/AndroidProjectSystem.xml b/week09/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/week09/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/week09/.idea/compiler.xml b/week09/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/week09/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week09/.idea/deploymentTargetSelector.xml b/week09/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..c716954 --- /dev/null +++ b/week09/.idea/deploymentTargetSelector.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/week09/.idea/deviceManager.xml b/week09/.idea/deviceManager.xml new file mode 100644 index 0000000..eebfe8e --- /dev/null +++ b/week09/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week09/.idea/gradle.xml b/week09/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/week09/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week09/.idea/inspectionProfiles/Project_Default.xml b/week09/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7061a0d --- /dev/null +++ b/week09/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,61 @@ + + + + \ No newline at end of file diff --git a/week09/.idea/migrations.xml b/week09/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/week09/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/week09/.idea/misc.xml b/week09/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/week09/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/week09/.idea/runConfigurations.xml b/week09/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/week09/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week09/.idea/vcs.xml b/week09/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/week09/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/.gitignore b/week09/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/week09/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/week09/app/build.gradle.kts b/week09/app/build.gradle.kts new file mode 100644 index 0000000..16ba0c1 --- /dev/null +++ b/week09/app/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + + id("kotlin-kapt") + +} + +android { + namespace = "com.example.flo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.example.flo" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("androidx.fragment:fragment:1.8.9") + implementation("com.google.android.material:material:1.13.0") + implementation("androidx.viewpager2:viewpager2:1.1.0") + implementation("com.tbuonomo:dotsindicator:5.1.0") + implementation("androidx.recyclerview:recyclerview:1.4.0") + implementation("com.google.code.gson:gson:2.13.2") + implementation("androidx.core:core-splashscreen:1.0.1") + + //roomDB + implementation("androidx.room:room-ktx:2.8.3") + implementation("androidx.room:room-runtime:2.8.3") + //implementation("androidx.room:room-compiler:2.8.3") + kapt("androidx.room:room-compiler:2.8.3") +} \ No newline at end of file diff --git a/week09/app/proguard-rules.pro b/week09/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/week09/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/week09/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt b/week09/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..6dfac89 --- /dev/null +++ b/week09/app/src/androidTest/java/com/example/flo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.flo + +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.flo", appContext.packageName) + } +} \ No newline at end of file diff --git a/week09/app/src/main/AndroidManifest.xml b/week09/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..55bc47b --- /dev/null +++ b/week09/app/src/main/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/activities/LoginActivity.kt b/week09/app/src/main/java/com/example/flo/activities/LoginActivity.kt new file mode 100644 index 0000000..d271884 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/activities/LoginActivity.kt @@ -0,0 +1,70 @@ +package com.example.flo.activities + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.data.db.SongDatabase +import com.example.flo.databinding.ActivityLoginBinding + +class LoginActivity : AppCompatActivity() { + private lateinit var binding: ActivityLoginBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding.root) + + //회원가입액티비티로의 화면전환 + binding.loginSignUpTv.setOnClickListener { + startActivity(Intent(this, SignUpActivity::class.java)) + } + + binding.loginSignInBtn.setOnClickListener { + login() + } + } + + //로그인 처리 함수 + private fun login() { + //예외 처리 + if (binding.loginIdEt.text.toString().isEmpty() || binding.loginDirectInputEt.text.toString().isEmpty()) { + Toast.makeText(this, "이메일을 입력해주세요", Toast.LENGTH_SHORT).show() + return + } + if (binding.loginPasswordEt.text.toString().isEmpty()) { + Toast.makeText(this, "비밀번호를 입력해주세요", Toast.LENGTH_SHORT).show() + return + } + + val email : String = binding.loginIdEt.text.toString() + "@" + binding.loginDirectInputEt.text.toString() + val pwd: String = binding.loginPasswordEt.text.toString() + + val songDB = SongDatabase.getInstance(this)!! + val user = songDB.userDao().getUser(email, pwd) + + //user가 null이 아니면 다음을 실행하라 + user?.let { + Log.d("LOGIN_ACT/GET_USER", "userId : ${user.id}, $user") + saveJwt(user.id) + startMainActivity() + } + Toast.makeText(this, "회원 정보가 존재하지 않습니다.", Toast.LENGTH_SHORT).show() + } + + private fun saveJwt(jwt:Int) { + val spf = getSharedPreferences("auth", MODE_PRIVATE) + val editor = spf.edit() + + editor.putInt("jwt", jwt) + editor.apply() + } + private fun startMainActivity() { + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/activities/MainActivity.kt b/week09/app/src/main/java/com/example/flo/activities/MainActivity.kt new file mode 100644 index 0000000..7f36ec1 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/activities/MainActivity.kt @@ -0,0 +1,250 @@ +package com.example.flo.activities + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.home.HomeFragment +import com.example.flo.locker.LockerFragment +import com.example.flo.look.LookFragment +import com.example.flo.R +import com.example.flo.data.album.Album +import com.example.flo.search.SearchFragment +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase +import com.example.flo.databinding.ActivityMainBinding +import com.google.gson.Gson + +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + + private var song:Song = Song() + private var gson: Gson = Gson() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setTheme(R.style.Theme_FLO) + enableEdgeToEdge() + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + inputDummySongs() //더미 송 데이터 db에 삽입 + inputDummyAlbums() //더미 앨범 데이터 db에 삽입 + + //하단플레이어에 나오는 노래를 Song객체에 저장 -> roomDB로 대체 +// val song = Song( +// title = binding.mainMiniplayerTitleTv.text.toString(), +// singer = binding.mainMiniplayerSingerTv.text.toString(), +// second = 0, playTime = 60, isPlaying = false, music = "music_lilac" +// ) + + //하단의 플레이어를 누르면 송액티비티로 전환. 이때 sharedPreference에 노래의 id를 저장 + binding.mainPlayerCl.setOnClickListener { + //에디터를 만들고 + val editor = getSharedPreferences("song", MODE_PRIVATE).edit() + + //송의 id를 넣어준다. + editor.putInt("songId", song.id) + + //최종 커밋 + editor.apply() + + //인텐트는 단순 전환 기능만. sharedPrefernece와 DB가 알아서 해주니까. + val intent = Intent(this, SongActivity::class.java) + startActivity(intent) + } + + //실행 시 첫 화면 설정 -> 홈프래그먼트 + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + + //BottomNavigationView를 눌렀을 때 Fragment 변경하기 + binding.mainBnv.setOnItemSelectedListener { item -> + when (item.itemId) { + //매인 화면 + R.id.homeFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commit() + true + } + //둘러보기 화면 + R.id.lookFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LookFragment()) + .commit() + true + } + //검색 화면 + R.id.searchFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, SearchFragment()) + .commit() + true + } + //보관함 화면 + R.id.lockerFragment -> { + supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, LockerFragment()) + .commit() + true + } + else -> false + } + } + } + + //메인 액티비티가 시작될 때-> sharedprference에서 id값을 가져와서 DB에서 해당 id에 해당하는 song을 가져옴 + override fun onStart() { + super.onStart() + //sharedprference에서 id값을 가져옴 + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId", 0) + + //DB인스턴스를 만들고 + val songDB = SongDatabase.getInstance(this)!! + + //DB에서 해당 id에 해당하는 song을 가져옴 + song = if (songId==0) { + songDB.songDao().getSong(1) + } else { + songDB.songDao().getSong(songId) + } + + Log.d("song ID", song.id.toString()) // 디버깅 + + //가져온 송 데이터를 뷰바인딩 + setMiniPlayer(song) + } + + private fun setMiniPlayer(song: Song){ + binding.mainMiniplayerTitleTv.text = song.title + binding.mainMiniplayerSingerTv.text = song.singer + binding.mainProgressSb.progress = (song.second*100000)/song.playTime + } + + //DB에 데이터가 없다면 더미 데이터를 넣는 작업 + private fun inputDummySongs() { + val songDB = SongDatabase.getInstance(this)!! + val songs = songDB.songDao().getSongs() + + //데이터가 있다면 종료 + if (songs.isNotEmpty()) return + + //데이터가 없을 경우 + songDB.songDao().insert( + Song( + title = "Lilac", + singer = "아이유 (IU)", + second = 0, + playTime = 230, + isPlaying = false, + music = "music_lilac", + coverImg = R.drawable.img_album_exp2, + isLike = false, + //albumIdx = 1 + ) + ) + + songDB.songDao().insert( + Song( + title = "BBoom BBoom", + singer = "모모랜드 (MOMOLAND)", + second = 0, + playTime = 240, + isPlaying = false, + music = "music_bboom", + coverImg = R.drawable.img_great_album_exp, + isLike = false, + //albumIdx = 2 + ) + ) + + songDB.songDao().insert( + Song( + title = "Butter", + singer = "방탄소년단 (BTS)", + second = 0, + playTime = 180, + isPlaying = false, + music = "music_butter", + coverImg = R.drawable.img_album_exp, + isLike = false, + //albumIdx = 3 + ) + ) + + songDB.songDao().insert( + Song( + title = "IRIS OUT", + singer = "요네즈 켄시 (Kenshi Yonezu)", + second = 0, + playTime = 155, + isPlaying = false, + music = "music_irisout", + coverImg = R.drawable.img_iris_album_exp, + isLike = false, + //albumIdx = 4 + ) + ) + + songDB.songDao().insert( + Song( + title = "Oort Cloud (오르트 구름)", + singer = "윤하 (YOUNHA)", + second = 0, + playTime = 210, + isPlaying = false, + music = "music_oortcloud", + coverImg = R.drawable.img_oort_album_exp, + isLike = false, + //albumIdx = 5 + ) + ) + //DB에 데이터가 잘 들어갔는지 로그로 확인 + val _songs = songDB.songDao().getSongs() //테이블의 모든 송을 가져옴 + Log.d("DB data", _songs.toString()) //DB에 데이터가 잘 들어갔는지 확인 + } + + //ROOM_DB + private fun inputDummyAlbums() { + val songDB = SongDatabase.getInstance(this)!! + val albums = songDB.albumDao().getAlbums() + + if (albums.isNotEmpty()) return + + songDB.albumDao().insert( + Album( + 0, + "IU 5th Album 'LILAC'", "아이유 (IU)", coverImg = R.drawable.img_album_exp2 + ) + ) + songDB.albumDao().insert( + Album( + 1, + "GREAT!", "모모랜드 (MOMOLAND)", coverImg = R.drawable.img_great_album_exp + ) + ) + songDB.albumDao().insert( + Album( + 2, + "Butter", "방탄소년단 (BTS)", coverImg = R.drawable.img_album_exp + ) + ) + songDB.albumDao().insert( + Album( + 3, + "LOST CORNER", "요네즈 켄시 (Kenshi Yonezu)", coverImg = R.drawable.img_iris_album_exp + ) + ) + songDB.albumDao().insert( + Album( + 4, + "END THEORY", "윤하 (YOUNHA)", coverImg = R.drawable.img_oort_album_exp + ) + ) + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/activities/SignUpActivity.kt b/week09/app/src/main/java/com/example/flo/activities/SignUpActivity.kt new file mode 100644 index 0000000..33c1a08 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/activities/SignUpActivity.kt @@ -0,0 +1,57 @@ +package com.example.flo.activities + +import android.os.Bundle +import android.util.Log + +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.data.db.SongDatabase + +import com.example.flo.data.user.User +import com.example.flo.databinding.ActivitySignupBinding + +class SignUpActivity : AppCompatActivity() { + private lateinit var binding: ActivitySignupBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySignupBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.signUpSignUpBtn.setOnClickListener { + signUp() //회원가입 + finish() //로그인액티비티로 이동 + } + } + + //유저 정보를 가져오는 메서드 + private fun getUser(): User { + val email : String = binding.signUpIdEt.text.toString() + "@" + binding.signUpDirectInputEt.text.toString() + val pwd: String = binding.signUpPasswordEt.text.toString() + + return User(email, pwd) + } + + //회원가입 메서드 + private fun signUp() { + //예외 처리 + if (binding.signUpIdEt.text.toString().isEmpty() || binding.signUpDirectInputEt.text.toString().isEmpty()) { + Toast.makeText(this, "이메일 형식이 잘못되었습니다.", Toast.LENGTH_SHORT).show() + return + } + if (binding.signUpPasswordEt.text.toString() != binding.signUpPasswordCheckEt.text.toString()) { + Toast.makeText(this, "비밀번호가 일치하지 않습니다.", Toast.LENGTH_SHORT).show() + return + } + + //입력한 정보를 DB에 저장 + val userDB = SongDatabase.getInstance(this)!! + userDB.userDao().insert(getUser()) + + //디버깅 + val user = userDB.userDao().getUsers() + Log.d("SIGNUPACT", user.toString()) + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/activities/SongActivity.kt b/week09/app/src/main/java/com/example/flo/activities/SongActivity.kt new file mode 100644 index 0000000..08f4572 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/activities/SongActivity.kt @@ -0,0 +1,262 @@ +package com.example.flo.activities + +import android.graphics.Color +import android.graphics.PorterDuff +import android.media.MediaPlayer +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.example.flo.databinding.ActivitySongBinding +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase +import com.google.gson.Gson +import com.example.flo.R + +class SongActivity : AppCompatActivity() { + private lateinit var binding: ActivitySongBinding + //lateinit var song: Song // 첫 isPlaying은 False + + lateinit var timer: Timer + private var mediaPlayer: MediaPlayer? = null + private var gson: Gson = Gson() + + // 재생할 "노래 목록(플레이리스트)"을 담기 위한 리스트. + // 여러 곡을 담고 이전곡/다음곡으로 이동할 수 있게 하기 위해 존재 + val songs = arrayListOf() + lateinit var songDB: SongDatabase // DB인스턴스 선언. DB CRUD작업을 할 때는 필수인 것 같다. + var nowPos = 0 //현재 곡을 가리키는 전역변수 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivitySongBinding.inflate(layoutInflater) + setContentView(binding.root) + initPlayList() //DB에서 모든 송들을 가져와 songs에 저장 + initSong() //송 데이터 받아와 실행 + initClickListener() + //setPlayer(songs[nowPos]) + + //반복재생 + var isRoop = false + binding.songRepeatIv.setOnClickListener { + if (!isRoop) { + binding.songRepeatIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + isRoop = true + } else { + binding.songRepeatIv.clearColorFilter() + isRoop = false + } + } + //전체재생(랜덤재생인듯?) + var willPlayAll = false + binding.songRandomIv.setOnClickListener { + if (!willPlayAll) { + binding.songRandomIv.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN) + willPlayAll = true + } else { + binding.songRandomIv.clearColorFilter() + willPlayAll = false + } + } + } + + // 사용자가 포커스를 잃었을 때 음악 중지 + override fun onPause() { + super.onPause() + setPlayerStatus(false) + songs[nowPos].second = ((binding.songProgressSb.progress * songs[nowPos].playTime) / 100) / 1000 + val sharedPreferences = getSharedPreferences("song", MODE_PRIVATE) + val editor = sharedPreferences.edit() //에디터 + + editor.putInt("songId", songs[nowPos].id) + + editor.apply() //꼭 쓰기!! 깃에서 push와 같음 + } + + //앱이 꺼질때 스레드 종료 + override fun onDestroy() { + super.onDestroy() + timer.interrupt() +// mediaPlayer?.release() // 미디어플레이어가 갖고 있던 리소스 해제 +// mediaPlayer? = null //미디어 플레이어 해제 + } + + //DB에서 모든 송들을 가져와 songs에 저장 + private fun initPlayList(){ + songDB = SongDatabase.getInstance(this)!! + songs.addAll(songDB.songDao().getSongs()) + } + + private fun initClickListener()= with(binding){ + //우측 상단 버튼 누르면 액티비티 종료 + songDownIb.setOnClickListener{ + finish() + } + //재생, 일시정지 + songMiniplayerIv.setOnClickListener { + setPlayerStatus(true) + } + songPauseIv.setOnClickListener { + setPlayerStatus(false) + } + + //이전곡/다음곡 + songPreviousIv.setOnClickListener { + moveSong(-1) + } + songNextIv.setOnClickListener { + moveSong(+1) + } + + songLikeIv.setOnClickListener { + setLike(songs[nowPos].isLike) + } + } + + //SharedPreference에서 id값을 받아와서 songid를 통해서 songs와 비교해서 index값을 구하는 함수 + private fun initSong() { + //sharedpreference에서 id를 받아옴 + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId", 0) + + //송의 id를 nowPos에 저장 + nowPos = getPlayingSongPosition(songId) + Log.d("now Song ID", songs[nowPos].id.toString()) + startTimer() //타이머 시작 + //뷰 렌더링, 미디어플레이어 시작 + setPlayer(songs[nowPos]) + } + + // + private fun getPlayingSongPosition(songId: Int): Int { + for(i in 0 until songs.size) { + if(songs[i].id==songId) { + return i + } + } + return 0 + } + + //좋아요 버튼 이벤트 + private fun setLike(isLike: Boolean) { + songs[nowPos].isLike = !isLike + songDB.songDao().updateIsLikeById(!isLike,songs[nowPos].id) + + if (!isLike) { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_on) + }else { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + } + + private fun moveSong(direct: Int) { + if (nowPos + direct<0) { + Toast.makeText(this, "first song", Toast.LENGTH_SHORT).show() + return + } + if (nowPos+direct >= songs.size) { + Toast.makeText(this, "last song", Toast.LENGTH_SHORT).show() + return + } + nowPos += direct + timer.interrupt() + + mediaPlayer?.release() + mediaPlayer = null + + setPlayer(songs[nowPos]) //뷰렌더링, 노래 시작 + startTimer() // ✅ 새 MediaPlayer로 세팅된 후 타이머 시작 + Log.d("현재 곡", songs[nowPos].music) + + } + + //송 데이터를 뷰에 렌더링하는 함수 + private fun setPlayer(song: Song) { + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + binding.songStartTimeTv.text = String.format("%02d:%02d", song.second / 60, song.second % 60) + binding.songEndTimeTv.text = String.format("%02d:%02d", song.playTime / 60, song.playTime % 60) + binding.songAlbumIv.setImageResource(song.coverImg!!) + binding.songProgressSb.progress = (song.second * 1000 / song.playTime) + + val music = resources.getIdentifier(song.music, "raw", this.packageName) + mediaPlayer = MediaPlayer.create(this, music) + + //좋아요 + if (song.isLike) { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_on) + }else { + binding.songLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + setPlayerStatus(song.isPlaying) + } + + //재생, 일시정지 버튼 로직 구현 함수 + private fun setPlayerStatus(isPlaying: Boolean) { + songs[nowPos].isPlaying = isPlaying + timer.isPlaying = isPlaying + if (isPlaying) { + binding.songMiniplayerIv.visibility = View.GONE + binding.songPauseIv.visibility = View.VISIBLE + mediaPlayer?.start() + } else { + binding.songMiniplayerIv.visibility = View.VISIBLE + binding.songPauseIv.visibility = View.GONE + if(mediaPlayer?.isPlaying==true) { // + mediaPlayer?.pause() + } + } + } + + //타이머 시작 함수 + private fun startTimer() { + timer = Timer(songs[nowPos].playTime, songs[nowPos].isPlaying) + timer.start() + } + + //재시작 함수 + private fun restart() { + timer.interrupt() // 기존 타이머 스레드 종료 + songs[nowPos].second = 0 // 곡 시간 초기화 + songs[nowPos].isPlaying = true // 재생 상태 설정 + setPlayer(songs[nowPos]) // 송 데이터를 다시 세팅 -> setPlayerStatus함수 호출 -> true이므로 ||버튼이 나옴 + startTimer() // 새로운 타이머 스레드를 생성하고 실행 + } + inner class Timer(private val playTime: Int, var isPlaying: Boolean = true) : Thread() { + private var second: Int = 0 // 타이머 텍스트뷰에 사용할 용도 + private var mills: Float = 0f // 경과된 시간 누적용, 시크바에 사용할 용도 + override fun run() { + super.run() + try { + while (true) { + if (second >= playTime) { + break + } + //노래가 재생중일동안 실행 + if (isPlaying) { + sleep(50) + mills += 50 + //시크바 갱신 + runOnUiThread { + binding.songProgressSb.progress = ((mills / playTime) * 100).toInt() + } + //타이머 텍스트뷰 갱신 + if (mills % 1000 == 0f) { + runOnUiThread { + binding.songStartTimeTv.text = + String.format("%02d:%02d", second / 60, second % 60) + } + second++ + } + } + } + } catch (e: InterruptedException) { //액티비티가 종료되었을 경우 스레드 종료 + Log.d("Song", "스레드가 죽었습니다. ${e.message}") + } + } + } + +} diff --git a/week09/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt b/week09/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt new file mode 100644 index 0000000..4e3e96d --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/albumfrag/AlbumFragment.kt @@ -0,0 +1,123 @@ +package com.example.flo.albumfrag + +import android.content.Context.MODE_PRIVATE +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.R +import com.example.flo.activities.MainActivity +import com.example.flo.databinding.FragmentAlbumBinding +import com.example.flo.data.album.Album +import com.example.flo.data.db.SongDatabase +import com.example.flo.data.like.Like +import com.example.flo.home.HomeFragment +import com.google.android.material.tabs.TabLayoutMediator +import com.google.gson.Gson + +class AlbumFragment : Fragment() { + lateinit var binding: FragmentAlbumBinding + private var gson: Gson = Gson() + + private val information = arrayListOf("수록곡", "상세정보", "영상") + private var isLiked: Boolean = false + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentAlbumBinding.inflate(inflater, container, false) + + //Home에서 넘어온 데이터 받아오기 + val albumData = arguments?.getString("album") + val album = gson.fromJson(albumData, Album::class.java) + + //Home에서 넘어온 데이터 반영 + isLiked = isLikedAlbum(album.id) + setInit(album) //앨범 정보 뷰바인딩 + setOnClickListeners(album) + + //홈프래그먼트로의 화면전환 + binding.albumBackIv.setOnClickListener { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, HomeFragment()) + .commitAllowingStateLoss() + } + + //뷰페이저 어댑터 객체 생성시 앨범 id를 넘겨줌 -> 송프래그먼트(수록곡) 정보를 넘겨줌 + val albumAdapter = AlbumVPAdapter(this, album.id) + binding.albumContentVp.adapter = albumAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.albumContentTb, binding.albumContentVp) { tap, position -> + tap.text = information[position] + }.attach() + + return binding.root + + } + + //리팩토링 중. 일단 사용 x + private fun getAlbumDatas(): Album { + // 1. arguments로 전달받은 albumId 꺼내기 + val albumId = arguments?.getInt("albumId", 0) ?: 0 + // 2. DB에서 앨범 조회 + val songDB = SongDatabase.getInstance(requireContext())!! + val album = songDB.albumDao().getAlbum(albumId) + return album + } + + //앨범 정보 뷰바인딩 + private fun setInit(album: Album) { + binding.albumAlbumIv.setImageResource(album.coverImg!!) + binding.albumMusicTitleTv.text = album.title.toString() + binding.albumSingerNameTv.text = album.singer.toString() + if (isLiked) { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_on) + } else { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_off) + } + } + + //SharedPreferences에서 JWT를 가져오는 메서드 + private fun getJwt(): Int { + val spf = activity?.getSharedPreferences("auth", MODE_PRIVATE) //activity?->프래그먼트에서의 작성방법 + return spf!!.getInt("jwt", 0) + } + + private fun likeAlbum(userId:Int, albumId:Int) { + val songDB = SongDatabase.getInstance(requireContext())!! + val like = Like(userId, albumId) + + songDB.albumDao().likeAlbum(like) + } + + private fun isLikedAlbum(albumId: Int): Boolean { + val songDB = SongDatabase.getInstance(requireContext())!! + val userId = getJwt() + + val likeId: Int? = songDB.albumDao().isLikedAlbum(userId, albumId) + return likeId != null //유저가 좋아요를 했으면 null이 아님 + } + + private fun disLikedAlbum(userId: Int, albumId: Int) { + val songDB = SongDatabase.getInstance(requireContext())!! + songDB.albumDao().disLikedAlbum(userId, albumId) + } + + private fun setOnClickListeners(album: Album) { + val userId = getJwt() + binding.albumLikeIv.setOnClickListener { + if (isLiked) { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_off) + disLikedAlbum(userId, album.id) + }else { + binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_on) + likeAlbum(userId, album.id) + } + } + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt b/week09/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt new file mode 100644 index 0000000..9abae00 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/albumfrag/AlbumVPAdapter.kt @@ -0,0 +1,24 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class AlbumVPAdapter(fragment: Fragment, private val albumId: Int) : FragmentStateAdapter(fragment){ + + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + val bundle = Bundle().apply { + putInt("albumId", albumId+1) //이 방식이 맞나... + } + + return when (position) { + 0 -> SongFragment().apply { arguments = bundle } + 1 -> DetailFragment().apply { arguments = bundle } + else -> VideoFragment().apply { arguments = bundle } + } + + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt b/week09/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt new file mode 100644 index 0000000..cea0ae4 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/albumfrag/DetailFragment.kt @@ -0,0 +1,37 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentDetailBinding + +class DetailFragment : Fragment() { + lateinit var binding : FragmentDetailBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailBinding.inflate(inflater, container, false) + + //앨범프래그먼트에서 전달한 데이터를 받음 + val singerName = arguments?.getString("singerName") + val albumTitle = arguments?.getString("albumTitle") + + Log.d("DetailFragment", "받은 가수 이름: $singerName") + Log.d("DetailFragment", "받은 앨범 제목: $albumTitle") + + + binding.singerNameTv.text = singerName + binding.albumNameTv.text = albumTitle + + + return binding.root + } + + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt b/week09/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt new file mode 100644 index 0000000..26d8ae3 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/albumfrag/SongFragment.kt @@ -0,0 +1,47 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.R +import com.example.flo.databinding.FragmentSongBinding +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase + +class SongFragment : Fragment() { + lateinit var binding: FragmentSongBinding + private var songDatas = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentSongBinding.inflate(inflater, container, false) + + // 전달받은 albumId 꺼내기 + val albumId = arguments?.getInt("albumId", 0) ?: 0 + + // DB에서 수록곡 조회 + val songDB = SongDatabase.getInstance(requireContext())!! + songDatas = ArrayList(songDB.songDao().getSongsInAlbum(albumId)) + + // 리사이클러뷰 어댑터 등록 + val songRVAdapter = SongRVAdapter(songDatas) + binding.albumTrackRv.adapter = songRVAdapter + binding.albumTrackRv.layoutManager = LinearLayoutManager(context) + + // 믹스 토글 버튼 + var isON = false + binding.songMixoffTg.setOnClickListener { + isON = !isON + binding.songMixoffTg.setImageResource( + if (isON) R.drawable.btn_toggle_on else R.drawable.btn_toggle_off + ) + } + return binding.root + } +} diff --git a/week09/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt b/week09/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt new file mode 100644 index 0000000..e435166 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/albumfrag/SongRVAdapter.kt @@ -0,0 +1,40 @@ +package com.example.flo.albumfrag + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSongBinding +import com.example.flo.data.song.Song + +class SongRVAdapter(private var songList: ArrayList): RecyclerView.Adapter(){ + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSongBinding = ItemSongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songList[position]) + } + + override fun getItemCount():Int = songList.size + + inner class ViewHolder(var binding: ItemSongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListOrderTv.text = song.num + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt b/week09/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt new file mode 100644 index 0000000..d337c6a --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/albumfrag/VideoFragment.kt @@ -0,0 +1,23 @@ +package com.example.flo.albumfrag + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentVideoBinding + +class VideoFragment : Fragment() { + lateinit var binding : FragmentVideoBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentVideoBinding.inflate(inflater, container, false) + + return binding.root + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/data/album/Album.kt b/week09/app/src/main/java/com/example/flo/data/album/Album.kt new file mode 100644 index 0000000..3cb2b1b --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/album/Album.kt @@ -0,0 +1,13 @@ +package com.example.flo.data.album + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "AlbumTable") +data class Album ( + @PrimaryKey(autoGenerate = false) var id: Int = 0, //이렇게 하는 의도가 정확히 뭘까..? + var title: String = "", + var singer: String = "", + var isLike: Boolean = false, + var coverImg: Int? = null, +) \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/data/album/AlbumDao.kt b/week09/app/src/main/java/com/example/flo/data/album/AlbumDao.kt new file mode 100644 index 0000000..e54354d --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/album/AlbumDao.kt @@ -0,0 +1,43 @@ +package com.example.flo.data.album + +import androidx.room.* +import com.example.flo.data.like.Like + +@Dao +interface AlbumDao { + @Insert + fun insert(album: Album) + + @Update + fun update(album: Album) + + @Delete + fun delete(album: Album) + + @Query("SELECT * FROM AlbumTable") // 테이블의 모든 값을 가져와라 + fun getAlbums(): List + + //WHERE을 조건문처럼 사용, id값으로 해당하는 앨범을 받아옴 + @Query("SELECT*FROM AlbumTable WHERE id=:id") + fun getAlbum(id: Int): Album + + //LikeTable 사용 + + @Insert + fun likeAlbum(like: Like) + + //좋아요 했는지 안했는지 확인 + @Query("SELECT id FROM LikeTable WHERE userId = :userId AND albumId =:albumId") + fun isLikedAlbum(userId:Int, albumId:Int): Int? + + //앨범 좋아요 취소 + @Query("DELETE FROM LikeTable WHERE userId = :userId AND albumId =:albumId") + fun disLikedAlbum(userId:Int, albumId:Int): Int? + + //LikeTable, AlbumTable을 각각 LT, AT로 대신 사용하겠다 + //LEFT JOIN on : 왼쪽에 있는 LT를 기준으로 조인을 시켜주겠다. 즉 테이블을 붙임 -> LT.albumID=AT.id가 되도록! + //현재 사용자와 LT에 있는 userId가 같은 것들의 정보만 모두 가져와라 + @Query("SELECT AT.* FROM LikeTable as LT LEFT JOIN AlbumTable as AT on LT.albumId = AT.id WHERE LT.userId = :userId") + fun getLikedAlbums(userId:Int) : List + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/data/db/SongDatabase.kt b/week09/app/src/main/java/com/example/flo/data/db/SongDatabase.kt new file mode 100644 index 0000000..7af4b00 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/db/SongDatabase.kt @@ -0,0 +1,39 @@ +package com.example.flo.data.db + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.example.flo.data.album.Album +import com.example.flo.data.album.AlbumDao +import com.example.flo.data.like.Like +import com.example.flo.data.song.Song +import com.example.flo.data.song.SongDao +import com.example.flo.data.user.User +import com.example.flo.data.user.UserDao + +@Database(entities = [Song::class, Album::class, User::class, Like::class], version = 4) +abstract class SongDatabase: RoomDatabase() { + abstract fun songDao(): SongDao + abstract fun albumDao(): AlbumDao + abstract fun userDao(): UserDao + + companion object { + private var instance: SongDatabase? = null + + @Synchronized + fun getInstance(context: Context): SongDatabase? { + if (instance==null) { + synchronized(SongDatabase::class){ + instance = Room.databaseBuilder( + context.applicationContext, + SongDatabase::class.java, + name = "song-database" //다른 데이터 베이스랑 이름 겹치면 꼬임 + ).fallbackToDestructiveMigration().allowMainThreadQueries().build() //원래는 메인 스레드로 하는 게 아님 + } + } + return instance + } + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/data/like/Like.kt b/week09/app/src/main/java/com/example/flo/data/like/Like.kt new file mode 100644 index 0000000..6567454 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/like/Like.kt @@ -0,0 +1,12 @@ +package com.example.flo.data.like + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "LikeTable") +data class Like( + var userId: Int, + var albumId: Int +){ + @PrimaryKey(autoGenerate = true) var id:Int = 0 +} diff --git a/week09/app/src/main/java/com/example/flo/data/song/Song.kt b/week09/app/src/main/java/com/example/flo/data/song/Song.kt new file mode 100644 index 0000000..f9405d1 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/song/Song.kt @@ -0,0 +1,22 @@ +package com.example.flo.data.song + +import androidx.room.Entity +import androidx.room.PrimaryKey + +//제목, 가수, 사진, 재생시간, 현재 재생시간, isPlaying(재생 되고 있는지) + +@Entity(tableName = "SongTable") +data class Song( + val num : String? = "01", + var title: String = "", + var singer: String = "", + var second: Int = 0, + var playTime: Int = 0, + var isPlaying: Boolean = false, + var music: String = "", + var coverImg: Int? = null, + var isLike: Boolean = false, + var albumIdx: Int? = 0 +){ + @PrimaryKey(autoGenerate = true) var id: Int = 0 +} diff --git a/week09/app/src/main/java/com/example/flo/data/song/SongDao.kt b/week09/app/src/main/java/com/example/flo/data/song/SongDao.kt new file mode 100644 index 0000000..bbd4753 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/song/SongDao.kt @@ -0,0 +1,38 @@ +package com.example.flo.data.song + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update + +@Dao +interface SongDao { + @Insert + fun insert(song: Song) + @Update + fun update(song: Song) + + @Delete + fun delete(song: Song) + + //SELECT:데이터를 선택해서 가져와라, *: 모든 데이터를, FROM: 어디서 가져올지 + @Query("SELECT*FROM SongTable") + fun getSongs(): List + + //WHERE을 조건문처럼 사용, id값으로 해당하는 송을 받아옴 + @Query("SELECT*FROM SongTable WHERE id=:id") + fun getSong(id: Int): Song + + //좋아요를 했을 때 DB에 곡의 id를 추가하는 함수 + @Query("UPDATE SongTable SET isLike= :isLike WHERE id = :id") + fun updateIsLikeById(isLike: Boolean, id: Int) + + //DB에서 좋아요 된 곡들을 가져오는 함수 + @Query("SELECT*FROM SongTable WHERE isLike = :isLike") + fun getLikedSongs(isLike: Boolean): List + + @Query("SELECT * FROM SongTable WHERE albumIdx = :albumIdx") + fun getSongsInAlbum(albumIdx: Int): List + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/data/user/User.kt b/week09/app/src/main/java/com/example/flo/data/user/User.kt new file mode 100644 index 0000000..5bb37e9 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/user/User.kt @@ -0,0 +1,12 @@ +package com.example.flo.data.user + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "UserTable") +data class User( + var email: String, + var password: String +){ + @PrimaryKey(autoGenerate = true) var id: Int = 0 +} diff --git a/week09/app/src/main/java/com/example/flo/data/user/UserDao.kt b/week09/app/src/main/java/com/example/flo/data/user/UserDao.kt new file mode 100644 index 0000000..1732aa8 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/data/user/UserDao.kt @@ -0,0 +1,20 @@ +package com.example.flo.data.user + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query + +@Dao +interface UserDao { + + @Insert + fun insert(user: User) + + //모든 유저들의 정보를 가져옴 + @Query("SELECT*FROM UserTable") + fun getUsers(): List + + //유저 한 명의 정보를 가져옴 + @Query("SELECT*FROM UserTable WHERE email= :email AND password = :password") + fun getUser(email:String, password:String) : User? //정보가 있을수도 있고 없을수도 있으니 nullable처리 +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt b/week09/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt new file mode 100644 index 0000000..5558800 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/home/AlbumRVAdapter.kt @@ -0,0 +1,63 @@ +package com.example.flo.home + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemAlbumBinding +import com.example.flo.data.album.Album + +class AlbumRVAdapter(private var albumList: ArrayList): RecyclerView.Adapter() { + + //리스너 인터페이스 정의 + interface MyItemClickListener { + fun onItemClick(album: Album) +// fun onRemoveAlbum(position: Int) + } + private lateinit var myItemClickListener: MyItemClickListener + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + fun addItem(album: Album) { + albumList.add(album) + notifyDataSetChanged() + } + +// fun removeItem(position: Int) { +// albumList.removeAt(position) +// notifyDataSetChanged() +// } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemAlbumBinding = ItemAlbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + //아이템 뷰 객체를 던져줌 + return ViewHolder(binding) + } + + // 뷰홀더에 데이터를 바인딩해줄때마다 호출, 클릭 이벤트 작성 + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(albumList[position]) + holder.itemView.setOnClickListener { myItemClickListener.onItemClick(albumList[position]) } + //holder.binding.itemAlbumTitleTv.setOnClickListener { myItemClickListener.onRemoveAlbum(position) } + } + + //데이터 세트 크기를 알려줌. 리사이클러뷰의 끝이 어딘지 + override fun getItemCount(): Int = albumList.size + + //뷰홀더 클래스 + inner class ViewHolder(var binding: ItemAlbumBinding): RecyclerView.ViewHolder(binding.root) { + + fun bind(album: Album) { + binding.itemAlbumTitleTv.text = album.title + binding.itemAlbumSingerTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImg!!) + } + + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/home/BannerFragment.kt b/week09/app/src/main/java/com/example/flo/home/BannerFragment.kt new file mode 100644 index 0000000..145a504 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/home/BannerFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentBannerBinding + +//인자를 넣어서 새로운 배너 프래그먼트 추가 +class BannerFragment(val imgRes : Int) : Fragment() { + lateinit var binding : FragmentBannerBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentBannerBinding.inflate(inflater, container, false) + + binding.bannerImageIv.setImageResource(imgRes) + + return binding.root + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt b/week09/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt new file mode 100644 index 0000000..e406726 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/home/BannerVPAdapter.kt @@ -0,0 +1,23 @@ +package com.example.flo.home + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class BannerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + + private val fragmentlist : ArrayList = ArrayList() + + override fun getItemCount(): Int { // 데이터를 몇개를 전달할 것이냐 + return fragmentlist.size + } + + override fun createFragment(position: Int): Fragment = fragmentlist[position] + + //리스트에 추가하는 함수 + fun addFragment(fragment: Fragment) { + fragmentlist.add(fragment) + notifyItemInserted(fragmentlist.size - 1) //뷰페이저에게 새로운 값이 추가가 됐다고 알림 + } + + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/home/HomeFragment.kt b/week09/app/src/main/java/com/example/flo/home/HomeFragment.kt new file mode 100644 index 0000000..fa97565 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/home/HomeFragment.kt @@ -0,0 +1,116 @@ +package com.example.flo.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.viewpager2.widget.ViewPager2 +import com.example.flo.albumfrag.AlbumFragment +import com.example.flo.R +import com.example.flo.databinding.FragmentHomeBinding +import com.example.flo.data.album.Album +import com.example.flo.activities.MainActivity +import com.example.flo.data.db.SongDatabase +import com.google.gson.Gson + +class HomeFragment : Fragment() { + lateinit var binding: FragmentHomeBinding + private var albumDatas = ArrayList() // 오늘의 앨범에 나올 앨범들을 위함 + + private lateinit var songDB: SongDatabase + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentHomeBinding.inflate(inflater, container, false) + + //데이터 리스트 생성 더미 데이터 + songDB = SongDatabase.getInstance(requireContext())!! + albumDatas.addAll(songDB.albumDao().getAlbums()) + + //inputDummyAlbums() //DB에 앨범데이터 삽입(초기설정용) + + //albumDatas = getTodayAlbumDatas() //DB에서 앨범 리스트 가져오기 + + //리사이클러뷰 어댑터 등록 (앨범 나열) + val albumRVAdapter = AlbumRVAdapter(albumDatas) + binding.homeTodayMusicAlbumRv.adapter = albumRVAdapter + + //리사이클러뷰의 레이아웃 매니저 설정 + binding.homeTodayMusicAlbumRv.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, false + ) + + //등록한 리사이클러뷰 어댑터 객체에 클릭리스너 세팅 + albumRVAdapter.setMyItemClickListener(object : AlbumRVAdapter.MyItemClickListener { + override fun onItemClick(album: Album) { + changeAlbumFragment(album) //앨범프래그먼트로 전환 시 클릭한 앨범의 id 전달 + } + +// override fun onRemoveAlbum(position: Int) { +// albumRVAdapter.removeItem(position) +// } + }) + + //뷰페이저2에 광고 배너들 연결 + val bannerAdapter = BannerVPAdapter(this) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) + bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) + binding.homeBannerVp.adapter = bannerAdapter + + //광고 뷰 페이저가 좌우로 스크롤 될수 있도록 지정 + binding.homeBannerVp.orientation = ViewPager2.ORIENTATION_HORIZONTAL + + return binding.root + } + + //앨범프래그먼트로 전환 시 클릭한 앨범 데이터를 JSON으로 전달 + private fun changeAlbumFragment(album: Album) { + (context as MainActivity).supportFragmentManager.beginTransaction() + .replace(R.id.main_frm, AlbumFragment().apply { + arguments = Bundle().apply { + val gson = Gson() + val albumJson = gson.toJson(album) + putString("album", albumJson) + } + }) + .commitAllowingStateLoss() + } + + //리팩토링 중, 일단 사용 X + private fun inputDummyAlbums() { + //DB인스턴스를 만든다 + val songDB = SongDatabase.getInstance(requireContext())!! + val albums = songDB.albumDao().getAlbums() + + //앨범 데이터가 있다면 종료 + if (albums.isNotEmpty()) return + + //데이터가 없을 경우 -> 앨범 데이터 삽입 + songDB.albumDao().apply { + insert(Album(1, "LILAC", "아이유 (IU)", false, R.drawable.img_album_exp2)) + insert(Album(2, "GREAT!", "모모랜드 (MOMOLAND)", false, R.drawable.img_great_album_exp)) + insert(Album(3, "Butter", "방탄소년단 (BTS)", false, R.drawable.img_album_exp)) + insert(Album(4, "LOST CORNER", "요네즈 켄시 (Kenshi Yonezu)", false, R.drawable.img_iris_album_exp)) + insert(Album(5, "END THEORY", "윤하 (YOUNHA)", false, R.drawable.img_oort_album_exp)) + } + } + + //리팩토링 중, 일단 사용 X + private fun getTodayAlbumDatas(): ArrayList { + val songDB = SongDatabase.getInstance(requireContext())!! + albumDatas = ArrayList(songDB.albumDao().getAlbums()) // DB에서 앨범 리스트 가져오기 + return albumDatas + } + + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/LockerFragment.kt b/week09/app/src/main/java/com/example/flo/locker/LockerFragment.kt new file mode 100644 index 0000000..b25ed1f --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/LockerFragment.kt @@ -0,0 +1,85 @@ +package com.example.flo.locker + +import android.content.Context.MODE_PRIVATE +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import com.example.flo.activities.LoginActivity +import com.example.flo.activities.MainActivity +import com.example.flo.databinding.FragmentLockerBinding +import com.google.android.material.tabs.TabLayoutMediator + +class LockerFragment : Fragment() { + lateinit var binding: FragmentLockerBinding +// private var songDatas = ArrayList< SavedSong>() + + private val information = arrayListOf("저장한 곡", "음악피일", "저장앨범") + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLockerBinding.inflate(inflater, container, false) + + //뷰페이저 어댑터 등록 + val lockerAdapter = LockerVPAdapter(this) + binding.lockerContentVp.adapter = lockerAdapter + + //탭레이아웃과 연결 + TabLayoutMediator(binding.lockerContentTb, binding.lockerContentVp) { tap, position -> + tap.text = information[position] + + }.attach() + + //로그인 액티비티로 화면전환 +// binding.login.setOnClickListener { +// startActivity(Intent(activity, LoginActivity::class.java)) +// } + return binding.root + } + + override fun onStart() { + super.onStart() + initView() + } + + //SharedPreferences에서 JWT를 가져오는 메서드 + private fun getJwt(): Int { + val spf = activity?.getSharedPreferences("auth", MODE_PRIVATE) //activity?->프래그먼트에서의 작성방법 + return spf!!.getInt("jwt", 0) + } + + //로그인으로 할지 로그아웃으로 할지 뷰를 결정, 클릭리스너도 담당 + private fun initView() { + val jwt: Int = getJwt() + if (jwt == 0) { + binding.login.text = "로그인" + binding.login.setOnClickListener { + startActivity(Intent(activity, LoginActivity::class.java)) + } + } + + else { + binding.login.text = "로그아웃" + binding.login.setOnClickListener { + //로그아웃 진행 + logout() + startActivity(Intent(activity, MainActivity::class.java)) + } + } + } + + //로그아웃 함수. SharedPreferences에서 jwt를 제거한다 + private fun logout() { + val spf = activity?.getSharedPreferences("auth", AppCompatActivity.MODE_PRIVATE) + val editor = spf!!.edit() + editor.remove("jwt") + editor.apply() + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt b/week09/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt new file mode 100644 index 0000000..4d1c8ae --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/LockerRVAdapter.kt @@ -0,0 +1,42 @@ +package com.example.flo.locker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.data.song.Song + +class LockerRVAdapter(private var songs: ArrayList) : RecyclerView.Adapter() + { + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + val binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.itemView.setOnClickListener { + + } + } + + override fun getItemCount(): Int = songs.size + + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + //binding.songListAlbumImgIv.setImageResource(song.img) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt b/week09/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt new file mode 100644 index 0000000..1351ad8 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/LockerVPAdapter.kt @@ -0,0 +1,29 @@ +package com.example.flo.locker + +import android.util.Log +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter + +class LockerVPAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + Log.d("FragmentCheck2", "createfrag") + + return when(position) { + 0 -> { + SavedsongFragment() + + } + 1 -> { + SongfileFragment() + } + else -> { + SavedalbumFragment() + } + } + + } + + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt b/week09/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt new file mode 100644 index 0000000..ba9d2a1 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/SavedAlbumRVAdapter.kt @@ -0,0 +1,68 @@ +package com.example.flo.locker + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedalbumBinding +import com.example.flo.data.album.Album + +class SavedAlbumRVAdapter(): + RecyclerView.Adapter() { + + private val albums = ArrayList() + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveAlbum(albumId: Int) + } + + private lateinit var myItemClickListener: SavedAlbumRVAdapter.MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): SavedAlbumRVAdapter.ViewHolder { + val binding = ItemSavedalbumBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: SavedAlbumRVAdapter.ViewHolder, position: Int) { + holder.bind(albums[position]) + holder.binding.albumCrudIv.setOnClickListener { + myItemClickListener.onRemoveAlbum(albums[position].id) + removeAlbum(position) + } + } + + override fun getItemCount(): Int = albums.size + + @SuppressLint("NotifyDataSetChanged") + fun addAlbums(albumList: ArrayList) { + albums.clear() // 기존 리스트 비우고 + albums.addAll(albumList) // 새 리스트 추가 + notifyDataSetChanged() // 리사이클러뷰 갱신 + } + + @SuppressLint("NotifyDataSetChanged") + fun removeAlbum(position: Int) { + albums.removeAt(position) + notifyDataSetChanged() + } + inner class ViewHolder(var binding: ItemSavedalbumBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(album: Album) { + binding.albumTitleTv.text = album.title + binding.albumSingerNameTv.text = album.singer + binding.itemAlbumCoverImgIv.setImageResource(album.coverImg!!) + //binding.albumInformationTv.text = album.information + } + + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt b/week09/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt new file mode 100644 index 0000000..f1f821c --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/SavedalbumFragment.kt @@ -0,0 +1,64 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.flo.databinding.FragmentSavedalbumBinding +import com.example.flo.data.album.Album +import com.example.flo.data.db.SongDatabase + +class SavedalbumFragment : Fragment() { + + //갱신 + lateinit var binding : FragmentSavedalbumBinding + lateinit var albumDB: SongDatabase + + override fun onCreateView( + + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedalbumBinding.inflate(inflater, container, false) + albumDB = SongDatabase.getInstance(requireContext())!! + + return binding.root + } + + override fun onStart() { + super.onStart() + initRecyclerview() + } + + private fun initRecyclerview(){ + binding.savedAlbumRv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + + val savedAlbumRVAdapter = SavedAlbumRVAdapter() + + //이거 강사가 이상하게 한 것 같은데 내가 나중에 다시 해야겠다. + savedAlbumRVAdapter.setMyItemClickListener(object : SavedAlbumRVAdapter.MyItemClickListener{ + override fun onRemoveAlbum(albumId: Int) { + albumDB.albumDao().getLikedAlbums(getJwt()) + } + }) + + binding.savedAlbumRv.adapter = savedAlbumRVAdapter + + //리사이클러뷰에 좋아요한 앨범을 불러옴 + savedAlbumRVAdapter.addAlbums(albumDB.albumDao().getLikedAlbums(getJwt()) as ArrayList) + } + + private fun getJwt() : Int { + val spf = activity?.getSharedPreferences("auth" , AppCompatActivity.MODE_PRIVATE) + val jwt = spf!!.getInt("jwt", 0) + Log.d("MAIN_ACT/GET_JWT", "jwt_token: $jwt") + + return jwt + } + +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt b/week09/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt new file mode 100644 index 0000000..fed382e --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/SavedsongFragment.kt @@ -0,0 +1,67 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSavedsongBinding +import com.example.flo.data.song.Song +import com.example.flo.data.db.SongDatabase + +class SavedsongFragment : Fragment() { + + lateinit var binding : FragmentSavedsongBinding + lateinit var songDB: SongDatabase + //private var savedSongList = ArrayList() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSavedsongBinding.inflate(inflater, container, false) + songDB = SongDatabase.getInstance(requireContext())!! + + // 곡 리스트 더미 데이터 생성 +// savedSongList.apply { +// add(SavedSong(R.drawable.img_album_exp, "Butter", "방탄소년단 (BTS)")) +// add(SavedSong(R.drawable.img_album_exp2, "아이와 나의 바다", "아이유 (IU)")) +// add(SavedSong(R.drawable.img_first_album_default, "운명 교향곡", "베토벤 (Beethoven)")) +// } + + //리사이클러뷰 어댑터 등록 +// val savedsongRVAdapter = SavedsongRVAdapter() +// binding.savedSongRv.adapter = savedsongRVAdapter + + + //등록한 리사이클러뷰 어댑터 객체에 리스너 세팅 +// savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { +// override fun onRemoveSong(position: Int) { +// savedsongRVAdapter.removeItem(position) +// } +// }) + + return binding.root + } + + override fun onStart() { + super.onStart() + initRecyclerView() + } + + private fun initRecyclerView() { + //리사이클러뷰 어댑터 등록 + val savedsongRVAdapter = SavedsongRVAdapter() + savedsongRVAdapter.setMyItemClickListener(object : SavedsongRVAdapter.MyItemClickListener { + override fun onRemoveSong(songId: Int) { + songDB.songDao().updateIsLikeById(false, songId) + } + }) + + binding.savedSongRv.adapter = savedsongRVAdapter + + savedsongRVAdapter.addSongs(songDB.songDao().getLikedSongs(true) as ArrayList) + + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt b/week09/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt new file mode 100644 index 0000000..bc73b13 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/SavedsongRVAdapter.kt @@ -0,0 +1,71 @@ +package com.example.flo.locker + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.flo.databinding.ItemSavedsongBinding +import com.example.flo.data.song.Song + +class SavedsongRVAdapter(): RecyclerView.Adapter() { + private var songs = ArrayList() + + interface MyItemClickListener { + //fun onItemClick(savedSong: SavedSong) + fun onRemoveSong(songId: Int) + } + + private lateinit var myItemClickListener: MyItemClickListener + + fun setMyItemClickListener(itemClickListener: MyItemClickListener) { + myItemClickListener = itemClickListener + } + + + override fun onCreateViewHolder( + viewGroup: ViewGroup, + viewType: Int + ): ViewHolder { + var binding: ItemSavedsongBinding = ItemSavedsongBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false + ) + + return ViewHolder(binding) + } + + override fun onBindViewHolder( + holder: ViewHolder, + position: Int + ) { + holder.bind(songs[position]) + holder.binding.songMoreIv.setOnClickListener { + myItemClickListener.onRemoveSong(songs[position].id) + removeSong(position) //리사이클러뷰에서 삭제 + } + + } + + override fun getItemCount():Int = songs.size + + @SuppressLint("NotifyDataSetChanged") + fun addSongs(songs: ArrayList) { + this.songs.clear() + this.songs.addAll(songs) + + notifyDataSetChanged() + } + + @SuppressLint("NotifyDataSetChanged") + fun removeSong(position: Int) { + songs.removeAt(position) + notifyDataSetChanged() + } + inner class ViewHolder(var binding: ItemSavedsongBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(song: Song) { + binding.songListAlbumImgIv.setImageResource(song.coverImg!!) + binding.songMusicTitleTv.text = song.title + binding.songSingerNameTv.text = song.singer + } + + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/locker/SongfileFragment.kt b/week09/app/src/main/java/com/example/flo/locker/SongfileFragment.kt new file mode 100644 index 0000000..720d1b9 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/locker/SongfileFragment.kt @@ -0,0 +1,25 @@ +package com.example.flo.locker + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSongfileBinding + +class SongfileFragment : Fragment() { + + lateinit var binding : FragmentSongfileBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSongfileBinding.inflate(inflater, container, false) + Log.d("FragmentCheck", "SongfileFragment onCreateView") + + return binding.root + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/look/LookFragment.kt b/week09/app/src/main/java/com/example/flo/look/LookFragment.kt new file mode 100644 index 0000000..d129ef6 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/look/LookFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.look + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentLookBinding + +class LookFragment : Fragment() { + lateinit var binding: FragmentLookBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLookBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/search/SearchFragment.kt b/week09/app/src/main/java/com/example/flo/search/SearchFragment.kt new file mode 100644 index 0000000..4ad6136 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/search/SearchFragment.kt @@ -0,0 +1,21 @@ +package com.example.flo.search + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.example.flo.databinding.FragmentSearchBinding + +class SearchFragment : Fragment() { + lateinit var binding: FragmentSearchBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentSearchBinding.inflate(inflater, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/services/Foreground.kt b/week09/app/src/main/java/com/example/flo/services/Foreground.kt new file mode 100644 index 0000000..06e86f6 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/services/Foreground.kt @@ -0,0 +1,48 @@ +package com.example.flo.services + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class Foreground : Service() { + + val CHANNEL_ID = "Foreground" + val NOTI_ID = 713 + fun createNotificationChannel() { + //API 26이상에서는 사전에 채널을 등록해야 함. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = + NotificationChannel(CHANNEL_ID, "FOREGROUND", NotificationManager.IMPORTANCE_HIGH) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + createNotificationChannel() + //내가 띄울 Notification을 띄운다. + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher_round) + .setContentTitle("ForegroundService") + .setContentText("Hello World!") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + + startForeground(NOTI_ID, notification) + + return super.onStartCommand(intent, flags, startId) + } + + override fun onBind(intent: Intent): IBinder { + return Binder() + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/services/MusicService.kt b/week09/app/src/main/java/com/example/flo/services/MusicService.kt new file mode 100644 index 0000000..4184776 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/services/MusicService.kt @@ -0,0 +1,128 @@ +package com.example.flo.services + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Intent +import android.media.MediaPlayer +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import com.example.flo.R + +class MusicService : Service() { + + //채널 ID와 Notificiation ID는 자유롭게! + private val CHANNEL_ID = "ForegroundMusicService" + private val NOTI_ID = 713 + + private var mediaPlayer: MediaPlayer? = null + private val binder = MusicBinder() + + //현재 재생 중인 노래 정보를 저장할 변수 + private var currentSongTitle: String = "Unknown Title" + private var currentSongArtist: String = "Unknown Artist" + + //Activity에 Service 인스턴스를 전달 + inner class MusicBinder : Binder() { + fun getService(): MusicService = this@MusicService + } + + //서비스 시작 시 초기화 + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + + //Notification 활성화 + createNotificationChannel() + + //Intent로 받은 정보들을 파싱 + val initialTitle = intent?.getStringExtra("songTitle") ?: "Unknown Title" + val initialArtist = intent?.getStringExtra("songArtist") ?: "Unknown Artist" + val isPlaying = intent?.getBooleanExtra("isPlaying", false) ?: false + + //MediaPlayer 및 변수 초기화 (임의로 노래를 연결) + if (mediaPlayer == null) { + mediaPlayer = MediaPlayer.create(this, R.raw.music_lilac) + currentSongTitle = initialTitle + currentSongArtist = initialArtist + if (isPlaying) { + mediaPlayer?.start() + } + } + + //알람도 같이 설정 + val notification = createNotification() + startForeground(NOTI_ID, notification) + + return START_STICKY + } + + override fun onBind(intent: Intent): IBinder { + return binder + } + + //알람 채널 설정(CHANNEL_ID와 name은 자유롭게 설정!) + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + CHANNEL_ID, + "Foreground Music Service Channel", + NotificationManager.IMPORTANCE_HIGH + ) + val manager = getSystemService(NotificationManager::class.java) + manager.createNotificationChannel(channel) + } + } + + //알람으로 노래가 재생중임을 표시 + private fun createNotification(): Notification { + val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle("음악 재생 중") + .setContentText("$currentSongTitle 이/가 재생 중입니다.") + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setOngoing(true) + .setOnlyAlertOnce(true) + + return notificationBuilder.build() + } + + //외부에서 서비스에 접근 가능한 함수들 + //음악 재생 + fun playMusic() { + mediaPlayer?.start() + } + //음악 멈춤 + fun pauseMusic() { + mediaPlayer?.pause() + } + //인자로 받은 위치로 곡의 재생 위치 이동 + fun seekTo(position: Int) { + mediaPlayer?.seekTo(position) + } + //현재 재생중인 노래 정보 업데이트 + fun updateCurrentSongInfo(title: String, artist: String) { + currentSongTitle = title + currentSongArtist = artist + } + //현재 재생중인 노래의 길이 리턴 + fun getDuration(): Int { + return mediaPlayer?.duration ?: 0 + } + //현재 노래의 위치 리턴(SeekBar에 넣을 거) + fun getCurrentPosition(): Int { + return mediaPlayer?.currentPosition ?: 0 + } + //재생 중임? + fun isPlaying(): Boolean { + return mediaPlayer?.isPlaying ?: false + } + + override fun onDestroy() { + mediaPlayer?.stop() + mediaPlayer?.release() + mediaPlayer = null + super.onDestroy() + } +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/ui/theme/Color.kt b/week09/app/src/main/java/com/example/flo/ui/theme/Color.kt new file mode 100644 index 0000000..6b31678 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.flo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/ui/theme/Theme.kt b/week09/app/src/main/java/com/example/flo/ui/theme/Theme.kt new file mode 100644 index 0000000..cc69550 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.flo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FLOTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/week09/app/src/main/java/com/example/flo/ui/theme/Type.kt b/week09/app/src/main/java/com/example/flo/ui/theme/Type.kt new file mode 100644 index 0000000..9a198f8 --- /dev/null +++ b/week09/app/src/main/java/com/example/flo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.flo.ui.theme + +import androidx.compose.material3.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( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/apple_44.png b/week09/app/src/main/res/drawable/apple_44.png new file mode 100644 index 0000000..f365d20 Binary files /dev/null and b/week09/app/src/main/res/drawable/apple_44.png differ diff --git a/week09/app/src/main/res/drawable/btn_actionbar_close.png b/week09/app/src/main/res/drawable/btn_actionbar_close.png new file mode 100644 index 0000000..b6cc3cc Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_actionbar_close.png differ diff --git a/week09/app/src/main/res/drawable/btn_actionbar_instagram.png b/week09/app/src/main/res/drawable/btn_actionbar_instagram.png new file mode 100644 index 0000000..90bc027 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_actionbar_instagram.png differ diff --git a/week09/app/src/main/res/drawable/btn_arrow_black.png b/week09/app/src/main/res/drawable/btn_arrow_black.png new file mode 100644 index 0000000..cc38ca8 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_arrow_black.png differ diff --git a/week09/app/src/main/res/drawable/btn_arrow_more.png b/week09/app/src/main/res/drawable/btn_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_arrow_more.png differ diff --git a/week09/app/src/main/res/drawable/btn_color_selector.xml b/week09/app/src/main/res/drawable/btn_color_selector.xml new file mode 100644 index 0000000..3ecf8a7 --- /dev/null +++ b/week09/app/src/main/res/drawable/btn_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/btn_input_password.png b/week09/app/src/main/res/drawable/btn_input_password.png new file mode 100644 index 0000000..8c2eb18 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_input_password.png differ diff --git a/week09/app/src/main/res/drawable/btn_input_password_off.png b/week09/app/src/main/res/drawable/btn_input_password_off.png new file mode 100644 index 0000000..8234f53 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_input_password_off.png differ diff --git a/week09/app/src/main/res/drawable/btn_main_arrow_more.png b/week09/app/src/main/res/drawable/btn_main_arrow_more.png new file mode 100644 index 0000000..59e410c Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_main_arrow_more.png differ diff --git a/week09/app/src/main/res/drawable/btn_main_mike.png b/week09/app/src/main/res/drawable/btn_main_mike.png new file mode 100644 index 0000000..9bddec6 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_main_mike.png differ diff --git a/week09/app/src/main/res/drawable/btn_main_setting.png b/week09/app/src/main/res/drawable/btn_main_setting.png new file mode 100644 index 0000000..7a8d5d6 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_main_setting.png differ diff --git a/week09/app/src/main/res/drawable/btn_main_ticket.png b/week09/app/src/main/res/drawable/btn_main_ticket.png new file mode 100644 index 0000000..52b6d64 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_main_ticket.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplay_mvpause.png b/week09/app/src/main/res/drawable/btn_miniplay_mvpause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplay_mvpause.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplay_mvplay.png b/week09/app/src/main/res/drawable/btn_miniplay_mvplay.png new file mode 100644 index 0000000..d118677 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplay_mvplay.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplay_pause.png b/week09/app/src/main/res/drawable/btn_miniplay_pause.png new file mode 100644 index 0000000..470e046 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplay_pause.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplayer_go_list.png b/week09/app/src/main/res/drawable/btn_miniplayer_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplayer_go_list.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplayer_next.png b/week09/app/src/main/res/drawable/btn_miniplayer_next.png new file mode 100644 index 0000000..3aedba3 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplayer_next.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplayer_play.png b/week09/app/src/main/res/drawable/btn_miniplayer_play.png new file mode 100644 index 0000000..f619072 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplayer_play.png differ diff --git a/week09/app/src/main/res/drawable/btn_miniplayer_previous.png b/week09/app/src/main/res/drawable/btn_miniplayer_previous.png new file mode 100644 index 0000000..d0bf1f6 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_miniplayer_previous.png differ diff --git a/week09/app/src/main/res/drawable/btn_panel_play_large.png b/week09/app/src/main/res/drawable/btn_panel_play_large.png new file mode 100644 index 0000000..4ac7103 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_panel_play_large.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_eq_off.png b/week09/app/src/main/res/drawable/btn_player_eq_off.png new file mode 100644 index 0000000..f23d9c6 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_eq_off.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_go_list.png b/week09/app/src/main/res/drawable/btn_player_go_list.png new file mode 100644 index 0000000..1b2d977 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_go_list.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_more.png b/week09/app/src/main/res/drawable/btn_player_more.png new file mode 100644 index 0000000..a8ad9e6 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_more.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_play.png b/week09/app/src/main/res/drawable/btn_player_play.png new file mode 100644 index 0000000..f6c3201 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_play.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_related.png b/week09/app/src/main/res/drawable/btn_player_related.png new file mode 100644 index 0000000..9026fe5 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_related.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_setting.png b/week09/app/src/main/res/drawable/btn_player_setting.png new file mode 100644 index 0000000..0df8f69 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_setting.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_unlike_off.png b/week09/app/src/main/res/drawable/btn_player_unlike_off.png new file mode 100644 index 0000000..b539504 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_unlike_off.png differ diff --git a/week09/app/src/main/res/drawable/btn_player_unlike_on.png b/week09/app/src/main/res/drawable/btn_player_unlike_on.png new file mode 100644 index 0000000..45a43ca Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_player_unlike_on.png differ diff --git a/week09/app/src/main/res/drawable/btn_playlist_select_off.png b/week09/app/src/main/res/drawable/btn_playlist_select_off.png new file mode 100644 index 0000000..62ef45c Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_playlist_select_off.png differ diff --git a/week09/app/src/main/res/drawable/btn_playlist_select_on.png b/week09/app/src/main/res/drawable/btn_playlist_select_on.png new file mode 100644 index 0000000..2d3b6af Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_playlist_select_on.png differ diff --git a/week09/app/src/main/res/drawable/btn_setting_phone.png b/week09/app/src/main/res/drawable/btn_setting_phone.png new file mode 100644 index 0000000..d6de4c6 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_setting_phone.png differ diff --git a/week09/app/src/main/res/drawable/btn_textbox_close.png b/week09/app/src/main/res/drawable/btn_textbox_close.png new file mode 100644 index 0000000..10f1f63 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_textbox_close.png differ diff --git a/week09/app/src/main/res/drawable/btn_titlebar_close.png b/week09/app/src/main/res/drawable/btn_titlebar_close.png new file mode 100644 index 0000000..6615def Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_titlebar_close.png differ diff --git a/week09/app/src/main/res/drawable/btn_toggle_off.png b/week09/app/src/main/res/drawable/btn_toggle_off.png new file mode 100644 index 0000000..983360d Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_toggle_off.png differ diff --git a/week09/app/src/main/res/drawable/btn_toggle_on.png b/week09/app/src/main/res/drawable/btn_toggle_on.png new file mode 100644 index 0000000..fb609f4 Binary files /dev/null and b/week09/app/src/main/res/drawable/btn_toggle_on.png differ diff --git a/week09/app/src/main/res/drawable/button_background_black_color.xml b/week09/app/src/main/res/drawable/button_background_black_color.xml new file mode 100644 index 0000000..a4afe1d --- /dev/null +++ b/week09/app/src/main/res/drawable/button_background_black_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/button_background_flo_color.xml b/week09/app/src/main/res/drawable/button_background_flo_color.xml new file mode 100644 index 0000000..046ded6 --- /dev/null +++ b/week09/app/src/main/res/drawable/button_background_flo_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/button_background_gray_color.xml b/week09/app/src/main/res/drawable/button_background_gray_color.xml new file mode 100644 index 0000000..3406c73 --- /dev/null +++ b/week09/app/src/main/res/drawable/button_background_gray_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/button_background_white_color.xml b/week09/app/src/main/res/drawable/button_background_white_color.xml new file mode 100644 index 0000000..679a1fd --- /dev/null +++ b/week09/app/src/main/res/drawable/button_background_white_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/discovery_banner_aos.jpg b/week09/app/src/main/res/drawable/discovery_banner_aos.jpg new file mode 100644 index 0000000..c905515 Binary files /dev/null and b/week09/app/src/main/res/drawable/discovery_banner_aos.jpg differ diff --git a/week09/app/src/main/res/drawable/fragment_look_chart_background.xml b/week09/app/src/main/res/drawable/fragment_look_chart_background.xml new file mode 100644 index 0000000..aae5110 --- /dev/null +++ b/week09/app/src/main/res/drawable/fragment_look_chart_background.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/fragment_look_chip_off_background.xml b/week09/app/src/main/res/drawable/fragment_look_chip_off_background.xml new file mode 100644 index 0000000..283cbe9 --- /dev/null +++ b/week09/app/src/main/res/drawable/fragment_look_chip_off_background.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/fragment_look_chip_on_background.xml b/week09/app/src/main/res/drawable/fragment_look_chip_on_background.xml new file mode 100644 index 0000000..e77b352 --- /dev/null +++ b/week09/app/src/main/res/drawable/fragment_look_chip_on_background.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/ic_all_album_play.xml b/week09/app/src/main/res/drawable/ic_all_album_play.xml new file mode 100644 index 0000000..21f11cb --- /dev/null +++ b/week09/app/src/main/res/drawable/ic_all_album_play.xml @@ -0,0 +1,9 @@ + + + diff --git a/week09/app/src/main/res/drawable/ic_bottom_home_no_select.png b/week09/app/src/main/res/drawable/ic_bottom_home_no_select.png new file mode 100644 index 0000000..69a8ab6 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_bottom_home_no_select.png differ diff --git a/week09/app/src/main/res/drawable/ic_bottom_locker_no_select.png b/week09/app/src/main/res/drawable/ic_bottom_locker_no_select.png new file mode 100644 index 0000000..a67dec3 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_bottom_locker_no_select.png differ diff --git a/week09/app/src/main/res/drawable/ic_bottom_look_no_select.png b/week09/app/src/main/res/drawable/ic_bottom_look_no_select.png new file mode 100644 index 0000000..6c2f4f0 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_bottom_look_no_select.png differ diff --git a/week09/app/src/main/res/drawable/ic_bottom_search_no_select.png b/week09/app/src/main/res/drawable/ic_bottom_search_no_select.png new file mode 100644 index 0000000..a77b8c5 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_bottom_search_no_select.png differ diff --git a/week09/app/src/main/res/drawable/ic_browse_arrow_right.png b/week09/app/src/main/res/drawable/ic_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_browse_arrow_right.png differ diff --git a/week09/app/src/main/res/drawable/ic_check.xml b/week09/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..bec5bec --- /dev/null +++ b/week09/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,12 @@ + + + diff --git a/week09/app/src/main/res/drawable/ic_flo_logo.png b/week09/app/src/main/res/drawable/ic_flo_logo.png new file mode 100644 index 0000000..643224d Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_flo_logo.png differ diff --git a/week09/app/src/main/res/drawable/ic_launcher_background.xml b/week09/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/week09/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week09/app/src/main/res/drawable/ic_launcher_foreground.xml b/week09/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/week09/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/ic_main_facebook.png b/week09/app/src/main/res/drawable/ic_main_facebook.png new file mode 100644 index 0000000..83e9732 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_main_facebook.png differ diff --git a/week09/app/src/main/res/drawable/ic_main_instagram.png b/week09/app/src/main/res/drawable/ic_main_instagram.png new file mode 100644 index 0000000..398ce61 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_main_instagram.png differ diff --git a/week09/app/src/main/res/drawable/ic_main_twitter.png b/week09/app/src/main/res/drawable/ic_main_twitter.png new file mode 100644 index 0000000..6ddc68e Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_main_twitter.png differ diff --git a/week09/app/src/main/res/drawable/ic_main_youtube.png b/week09/app/src/main/res/drawable/ic_main_youtube.png new file mode 100644 index 0000000..0c4ec93 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_main_youtube.png differ diff --git a/week09/app/src/main/res/drawable/ic_my_like_off.png b/week09/app/src/main/res/drawable/ic_my_like_off.png new file mode 100644 index 0000000..c06e139 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_my_like_off.png differ diff --git a/week09/app/src/main/res/drawable/ic_my_like_on.png b/week09/app/src/main/res/drawable/ic_my_like_on.png new file mode 100644 index 0000000..22577c0 Binary files /dev/null and b/week09/app/src/main/res/drawable/ic_my_like_on.png differ diff --git a/week09/app/src/main/res/drawable/ico_20_logo_tid_white.png b/week09/app/src/main/res/drawable/ico_20_logo_tid_white.png new file mode 100644 index 0000000..c6f4d4f Binary files /dev/null and b/week09/app/src/main/res/drawable/ico_20_logo_tid_white.png differ diff --git a/week09/app/src/main/res/drawable/icon_browse_arrow_right.png b/week09/app/src/main/res/drawable/icon_browse_arrow_right.png new file mode 100644 index 0000000..71b588b Binary files /dev/null and b/week09/app/src/main/res/drawable/icon_browse_arrow_right.png differ diff --git a/week09/app/src/main/res/drawable/img_album_exp.png b/week09/app/src/main/res/drawable/img_album_exp.png new file mode 100644 index 0000000..6e3f38a Binary files /dev/null and b/week09/app/src/main/res/drawable/img_album_exp.png differ diff --git a/week09/app/src/main/res/drawable/img_album_exp2.png b/week09/app/src/main/res/drawable/img_album_exp2.png new file mode 100644 index 0000000..28ea3ee Binary files /dev/null and b/week09/app/src/main/res/drawable/img_album_exp2.png differ diff --git a/week09/app/src/main/res/drawable/img_album_lp.png b/week09/app/src/main/res/drawable/img_album_lp.png new file mode 100644 index 0000000..29fb1b4 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_album_lp.png differ diff --git a/week09/app/src/main/res/drawable/img_first_album_default.png b/week09/app/src/main/res/drawable/img_first_album_default.png new file mode 100644 index 0000000..926d34f Binary files /dev/null and b/week09/app/src/main/res/drawable/img_first_album_default.png differ diff --git a/week09/app/src/main/res/drawable/img_great_album_exp.jpg b/week09/app/src/main/res/drawable/img_great_album_exp.jpg new file mode 100644 index 0000000..33efe01 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_great_album_exp.jpg differ diff --git a/week09/app/src/main/res/drawable/img_home_viewpager_exp.png b/week09/app/src/main/res/drawable/img_home_viewpager_exp.png new file mode 100644 index 0000000..da78032 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_home_viewpager_exp.png differ diff --git a/week09/app/src/main/res/drawable/img_home_viewpager_exp2.png b/week09/app/src/main/res/drawable/img_home_viewpager_exp2.png new file mode 100644 index 0000000..50fa4be Binary files /dev/null and b/week09/app/src/main/res/drawable/img_home_viewpager_exp2.png differ diff --git a/week09/app/src/main/res/drawable/img_iris_album_exp.jpg b/week09/app/src/main/res/drawable/img_iris_album_exp.jpg new file mode 100644 index 0000000..040d531 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_iris_album_exp.jpg differ diff --git a/week09/app/src/main/res/drawable/img_jenre_exp_1.png b/week09/app/src/main/res/drawable/img_jenre_exp_1.png new file mode 100644 index 0000000..0d43e8e Binary files /dev/null and b/week09/app/src/main/res/drawable/img_jenre_exp_1.png differ diff --git a/week09/app/src/main/res/drawable/img_jenre_exp_2.png b/week09/app/src/main/res/drawable/img_jenre_exp_2.png new file mode 100644 index 0000000..f03efb2 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_jenre_exp_2.png differ diff --git a/week09/app/src/main/res/drawable/img_jenre_exp_3.png b/week09/app/src/main/res/drawable/img_jenre_exp_3.png new file mode 100644 index 0000000..51de684 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_jenre_exp_3.png differ diff --git a/week09/app/src/main/res/drawable/img_oort_album_exp.jpg b/week09/app/src/main/res/drawable/img_oort_album_exp.jpg new file mode 100644 index 0000000..d9b06ab Binary files /dev/null and b/week09/app/src/main/res/drawable/img_oort_album_exp.jpg differ diff --git a/week09/app/src/main/res/drawable/img_potcast_exp.png b/week09/app/src/main/res/drawable/img_potcast_exp.png new file mode 100644 index 0000000..50a46e0 Binary files /dev/null and b/week09/app/src/main/res/drawable/img_potcast_exp.png differ diff --git a/week09/app/src/main/res/drawable/img_video_exp.png b/week09/app/src/main/res/drawable/img_video_exp.png new file mode 100644 index 0000000..7f6b05f Binary files /dev/null and b/week09/app/src/main/res/drawable/img_video_exp.png differ diff --git a/week09/app/src/main/res/drawable/kakako_44.png b/week09/app/src/main/res/drawable/kakako_44.png new file mode 100644 index 0000000..243298e Binary files /dev/null and b/week09/app/src/main/res/drawable/kakako_44.png differ diff --git a/week09/app/src/main/res/drawable/naver_44.png b/week09/app/src/main/res/drawable/naver_44.png new file mode 100644 index 0000000..d984487 Binary files /dev/null and b/week09/app/src/main/res/drawable/naver_44.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_down.png b/week09/app/src/main/res/drawable/nugu_btn_down.png new file mode 100644 index 0000000..03a04c5 Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_down.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_pause_32.png b/week09/app/src/main/res/drawable/nugu_btn_pause_32.png new file mode 100644 index 0000000..9388aa3 Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_pause_32.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_play_32.png b/week09/app/src/main/res/drawable/nugu_btn_play_32.png new file mode 100644 index 0000000..b781e4c Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_play_32.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_random_inactive.png b/week09/app/src/main/res/drawable/nugu_btn_random_inactive.png new file mode 100644 index 0000000..fe4f880 Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_random_inactive.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_repeat_inactive.png b/week09/app/src/main/res/drawable/nugu_btn_repeat_inactive.png new file mode 100644 index 0000000..1e4044d Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_repeat_inactive.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_skip_next_32.png b/week09/app/src/main/res/drawable/nugu_btn_skip_next_32.png new file mode 100644 index 0000000..fc02f28 Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_skip_next_32.png differ diff --git a/week09/app/src/main/res/drawable/nugu_btn_skip_previous_32.png b/week09/app/src/main/res/drawable/nugu_btn_skip_previous_32.png new file mode 100644 index 0000000..03ec854 Binary files /dev/null and b/week09/app/src/main/res/drawable/nugu_btn_skip_previous_32.png differ diff --git a/week09/app/src/main/res/drawable/splash.xml b/week09/app/src/main/res/drawable/splash.xml new file mode 100644 index 0000000..da83aa4 --- /dev/null +++ b/week09/app/src/main/res/drawable/splash.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/textview_background_radius.xml b/week09/app/src/main/res/drawable/textview_background_radius.xml new file mode 100644 index 0000000..d250c1e --- /dev/null +++ b/week09/app/src/main/res/drawable/textview_background_radius.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/textview_background_select_color_radius.xml b/week09/app/src/main/res/drawable/textview_background_select_color_radius.xml new file mode 100644 index 0000000..8aaca4c --- /dev/null +++ b/week09/app/src/main/res/drawable/textview_background_select_color_radius.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/drawable/widget_black_play.png b/week09/app/src/main/res/drawable/widget_black_play.png new file mode 100644 index 0000000..0ec2700 Binary files /dev/null and b/week09/app/src/main/res/drawable/widget_black_play.png differ diff --git a/week09/app/src/main/res/layout/activity/activity_test.xml b/week09/app/src/main/res/layout/activity/activity_test.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/week09/app/src/main/res/layout/activity/activity_test.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/activity_login.xml b/week09/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..7a3b16f --- /dev/null +++ b/week09/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/activity_main.xml b/week09/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..3f45054 --- /dev/null +++ b/week09/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/activity_signup.xml b/week09/app/src/main/res/layout/activity_signup.xml new file mode 100644 index 0000000..7a0c00b --- /dev/null +++ b/week09/app/src/main/res/layout/activity_signup.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/activity_song.xml b/week09/app/src/main/res/layout/activity_song.xml new file mode 100644 index 0000000..73a6cc4 --- /dev/null +++ b/week09/app/src/main/res/layout/activity_song.xml @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/activity_splash.xml b/week09/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 0000000..29ce312 --- /dev/null +++ b/week09/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_album.xml b/week09/app/src/main/res/layout/fragment_album.xml new file mode 100644 index 0000000..79aaf13 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_album.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_banner.xml b/week09/app/src/main/res/layout/fragment_banner.xml new file mode 100644 index 0000000..b7ef866 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_banner.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_detail.xml b/week09/app/src/main/res/layout/fragment_detail.xml new file mode 100644 index 0000000..151ebe6 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_detail.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_home.xml b/week09/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..90215e6 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_locker.xml b/week09/app/src/main/res/layout/fragment_locker.xml new file mode 100644 index 0000000..c37d43c --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_locker.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week09/app/src/main/res/layout/fragment_look.xml b/week09/app/src/main/res/layout/fragment_look.xml new file mode 100644 index 0000000..31b020c --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_look.xml @@ -0,0 +1,516 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_savedalbum.xml b/week09/app/src/main/res/layout/fragment_savedalbum.xml new file mode 100644 index 0000000..c395bf2 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_savedalbum.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/week09/app/src/main/res/layout/fragment_savedsong.xml b/week09/app/src/main/res/layout/fragment_savedsong.xml new file mode 100644 index 0000000..41fb837 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_savedsong.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_search.xml b/week09/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..301f760 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_song.xml b/week09/app/src/main/res/layout/fragment_song.xml new file mode 100644 index 0000000..439b6f3 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_song.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_songfile.xml b/week09/app/src/main/res/layout/fragment_songfile.xml new file mode 100644 index 0000000..05dca29 --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_songfile.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/fragment_video.xml b/week09/app/src/main/res/layout/fragment_video.xml new file mode 100644 index 0000000..70e650d --- /dev/null +++ b/week09/app/src/main/res/layout/fragment_video.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/item_album.xml b/week09/app/src/main/res/layout/item_album.xml new file mode 100644 index 0000000..99ae14e --- /dev/null +++ b/week09/app/src/main/res/layout/item_album.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/item_savedalbum.xml b/week09/app/src/main/res/layout/item_savedalbum.xml new file mode 100644 index 0000000..cabe757 --- /dev/null +++ b/week09/app/src/main/res/layout/item_savedalbum.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/item_savedsong.xml b/week09/app/src/main/res/layout/item_savedsong.xml new file mode 100644 index 0000000..fc292d7 --- /dev/null +++ b/week09/app/src/main/res/layout/item_savedsong.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/layout/item_song.xml b/week09/app/src/main/res/layout/item_song.xml new file mode 100644 index 0000000..bf9e8a2 --- /dev/null +++ b/week09/app/src/main/res/layout/item_song.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/menu/bottom_nav_menu.xml b/week09/app/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 0000000..2b56b8c --- /dev/null +++ b/week09/app/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week09/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week09/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week09/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/week09/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week09/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/week09/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/week09/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week09/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/week09/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/week09/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week09/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/week09/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/week09/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week09/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/week09/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/week09/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week09/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/week09/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/week09/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week09/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/week09/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/week09/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week09/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/week09/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/week09/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week09/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/week09/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/week09/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week09/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/week09/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/week09/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week09/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/week09/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/week09/app/src/main/res/raw/music_bboom.mp3 b/week09/app/src/main/res/raw/music_bboom.mp3 new file mode 100644 index 0000000..9b1e5db Binary files /dev/null and b/week09/app/src/main/res/raw/music_bboom.mp3 differ diff --git a/week09/app/src/main/res/raw/music_butter.mp3 b/week09/app/src/main/res/raw/music_butter.mp3 new file mode 100644 index 0000000..94ffc91 Binary files /dev/null and b/week09/app/src/main/res/raw/music_butter.mp3 differ diff --git a/week09/app/src/main/res/raw/music_irisout.mp3 b/week09/app/src/main/res/raw/music_irisout.mp3 new file mode 100644 index 0000000..7e40d8d Binary files /dev/null and b/week09/app/src/main/res/raw/music_irisout.mp3 differ diff --git a/week09/app/src/main/res/raw/music_lilac.mp3 b/week09/app/src/main/res/raw/music_lilac.mp3 new file mode 100644 index 0000000..7c85690 Binary files /dev/null and b/week09/app/src/main/res/raw/music_lilac.mp3 differ diff --git a/week09/app/src/main/res/raw/music_oortcloud.mp3 b/week09/app/src/main/res/raw/music_oortcloud.mp3 new file mode 100644 index 0000000..7e7cbf8 Binary files /dev/null and b/week09/app/src/main/res/raw/music_oortcloud.mp3 differ diff --git a/week09/app/src/main/res/values/colors.xml b/week09/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..71cd486 --- /dev/null +++ b/week09/app/src/main/res/values/colors.xml @@ -0,0 +1,24 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + #FFD3D3D3 + #FF0000FF + #3f3fff + + #9cbee2 + #062342 + #424242 + #6bb2ff + + #00ff0000 + #3f3fff + #a8a8a8 + #3f3fff + #a8a8a8 + \ No newline at end of file diff --git a/week09/app/src/main/res/values/strings.xml b/week09/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..63f5ff1 --- /dev/null +++ b/week09/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + FLO + + Hello blank fragment + \ No newline at end of file diff --git a/week09/app/src/main/res/values/themes.xml b/week09/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..e76a4bf --- /dev/null +++ b/week09/app/src/main/res/values/themes.xml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/xml/backup_rules.xml b/week09/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..4df9255 --- /dev/null +++ b/week09/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/week09/app/src/main/res/xml/data_extraction_rules.xml b/week09/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/week09/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/week09/app/src/test/java/com/example/flo/ExampleUnitTest.kt b/week09/app/src/test/java/com/example/flo/ExampleUnitTest.kt new file mode 100644 index 0000000..d39df20 --- /dev/null +++ b/week09/app/src/test/java/com/example/flo/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.flo + +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/week09/build.gradle.kts b/week09/build.gradle.kts new file mode 100644 index 0000000..952b930 --- /dev/null +++ b/week09/build.gradle.kts @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false +} \ No newline at end of file diff --git a/week09/gradle.properties b/week09/gradle.properties new file mode 100644 index 0000000..20e2a01 --- /dev/null +++ b/week09/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. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-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/week09/gradle/libs.versions.toml b/week09/gradle/libs.versions.toml new file mode 100644 index 0000000..339d205 --- /dev/null +++ b/week09/gradle/libs.versions.toml @@ -0,0 +1,36 @@ +[versions] +agp = "8.13.0" +kotlin = "2.0.21" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2024.09.00" +constraintlayout = "2.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version = "2.2.21" } + + diff --git a/week09/gradle/wrapper/gradle-wrapper.jar b/week09/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/week09/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week09/gradle/wrapper/gradle-wrapper.properties b/week09/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..af10ccc --- /dev/null +++ b/week09/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Sep 28 16:12:35 KST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week09/gradlew b/week09/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/week09/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/week09/gradlew.bat b/week09/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/week09/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/week09/settings.gradle.kts b/week09/settings.gradle.kts new file mode 100644 index 0000000..2a48c99 --- /dev/null +++ b/week09/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "FLO" +include(":app") + \ No newline at end of file