Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
a82139b
Delete naru/W01 directory
yangjiae12 Oct 6, 2024
2f17233
Feat : 2주차 미션
yangjiae12 Oct 6, 2024
46b09ba
Feat: 2주차 미션
yangjiae12 Oct 6, 2024
37690be
feat: 2주차 미션
yangjiae12 Oct 6, 2024
09bd2dd
feat: 바텀 네비게이션 및 프래그먼트 전환 개선
yangjiae12 Oct 11, 2024
83e3aae
feat : 3주차 미션 레이아웃 설정, 액티비티 및 프래그먼트 이동
yangjiae12 Oct 12, 2024
13e54b5
feat: 3주차 미션 SongActivity 데이터 전달 및 토스트 메시지 표시
yangjiae12 Oct 12, 2024
39b5ec0
feat: 3주차 미션 HomeFragment의 Banner 부분 ViewPager 구현
yangjiae12 Oct 12, 2024
8da4619
feat: 3주차 미션 AlbumFragment의 TabLayout 및 Viewpager 구현
yangjiae12 Oct 13, 2024
3292836
feat: 3주차 미션 AlbumFragment에서 가수 및 앨범 전달 기능 구현
yangjiae12 Oct 13, 2024
ada2f4e
feat: 3주차 미션 HomeFragment 레이아웃 추가 구현
yangjiae12 Oct 14, 2024
ce10849
Feat: 3주차 mix 버튼 클릭 시 이미지 변경
yangjiae12 Oct 26, 2024
31c95f0
Feat: 3주차 반복재생, 전체재생 이미지 교체
yangjiae12 Oct 26, 2024
355fbe5
Feat: 3주차 Detail Fragment 화면 구현
yangjiae12 Oct 26, 2024
dfdd95c
Feat: 3주차 Video Fragment 레이아웃 구현
yangjiae12 Oct 26, 2024
649c595
Feat: LockerFragment의 TabLayout과 ViewPager 구현
yangjiae12 Oct 26, 2024
ba2e32d
Chore: 3주차 LockerFragment, SavedSongFragment, MusicFileFragment 레이아웃 수정
yangjiae12 Oct 26, 2024
3bc14a2
Feat: 3주차 VideoFragment에 스크롤뷰 적용
yangjiae12 Oct 26, 2024
a0e6bd1
Feat: 3주차 HomeFragment 화면 panel 부분 ViewPager로 구현
yangjiae12 Oct 27, 2024
1ea2dc6
Chore: 3주차 panel 관련 프래그먼트, 클래스, 아이디 이름 변경
yangjiae12 Oct 27, 2024
e131771
Feat: 3주차 Indicator 추가 및 자동 슬라이드 구현
yangjiae12 Oct 27, 2024
3500132
Chore: 3주차 미션 주석 추가
yangjiae12 Oct 27, 2024
79513a0
Refactor: 자동 슬라이드 생명주기 관리를 위한 수정
yangjiae12 Oct 28, 2024
1290040
Feat: 4주차 SongActivity Timer Seekbar 구현
yangjiae12 Nov 3, 2024
828039b
Feat: 3주차 스플래시 화면 구현
yangjiae12 Nov 3, 2024
af74a99
Feat: 4주차 타이머 구현
yangjiae12 Nov 3, 2024
089a6cb
Chore: 4주차 실전미션 주석 추가
yangjiae12 Nov 3, 2024
11e5e8e
Feat: 5주차 한곡재생 버튼 클릭 시 스레드 재시작 구현
yangjiae12 Nov 9, 2024
3edbb9a
Feat: 5주차 mediaPlayer 구현
yangjiae12 Nov 10, 2024
e2de8e7
Feat: 5주차 onPause, onDestroy 구현
yangjiae12 Nov 10, 2024
4a9f4ea
Feat: 5주차 SongActivity에서 Song 데이터 저장하기
yangjiae12 Nov 10, 2024
f18a524
Feat: 5주차 MainActivity에서 Song 데이터 가져오기
yangjiae12 Nov 10, 2024
9b12799
Fix: 5주차 한곡재생 클릭리스너 수정
yangjiae12 Nov 10, 2024
7a25c9d
Fix: 타이머 종료 시 미디어 플레이어 리소스 해제
yangjiae12 Nov 10, 2024
6432c1b
Feat: 5주차 실전 미션 초기화
yangjiae12 Nov 10, 2024
8ec9832
Feat: 5주차 실전 미션 레이아웃 구현 및 SDK 버전 업데이트
yangjiae12 Nov 10, 2024
1cb2415
Feat: 5주차 실전 미션 MainActivity 기능 구현
yangjiae12 Nov 10, 2024
f852bc1
Feat: 5주차 실전미션 ViewActivity 기능 구현
yangjiae12 Nov 10, 2024
554987c
Feat: 5주차 실전미션 EditText 기본 텍스트를 Hint로 변경
yangjiae12 Nov 10, 2024
c2dae11
Feat: 5주차 실전미션 텍스트 사이즈 sp로 수정
yangjiae12 Nov 10, 2024
61125a5
Fix: 5주차 실전미션 메모 내용 비우기 및 기존 Hint 유지
yangjiae12 Nov 10, 2024
d5f9b1b
Fix: 5주차 한곡 재생 모드에서 스레드 재시작 시 노래 처음부터 재생
yangjiae12 Nov 12, 2024
ad2be96
Fix: 가수 이름 오타 수정
yangjiae12 Nov 12, 2024
28a49b0
Feat: 6주차HomeFragment 앨범 RecyclerView 구현
yangjiae12 Nov 15, 2024
0b74a94
Feat: 6주차 HomeFragment RecyclerView 클릭이벤트 적용
yangjiae12 Nov 15, 2024
bfdfd0c
Feat: 6주차 AlbumFragment로 데이터 전달 구현
yangjiae12 Nov 15, 2024
c7d712d
Feat: 6주차 HomeFragment RecyclerView CRUD
yangjiae12 Nov 15, 2024
b91f6b4
Feat: 6주차 SavedSongFragment RecyclerView 구현
yangjiae12 Nov 16, 2024
501e7b1
Feat: 6주차 SavedSongFragment RecyclerView 클릭이벤트 적용
yangjiae12 Nov 16, 2024
9b7571d
Feat: 6주차 HomeFragment Play 버튼 클릭 시 MiniPlayer에 동기화
yangjiae12 Nov 16, 2024
76b3d4c
Feat: 6주차 스위치 ON/OFF 문제 해결
yangjiae12 Nov 16, 2024
1112fbe
Feat: 6주차 ForegroundService 사용하여 알림창 구현
yangjiae12 Nov 17, 2024
63679a4
Feat: 6주차 실전미션 Bottom Navigation 구현
yangjiae12 Nov 17, 2024
0d479eb
Feat: 6주차 실전미션 HomeFragment TabLayout 구현
yangjiae12 Nov 17, 2024
fe3ce34
Feat: 6주차 실전미션 RankingFragment RecyclerView 구현
yangjiae12 Nov 17, 2024
ba2d5f9
Feat: 6주차 실전미션 ProductFragment 및 RecyclerView 클릭이벤트 적용
yangjiae12 Nov 17, 2024
abc2d52
Docs: 플로 클론 코딩 주석 추가
yangjiae12 Nov 18, 2024
57d8bae
Feat: 6주차 수록곡 추가 및 첫번째 곡 재생 기능 구현
yangjiae12 Nov 18, 2024
e5c4b40
Feat: 6주차 Foreground Service로 알림창 구현
yangjiae12 Nov 19, 2024
e33a2b5
Feat: 7주차 간단실습
yangjiae12 Nov 20, 2024
e110c54
Fix: SplashActivity 전환 후 종료
yangjiae12 Nov 23, 2024
5047b1c
Fix: 미니 플레이어 클릭 시 SongActivity로 데이터 전달 부분 수정
yangjiae12 Nov 23, 2024
5ecdea5
Chore: 더미데이터 수정 및 음악 파일 추가
yangjiae12 Nov 23, 2024
af7ea5f
Chore: 7주차 미션 RoomDB 의존성 추가
yangjiae12 Nov 23, 2024
54974d0
Feat: 7주차 미션 RoomDB 데이터베이스 클래스 및 초기 설정 추가
yangjiae12 Nov 23, 2024
59854d3
Feat: 7주차 미션 Song 데이터베이스 구축
yangjiae12 Nov 23, 2024
8605180
Feat: 7주차 미션 Song Database 활용하여 노래 넘기기 구현
yangjiae12 Nov 23, 2024
65132a3
Chore: 7주차 미션 불필요한 주석 제거
yangjiae12 Nov 23, 2024
d931e3a
Fix: songId 저장 및 불러오기 수정
yangjiae12 Nov 23, 2024
5984299
Feat: 7주차 미션 좋아요 기능 구현
yangjiae12 Nov 23, 2024
213587e
Feat: 7주차 미션 SavedSongFragment에 좋아요한 노래 표시
yangjiae12 Nov 23, 2024
121fce8
Feat: 7주차 미션 MiniPlayer의 SeekBar 재생시간 표시
yangjiae12 Nov 24, 2024
2cd4bef
Fix: onPause() 시 Foreground Service 중단되도록 수정
yangjiae12 Nov 24, 2024
8c10682
Feat: MiniPlayer에서 노래 넘기기 구현
yangjiae12 Nov 24, 2024
733c201
Chore: Foreground Service를 통한 알림창 기능 임시 비활성화
yangjiae12 Nov 24, 2024
d82127a
Fix: 7주차 미션 onStart에서 ID에 맞는 노래 위치 확인 및 미니 플레이어 업데이트
yangjiae12 Nov 24, 2024
60fca05
Feat: 7주차 미션 AlbumDB 구현 및 적용
yangjiae12 Nov 24, 2024
1922bde
Feat: 7주차 미션 좋아요 Toast message 커스텀
yangjiae12 Nov 24, 2024
bbb1e89
Feat: 7주차 미션 BottomSheetDialog 구현
yangjiae12 Nov 25, 2024
e5f0f6b
Feat: 7주차 미션 앨범 재생 클릭 시 앨범 수록곡 전체 재생 구현
yangjiae12 Nov 29, 2024
e6d68a4
Feat: 7주차 미션 MiniPlayer에서 음악 재생
yangjiae12 Nov 29, 2024
4ff0f1f
Feat: 7주차 미션 보관함 전체 선택 후 좋아요 취소 기능 구현
yangjiae12 Nov 29, 2024
05cefc4
Feat: 8주차 LoginActivity, SignActivity 추가
yangjiae12 Dec 2, 2024
47734eb
Feat: 8주차 액티비티 간 이동 및 UserTable 생성
yangjiae12 Dec 2, 2024
cbb2f31
Feat: 8주차 회원가입 기능 구현
yangjiae12 Dec 2, 2024
3485803
Feat: 8주차 로그인 및 로그아웃 기능 구현
yangjiae12 Dec 2, 2024
24b2d9b
Feat: 8주차 앨범 좋아요 실습 RoomDB 사용 준비
yangjiae12 Dec 2, 2024
0e5e1b9
Feat: 8주차 앨범 좋아요 및 좋아요 취소 기능
yangjiae12 Dec 2, 2024
b2d88fe
Feat: 8주차 좋아요 한 앨범 목록 표시하는 기능 구현
yangjiae12 Dec 2, 2024
f8850aa
Fix: 8주차 로그인 성공 시에는 실패 메시지 뜨지 않도록 수정
yangjiae12 Dec 2, 2024
e661e72
Chore: 9주차 초기 설정
yangjiae12 Dec 25, 2024
3040067
Feat: 9주차 API 활용하여 회원가입 구현
yangjiae12 Dec 25, 2024
1b00df5
Refactor: 9주차 API 모듈화
yangjiae12 Dec 25, 2024
7befbde
Fix: 9주차 AuthResponse의 code를 Int에서 String으로 변경
yangjiae12 Dec 25, 2024
cf004d9
Fix: 9주차 API 활용하여 로그인 구현
yangjiae12 Dec 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 18 additions & 0 deletions naru/AndroidFloClone/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions naru/AndroidFloClone/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
70 changes: 70 additions & 0 deletions naru/AndroidFloClone/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("kotlin-kapt")
}

android {
namespace = "com.example.androidfloclone"
compileSdk = 34

defaultConfig {
applicationId = "com.example.androidfloclone"
minSdk = 24
targetSdk = 34
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_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}

buildFeatures {
viewBinding = true
dataBinding = true
}
}

dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.circleindicator)
implementation(libs.gson)
implementation(libs.room.runtime)
implementation(libs.room.ktx)
kapt(libs.room.compiler)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")

// OkHTTP
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")

// Glide
implementation("com.github.bumptech.glide:glide:4.15.1")
kapt("com.github.bumptech.glide:compiler:4.15.1")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.example.androidfloclone

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.androidfloclone", appContext.packageName)
}
}
55 changes: 55 additions & 0 deletions naru/AndroidFloClone/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidFloClone"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".SignUpActivity"
android:exported="false" />
<activity
android:name=".LoginActivity"
android:exported="false" />

<service
android:name=".MusicService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="mediaPlayback"
tools:ignore="ForegroundServicePermission" />

<activity
android:name=".MainActivity"
android:exported="false" />
<activity
android:name=".SongActivity"
android:exported="false" />
<activity
android:name=".SplashActivity"
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.androidfloclone

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 coverImg: Int? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example.androidfloclone

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update

@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<Album>

@Query("SELECT * FROM AlbumTable WHERE id = :id")
fun getAlbum(id: Int): Album

@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)

@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<Album>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.example.androidfloclone

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.example.androidfloclone.databinding.FragmentAlbumBinding
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)

val albumJson = arguments?.getString("album")
val album = gson.fromJson(albumJson, Album::class.java)
isLiked = isLikedAlbum(album.id)
setInit(album)
setOnClickListeners(album)

binding.albumBackIv.setOnClickListener {
(context as MainActivity).supportFragmentManager.beginTransaction()
.replace(R.id.main_frm,HomeFragment())
.commitAllowingStateLoss()
}

// 앨범 어댑터 초기화
val albumAdapter = AlbumVPAdapter(this)
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.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)
}
}

private fun getJwt(): Int {
val spf = activity?.getSharedPreferences("auth", AppCompatActivity.MODE_PRIVATE)
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
}

private fun disLikedAlbum(albumId: Int) {
val songDB = SongDatabase.getInstance(requireContext())!!
val userId = getJwt()

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(album.id)
}
else {
binding.albumLikeIv.setImageResource(R.drawable.ic_my_like_on)
likeAlbum(userId, album.id)
}
}
}
}
Loading