From 7b2c4680ed9011547de896aec1dab50e4c97bcd5 Mon Sep 17 00:00:00 2001 From: sungahbak Date: Tue, 4 Nov 2025 22:47:06 +0900 Subject: [PATCH 1/3] =?UTF-8?q?keyword=20:=206=EC=A3=BC=EC=B0=A8=20?= =?UTF-8?q?=ED=82=A4=EC=9B=8C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- keyword/chapter06/keyword | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 keyword/chapter06/keyword diff --git a/keyword/chapter06/keyword b/keyword/chapter06/keyword new file mode 100644 index 0000000..24a92a0 --- /dev/null +++ b/keyword/chapter06/keyword @@ -0,0 +1,71 @@ +- Lifecycle + - Lifecycle이란 무엇일까요? + + 컴포넌트가 생성되고 사라지기 전까지 갖게되는 상태의 집합 + + | 상태 | 의미 | + | --- | --- | + | onCreate() | 액티비티가 시작될때 / setContentView,savedInstanceState | + | onStart() | ui관리하는 코드를 초기화, 브로드캐스트리시버와 비슷한 기능 | + | onResume() | 액티비티가 Resumed 상태가 되면 액티비티는 포그라운드로 이동하고 안드로이드 시스템은 onResume을 호출 | + | onPause() | 액티비티가 포커스를 잃거나 종료될때, 시간이 오래걸리는 작업 | + | onStop() | 액티비티가 완전히 가려지는 경우에 onPause() 호출 다음에 onStop()이 호출되고 Stopped 상태를 유지 | + | onDestory() | 액티비티가 소멸되기 전에 호출 | + + ![image.png](attachment:10a895b0-b53f-4d10-a54a-970d0f91fb63:image.png) + + - Lifecycle은 왜 등장하게 되었을까요? + 1. 소프트웨어 규모의 대규모화 및 복잡성 증가 + 2. 체계적인 개발 절차의 부재 문제 + 3. 일관된 관리 및 의사소통 수단 제공 + + https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ko + +- Activity의 Lifecycle + - Activity의 대표적인 Lifecycle은 어떤게 있을까요? + + + | 상태 | 의미 | + | --- | --- | + | onCreate() | 액티비티가 시작될때 / setContentView,savedInstanceState/ 최초생성될때 | + | onStart() | ui관리하는 코드를 초기화, 브로드캐스트리시버와 비슷한 기능/사용자에게 보여지기 시작 | + | onResume() | 액티비티가 Resumed 상태가 되면 액티비티는 포그라운드로 이동하고 안드로이드 시스템은 onResume을 호출 / 사용자와 실제 상호작용가능 | + | onPause() | 액티비티가 포커스를 잃거나 종료될때, 시간이 오래걸리는 작업 / 다른 액티비티가 포커스를 가질 때 | + | onStop() | 액티비티가 완전히 가려지는 경우에 onPause() 호출 다음에 onStop()이 호출되고 Stopped 상태를 유지 / 화면에서 완전히 안 보일 때 | + | onDestory() | 액티비티가 소멸되기 전에 호출 / 메모리에서 완전히 제거될 때 | + - 각 Lifecycle을 활용하는 실제 예시들은 어떤게 있을까요? + + + | **콜백 메서드** | **발생 상황 및 상태 변화** | **실제 사용 예시** | + | --- | --- | --- | + | **`onCreate()`** | 액티비티가 **최초 생성**될 때 호출됨. (`setContentView`, `savedInstanceState` 처리) | 🌟 앱의 **초기 설정**: UI 레이아웃 설정 (`setContentView`), 뷰 초기화, 데이터 바인딩, ViewModel 연결, 클래스 범위 변수 인스턴스화 등. 이전 상태(`savedInstanceState`) 복원. | + | **`onStart()`** | 액티비티가 **사용자에게 보여지기 시작**할 때 호출됨. (`Created` $\rightarrow$ `Started`) | 🖼️ **화면 표시 준비**: UI를 관리하는 코드 초기화. 예를 들어, 동영상 플레이어의 UI는 보이기 시작하지만, 아직 재생은 시작하지 않은 상태. 브로드캐스트 리시버 등록. | + | **`onResume()`** | 액티비티가 **포그라운드로 이동**하여 사용자와 **상호작용이 가능**할 때 호출됨. (`Started` $\rightarrow$ `Resumed`) | 🏃 **활발한 상호작용**: 게임의 **실제 플레이 시작**, 카메라 미리보기 시작, 애니메이션 시작, 세밀한 위치 업데이트(GPS) 시작, 센서 리스너 등록 등. | + | **`onPause()`** | 액티비티가 **포커스를 잃거나 종료**될 때 (다른 액티비티가 부분적으로 가릴 때) 호출됨. **매우 짧은 시간** 실행. | 💾 **임시 데이터 저장 및 일시정지**: **게임의 진행 상태 저장** (영구적이지 않은 데이터), 리소스 사용이 많은 애니메이션 일시정지, 카메라 미리보기 일시정지, 센서 리스너 해제. **무거운 작업 피하기**. | + | **`onStop()`** | 액티비티가 **완전히 가려져서** 사용자에게 **보이지 않을 때** 호출됨. (`Resumed` $\rightarrow$ `Stopped`) | 🛑 **시스템 리소스 해제**: 화면에서 완전히 사라진 경우, **백그라운드에서 불필요한 작업 중지** (예: 위치 정보 업데이트를 정밀 $\rightarrow$ 대략적으로 변경), 동영상 재생 중지, 대규모 데이터베이스 트랜잭션 등 시간이 오래 걸리는 작업 완료. | + | **`onDestroy()`** | 액티비티가 **소멸되기 직전**에 호출됨. (메모리에서 완전히 제거) | 🗑️ **최종 정리**: `onStop()`에서 마무리되지 않은 모든 **리소스 해제 및 정리** (브로드캐스트 리시버 해제, 열려있는 데이터베이스 연결 닫기 등). | +- SharedPreferences + - SharedPreference란 무엇일까요? + 1. 데이터를 저장하는 안드로이드 API + + (보통데이터를 저장할때는 db를 사용하지만 sharedpreference를 쓰는 이유는 간단하게 저장을 하기 위해서) + + 1. xml 파일형태로 데이터를 저장 + 2. 어플리케이션이 삭제되기 전까지 데이터가 보존된다 + 3. key-value형태로 데이터가 저장된다. + - SharedPreference는 어떤 방식으로 값을 저장할까요? + - [**`getSharedPreferences()`](https://developer.android.com/reference/android/content/Context?hl=ko#getSharedPreferences(java.lang.String,%20int)):** 이름으로 식별되는 공유 환경설정 파일이 여러 개 필요한 경우 이 메서드를 사용합니다. 이름은 첫 번째 매개변수로 지정할 수 있습니다. 앱의 모든 [**`Context`**](https://developer.android.com/training/data-storage/shared-preferences?hl=ko#kotlin:~:text=this%20from%20any-,Context,-in%20your%20app)에서 이 메서드를 호출할 수 있습니다. + - [**`getPreferences()`](https://developer.android.com/reference/android/app/Activity?hl=ko#getPreferences(int)):** 활동에 공유 환경설정 파일을 하나만 사용해야 하는 경우 [**`Activity`**](https://developer.android.com/reference/android/app/Activity?hl=ko)에서 이 메서드를 사용합니다. 이 메서드는 활동에 속한 기본 공유 환경설정 파일을 검색하기 때문에 이름을 제공할 필요가 없습니다. + + ```kotlin + val sharedPref = activity?.getSharedPreferences( + getString(R.string.preference_file_key), Context.MODE_PRIVATE) + ``` + + https://developer.android.com/training/data-storage/shared-preferences?hl=ko + + - JSON과 GSON이란 무엇일까요? + + json은 데이터를 주고받기위해 사용되는 개방형 표준 포맷이다. 사람이 읽기 쉬운 텍스트 형식으로, 언어와 플랫폼에 독립적이여서 시스템 간 데이터교환에 용이, 주로 웹 애플리케이션과 서버간에 데이터를 전송할 때 많이 사용된다. + + gson은 구글에서 개발한 자바 라이브러리이다. 복잡한 별도의 로직없이 자바객체와 json데이터를 상호변환할수 있게 해준다.  Java 개발자가 JSON 데이터를 다룰 때, `toJson()`을 사용하여 Java 객체를 JSON 문자열로 변환하고, `fromJson()`을 사용하여 JSON 문자열을 Java 객체로 변환하는 등 데이터 처리 작업을 효율적으로 할 수 있도록 돕는다. \ No newline at end of file From 33ccf3a6a326ab19da77eeece065c844d55ecf5f Mon Sep 17 00:00:00 2001 From: sungahbak Date: Wed, 5 Nov 2025 12:20:07 +0900 Subject: [PATCH 2/3] =?UTF-8?q?mission=20:=206=EC=A3=BC=EC=B0=A8=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20-(1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 9th_Android | 2 +- app/src/main/res/drawable/apple_44.png | Bin 0 -> 4823 bytes .../main/res/drawable/btn_actionbar_close.png | Bin 0 -> 773 bytes .../main/res/drawable/btn_input_password.png | Bin 0 -> 1931 bytes .../main/res/drawable/btn_setting_phone.png | Bin 0 -> 1070 bytes .../button_background_black_color.xml | 10 + .../drawable/button_background_flo_color.xml | 10 + .../button_background_white_color.xml | 10 + .../res/drawable/ico_20_logo_tid_white.png | Bin 0 -> 1676 bytes app/src/main/res/drawable/kakako_44.png | Bin 0 -> 8323 bytes app/src/main/res/drawable/naver_44.png | Bin 0 -> 7504 bytes app/src/main/res/layout/activity_login.xml | 284 ++++++++++++++++++ app/src/main/res/layout/activity_signup.xml | 200 ++++++++++++ 13 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/apple_44.png create mode 100644 app/src/main/res/drawable/btn_actionbar_close.png create mode 100644 app/src/main/res/drawable/btn_input_password.png create mode 100644 app/src/main/res/drawable/btn_setting_phone.png create mode 100644 app/src/main/res/drawable/button_background_black_color.xml create mode 100644 app/src/main/res/drawable/button_background_flo_color.xml create mode 100644 app/src/main/res/drawable/button_background_white_color.xml create mode 100644 app/src/main/res/drawable/ico_20_logo_tid_white.png create mode 100644 app/src/main/res/drawable/kakako_44.png create mode 100644 app/src/main/res/drawable/naver_44.png create mode 100644 app/src/main/res/layout/activity_login.xml create mode 100644 app/src/main/res/layout/activity_signup.xml diff --git a/9th_Android b/9th_Android index 02b7314..7a52fec 160000 --- a/9th_Android +++ b/9th_Android @@ -1 +1 @@ -Subproject commit 02b731467639ace62f7acc042d044bf7031540fe +Subproject commit 7a52fecad4d0ac08a97e1e894f2c94d59154a034 diff --git a/app/src/main/res/drawable/apple_44.png b/app/src/main/res/drawable/apple_44.png new file mode 100644 index 0000000000000000000000000000000000000000..f365d20cd278394af14d8774bb7209f363f9ffda GIT binary patch literal 4823 zcmV;|5-9D7P)Px{kx4{BRCodHU2BXLMHX(J3NnC*fUqlJh&md;8CFG!D2gCN(U=%bR@4m%KS)rF ziLYqlEZK<|Tw;u?tmv{~CE_DG!8a?97?nq0oe>R8h#(>Z$ZO;cI@Eq&J9pCe-tIg7 zy7zWhos*pD?z+|0b-wd;O?5pxSt3CY=#I$4p_jDj5FC3!D+(xnvW^tcqxfwXw5d(M z$MG~�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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/button_background_black_color.xml b/app/src/main/res/drawable/button_background_black_color.xml new file mode 100644 index 0000000..a4afe1d --- /dev/null +++ b/app/src/main/res/drawable/button_background_black_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_background_flo_color.xml b/app/src/main/res/drawable/button_background_flo_color.xml new file mode 100644 index 0000000..046ded6 --- /dev/null +++ b/app/src/main/res/drawable/button_background_flo_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_background_white_color.xml b/app/src/main/res/drawable/button_background_white_color.xml new file mode 100644 index 0000000..679a1fd --- /dev/null +++ b/app/src/main/res/drawable/button_background_white_color.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ico_20_logo_tid_white.png b/app/src/main/res/drawable/ico_20_logo_tid_white.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f4d4f9b718f08a557e099b2f96d2e250d111ad GIT binary patch literal 1676 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 N002ovPDHLkV1hXtFdYB@ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/naver_44.png b/app/src/main/res/drawable/naver_44.png new file mode 100644 index 0000000000000000000000000000000000000000..d9844877b9cc803cbcd331ce7b1159b630b4ff55 GIT binary patch literal 7504 zcmV-W9k1evP)Py73Q0skRCodHT?w!p#d-c`R|iiQiU0|Oq=%%~qM{Ip5fQ{dm98h^R5=w=q*4eI zaBvxnO&M&LiHR}ha7X|{85{$_;DEtSsG^-w@kH4#Sr>Bp!dBLm~6%Es5{%8{xo z)#V9+w>lSrv)9R(ox5coz&Rb{oCDI$@jP7fG81XDZu*4p2T|50lr@0z2jCw-`5Pvm zAnRV4CkGQQtL?=pfzgH3toz=Sa{M3?%INAZ|}PK>;EkLVaIE2d>VDtU0Go);;aXU^}%TiMn0sfMAP2(3JBK=`t9284 zrhYeTg&co0C!YstzX&NOmX(B-lc?0Pd0s11ysWrpM^Zz3AT+hJAvOqJ!R-Q(?;Dws z2i{mBdn=@Eo9K=p@JH9kiH8o$_0XEvg1pCm0v>m_vz^?Q-P!wsoRT{zH={$YM1PHTI%en=E%Oj#h@1A(Lu>_FAh2Lw z>pc3+3$=sC7+MXe$D9{&wvO*tj{l75y6jRs}J-dgs2{YbW=iGc)iQzDy(eX3IC)>X{fn}#b25W z>gq>;W<{Qh(lHtt|73fxVtC`0rSb^;F)8XVH>sR0N#L0)Wy;ZG@+2C$D7K-P0?Tmc zLYvLq#br%B9r=WEsdlk%L118JN zirFv$*2%@1X*X=xj58}hlpPsQmO&e@ZY2y_Mu**!m&}aiatk)wtcZ};Hy5xyT*;dr zeaw70G3LLUquO9UoXoyqAF;2}t3_>+ood#WIjPi~*Bv|rlOZn)A~LyhHWr~RQPW86 zIyV4}&3%C8ab?eSo~+6CKpVHfyz#KpV#Z2YoEtRcogBdl(_&_7%#G0drXi5Wlp8-0 z=gH1YR+epDEGr{%O$->;zk+GYOkVt~GUJrIP2@qzqNqUF7mRJQ=nsKy^qZ^_gL+!&KF#n-FF> zc)2`?nTD&}HuKl6CWDJgYu%SJDWHWOnZH!7ZuT;CQwe<98aZz8u>2U~gFg#(3u@tU zdMx@24<*x^)4`2#hwm!A`f_0n|52;$MKop9G2DZ$@jHLST^hQTY19-&ChN@7 z;?N3PQ7~s4xVn~jX~iPc*Fp$zV7DLj32S2Z|8;LJmHU&dX`+H3~|@Cd7<>S%h~+^rIrdFDjVp zZM1fpzhe-{W69YZLRf534(|l%+uA3qib1ve8X_>C9zHfGzk>EHK7dKPmop9loola@ z=IB5KFe71RCNM+cJ1jT9Ga@TzHuAJ{-82JfJwEy#A}?xYHs{nW)o+?!I}QPG!f?ZC z7`ap6P~D2OZmRX-&=J&SkyW3e&FI+YpiU8pMF8B0d0=5tflIMjDh1ZX{K9ch1Na3M zPt5T*=u|3ER?Lj!7)~I>N&=$E)9H$XO-FHrQORt4(b$vDiAPSu~a9y zL{3$aHIl><6N!rrD4Y`cpIER6@|rWsbjmCiFAa=Gz#J^d=a9dTMDFC^#zdwwtIwORzs8O}EQpb&X{ZmnA{Yg))S@Nu~g>i!D5l4c)hO;YUK z>hD?vr~=6w9=ct0CvV>*d$7Q}_Op_)0zK@XQM4VuPOjet31o99dv97uT>E4j0_Rq>Y5>NGH4Wo46B z2W~#rdQAWUcR**j2F_I@x}pZ=qQ$|(vIW9|jd4cp2fDbLVl<5+PyqqFufv=YUrcsz z%xLMYw75}G1DiKsTI4meze?UB%<4-90dgv=PRA6uS5|&Fi<7kQ?%^$%ItyOks@m59 zNpF)wz|q23V&02)JNK4*w{uwyTzGMIKwfT<%3wCMSo0LcVlBQG1L=Erk6esPKwjD> z=7oacWO}CvB#J=HD}qlfa51)=k_3kOzTD0cBiN2szao$f0x^mbT>Mli;jtzJ7cTIw zux-c`5ZpW_q2V7i0YQstF;L6PGTaAo=E+heuMLs< z(?kGVb56U=6gU|vHTD4@sO8JC8WK3Jl(f4$dDJvHd)#@6HshszKbPIdb|xZo@x)Kc z=uC1G>;ng1liz;$>qP1{976bHyLoeHp>T2%-n-noL`;a&`sJ)+Ir*O;AyQ@m{L@GNEz!EJdH+A;ih)lgBJ;mLwo^_Rc~T;>DCC}PH_Lan-}mL?sMkw4trC$HLd3CsjP5U&#r58kMw+nl_9+mgO6nD{4h>EzEQEmq|b0dUSS zBgEw# zcxbV@k_e2=j+1+4{QwFh1ZBze8c_oRh`=9B zxIjL0$_>Q;^(BUY%R!f;Ap*l*USO9T9L#11sy`NiFHgH&KGHKcHckWUN5JKv%h7O7{ag8i zvFDUdpfNQg;BwLCYCvExJ49fKU8AeH?5@i&0%+ei`w1D%_hKutHoE@6H+_@X`zhVY)LqfQ5$C`gDDOn>* zB5>uD>*Tx%p-G*RX*Hq(0_38#nT%W|XPL`rV8owpi*Tnd>^SvThk%C%y6&F!n2gI7 z4>GDQr>2TSz~!XRSwmph6mvqEOlT-XZ|Xo`+UQ>SM(=%fK=re(9&<7cE3y+d1@0%>dYeC ztqpj==A2B%oq;Io;?6{27+ZDxh>4h5dvq9U(B?%u+~iam_3hM9vs43z;7I!B!ijxy z+2m`I7TX>2qTHOy$CdeF*rHSWw}?ebzME#;CB376HznyEEY{&Bxtqy*VFEj8Iv9=N zYucFXSo!wsf6>Q~YU~1+o8)c=fgug-PFK`eh9<8PfqCQqSgt|0y!V;ajCLu5?Gs^589vSoec$2EoR>ip7 zBzH47`6OgQxGZn07B;!EIh=slsQbOKXUZ2({YIl=x*~ssn{k6U-3MGf7an>$a#UCK znXQ!9O#P}%$WF9E)EkR{Gm0A;#5o#R2^1JXhgaQa2_~(l(1_lr(1s8OW%6<4Y_^mm)gD^ zZP5USo8)c=YFG)}VDCM(^I`ef`_DHhMYC5#z#%ZXn}N+6A~5FG)YXB&SKjy=*?a80 zI&x~3Y7vNVlNuO&4G|cuR#yiCJCAOcn>Kx}j+~mMS_E8flDiQTLit-QoY8bY-ScDl z_ua{!0v|1I4&$9BtCH(lih>wN+UxC@_HnS%-84C3sUY9vr*SBhBu{&Vu9osV>7+nd>FXygN2 z$k-k#wDINrkhpHWxoyi0vhDEZZf$-#?RL4Dm$x_zu_06%-jb-UaRffVt0up+@d`;| z!%yS2=@1DHH(>)0WHK2Uu$$-F8FrldYeQh|{-4YDcj(blwV_rzwaZO%H#2UkY($nK zx1pwWAXgg1T4V0oc9Z0Kb!;iS*mAp&DG7lJ@Fa0rehZU*HT zOo_|o!`z2Si0eKX4kuwk7|srv5YAMZYT$JE@!Jo7E&sUfYv~B@aH%dQ{pnvr;K?V* zI;i9$0R~jp?#_uIQaz0zz-hIY_WisO5#5)UT(nFGa+RDV5Qf07%#(xguVsMm@<)B2 zUXw*2Zx%QX42E{GCR;>@NsHm)+5%^buULmou{zZ5W1%~}Nf3cIk8GA(w_Kl~#10qb zaM9+f(ZFmzv~-BTI&GOQDgO1{@5`$9o=dlo4w3G1(dKGE;0e>@B{2I?&}NMK+_|?P zPCbbrz-^cB9o?OXtWFhTIB3m4kfY?P-`;@0T-88e=#T?X?O-3LRIcwH-61z^*0X}k zfg8iY7Ykf9*#ZLd4x_s@wlH_7B)`3!74uYd0Q+I^jX0Um+ zrLBddKV;|#x8dM=`G^`a}r4 zxldk&s(vk~ECoe>2|=`a6oFI_Am=Q_2~MsjH{G%#1ZD!{3u|GWPIGb7`;-xI2XEly z6LCex5*TcM5{ZKe31dcBn|#1fbZktw9I^M?^=*(7noG)xg_7y)q1aLp3ra?y&44&waClP1YC z@bB{PNnTfQ5T_nRARz=|6y>f07h_8(se!rQ63h=BYQQ;R^LTTtC=FBu8bg5Ga@QTm zL4WUWob-|eX5x_n_T1{pD|^K?orfI~eABS3BiQwPS3-AfLZE2S)f-&g|j=HQ4dzms8{%xmQVcMFJZEp4^RXYk}V7E_v73u2hi5D*~ku zFp~qe?MtqKbEVST;Z+gXOd@;o13P1$4bS zftfhdBj1D;-sflJyl^gBa1gB?MW7l442L+bDmZd1Ge&Op?<-xaCh(RE;JtE0@oXtD3;fG=B-^yj`DQwGP z`6cX>M{U7o0y?0y9ix6lAO-<&#a*-@r^v0C)MbNeCNQP-jFKBMPq!zKj0)Kg-v#07 zQ3PTTFkG<|9=SwL#U!m5R2PBG;zr&n5YI2Uzp9F*Yl5yrz;MKQ)(!7_yRn)@i#V{L zx$AS-Ipj@WE-R3Gku4!J4tJr`ChS=CcQpbaZZ7m*ScAr@ZA)bdw6LX8cpIH@G>3S-tdD|xUYJyW7wA9QA1 z9C^WwOjed9MP34z7=bBl>rzasdGba21BYLqJ8>Pvsi!j$DAniS#@5B*^F|s4AW;Id zGH))G`!O?dN2p?)LgD#o>w+3 z&nNN-%q+oTV84=gkK07fQIz3L4KIIa+-y2TXh;9N~1TejX;S$ERdI)H&yZyoYV=- zLeP*M{5A3~h4+E;XD5`z0VHkXA$j9w8)!BRY2F>pXiHNF%!U|E40{M94h`%$pd%3O zT6r@XuVvJS0Q<_27ky_t_HDuDO{O=a_^6gg}JW_zYBmoLDCxDVbiT~RCZf<=9@Bc*PyQ7oUN;0p&GlK~+) zZXHNtg{|5e4l99K$r;OK34Yu^1USWAY=zpZNl|S#rkAdi$pGT+gx0yt?0-qG_==K; zoxrSNVJqg7An}4ojiH5&Hg1WUMrzl&0UTUY>q7fR9QN~KOJt(E$|7Y{84&*Kt};{7 z$+*4lsy-ppY%czb~A~7W3`|E0KB=Ljc4j*2Fx9ygBv}`zpyTk&V>7<@DN& zep!T7yC?CP;x-KDW{Hf!AWv;$7n(%w%{~V1X9%khBO8ko=J`iHLY7Ej2?=RA0<&E+ zSIU&5$IQzX7sa*{GZi>3(;fQ7Ce^?y5CCD#DUq1pE#X%2>ET8nz$_uVq2QJzFk8fP zCwiC5Re4YDgnv?`m8dzV+q_Yc7!9Za0dqzfkI9YBF!1PvJv?*-4_`h4e@u!R3Q8$y z%M#dc??>0jiHDAW#CUcT5Ju`tv%(vV)cmNc9s$_7v~}am1)vPQA&>I7r+QD!slFnO zrHl}wF>&eT?p-P84GzlpK;koFOF>IASjo#nBSTxLi$MVYWac$#=1o(j^eK)wd})zxMhdWC!*TH{vWKOq(!YGjg_8o8}n7u%X-0s)rMw$6LlY~g@v9}k!2 z`Mk|u4z}x2tG_L~nDfTi{eLqWdnNiN-grRENMbHcOSeAOj~!#?Tn4_Lr-a4@OpJYu z$NIO*)EMehwQEZP`>mVaFH_MmU&deKXAy=8ws_}(z-F+=0bg6UIKF+MP!biI)(p9)dy(RbWcYR*l*~p6>|L19BkygIh*1{KRotIGIQq}v~!-~%8c-92(Kh=kb#!$us5N`flZED{rfHQ{v#! zP6mmWp`j%6?^j&_?Ph#PegB%LKV`&FNAXBbe5hT6Yk7M%)GXBTHHdi}*C*TAz6~|1 z#7)ZGQKHmg3O=o0&KiVPM)8+|D3QGuRaJ{5#>dQT@CpP8qEBv`pN8ZN^wDJ?K8Bq1 z!cUSi*nE+&GzEC&rw)fQdCu-rS!mnMeK=&XOPmjJmo#^%nVe64xnJgiD+@uQ1qeMK zq~h+1ws9aV7l2ApJNonth>ffqAdbh* zm+=5{JpCZtIM}sAVYpH};`d`$*M8W<`;q1V((DH*O&I-1vONc)!hYQ_ZmMil%}Ug& abN>%w^3q|Q=HGq*0000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_signup.xml b/app/src/main/res/layout/activity_signup.xml new file mode 100644 index 0000000..9b174bf --- /dev/null +++ b/app/src/main/res/layout/activity_signup.xml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ff91aa0b50d3f3f37d0cdac2c51802d0698c2e18 Mon Sep 17 00:00:00 2001 From: sungahbak Date: Mon, 10 Nov 2025 10:15:00 +0900 Subject: [PATCH 3/3] =?UTF-8?q?mission=20:=206=EC=A3=BC=EC=B0=A8=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20-(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 11 +- app/src/main/AndroidManifest.xml | 6 + app/src/main/java/com/example/umc/Album.kt | 8 +- app/src/main/java/com/example/umc/AlbumDao.kt | 34 --- .../java/com/example/umc/AlbumRVAdapter.kt | 6 +- .../main/java/com/example/umc/HomeFragment.kt | 68 +++--- .../java/com/example/umc/LockerFragment.kt | 17 +- .../java/com/example/umc/LoginActivtity.kt | 28 +++ .../main/java/com/example/umc/MainActivity.kt | 215 ++++++++++++++++-- .../com/example/umc/SavedAlbumFragment.kt | 20 ++ .../java/com/example/umc/SignupActivity.kt | 17 ++ .../main/java/com/example/umc/SongActivity.kt | 25 +- .../main/java/com/example/umc/SongDatabase.kt | 6 +- .../java/com/example/umc/SongListConverter.kt | 29 +++ .../res/drawable/selector_chip_background.xml | 5 + .../main/res/drawable/selector_chip_text.xml | 5 + app/src/main/res/layout/activity_login.xml | 3 +- app/src/main/res/layout/fragment_home.xml | 20 +- app/src/main/res/layout/fragment_locker.xml | 3 +- .../res/layout/fragment_locker_savedalbum.xml | 18 ++ app/src/main/res/layout/fragment_search.xml | 107 ++++++++- 21 files changed, 512 insertions(+), 139 deletions(-) delete mode 100644 app/src/main/java/com/example/umc/AlbumDao.kt create mode 100644 app/src/main/java/com/example/umc/LoginActivtity.kt create mode 100644 app/src/main/java/com/example/umc/SignupActivity.kt create mode 100644 app/src/main/java/com/example/umc/SongListConverter.kt create mode 100644 app/src/main/res/drawable/selector_chip_background.xml create mode 100644 app/src/main/res/drawable/selector_chip_text.xml create mode 100644 app/src/main/res/layout/fragment_locker_savedalbum.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 369b6c6..e1018f8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -34,6 +34,7 @@ android { } buildFeatures { viewBinding = true + dataBinding = true } kotlinOptions { jvmTarget = "11" @@ -44,7 +45,7 @@ android { dependencies { - implementation("androidx.core:core-ktx:1.10.1") + implementation("androidx.core:core-ktx:1.13.1") implementation(libs.androidx.appcompat) implementation(libs.material) implementation(libs.androidx.activity) @@ -57,13 +58,13 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + implementation("androidx.core:core-splashscreen:1.0.1") + implementation("com.google.android.material:material:1.13.0") + implementation("me.relex:circleindicator:2.1.6") + val roomVersion = "2.6.1" - // 💡 Kotlin DSL 문법에 맞게 'roomVersion' 변수를 사용합니다. implementation("androidx.room:room-runtime:$roomVersion") - - // 💡 kapt를 dependencies 블록 내부에서 함수 호출처럼 사용합니다. kapt("androidx.room:room-compiler:$roomVersion") - implementation("androidx.room:room-ktx:$roomVersion") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1da4141..953ca88 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,6 +29,12 @@ android:name=".SongActivity" android:exported="false"/> + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/Album.kt b/app/src/main/java/com/example/umc/Album.kt index b7127bb..e13be88 100644 --- a/app/src/main/java/com/example/umc/Album.kt +++ b/app/src/main/java/com/example/umc/Album.kt @@ -1,14 +1,18 @@ package com.example.umc import androidx.room.Entity +import androidx.room.Ignore import androidx.room.PrimaryKey import java.util.* @Entity(tableName = "AlbumTable") data class Album( - @PrimaryKey(autoGenerate = false) var id: Int = 0, // album의 pk는 임의로 지정해주기 위해 autogenerate 안씁니다. + @PrimaryKey(autoGenerate = false) + var id: Int = 0, var title: String? = "", var singer: String? = "", - var coverImg: Int? = null + var coverImg: Int? = null, + @Ignore + val songs: List = emptyList() ) \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/AlbumDao.kt b/app/src/main/java/com/example/umc/AlbumDao.kt deleted file mode 100644 index 6a568c2..0000000 --- a/app/src/main/java/com/example/umc/AlbumDao.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.umc - -import androidx.room.* -import androidx.room.RoomDatabase - -@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 - - @Query("SELECT * FROM AlbumTable WHERE id = :id") - fun getAlbum(id: Int): Album - - @Insert - fun likeAlbum(like: Like) - - @Query("DELETE FROM LikeTable WHERE userId = :userId AND albumId = :albumId") - fun disLikeAlbum(userId: Int, albumId: Int) - - @Query("SELECT id FROM LikeTable WHERE userId = :userId AND albumId = :albumId") - fun isLikedAlbum(userId: Int, albumId: Int): 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 -} \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/AlbumRVAdapter.kt b/app/src/main/java/com/example/umc/AlbumRVAdapter.kt index 585204a..b0aeb89 100644 --- a/app/src/main/java/com/example/umc/AlbumRVAdapter.kt +++ b/app/src/main/java/com/example/umc/AlbumRVAdapter.kt @@ -4,7 +4,6 @@ import android.text.Layout import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView - import com.example.umc.databinding.ItemAlbumBinding class AlbumRVAdapter(private val albumList:ArrayList):RecyclerView.Adapter(){ @@ -12,6 +11,7 @@ class AlbumRVAdapter(private val albumList:ArrayList):RecyclerView.Adapte interface MyItemClickListener{ fun onItemClick(album: Album) fun onRemoveAlbum(position: Int) + fun onPlayButtonClick(album: Album) } private lateinit var mItemClickListener: MyItemClickListener @@ -42,6 +42,10 @@ class AlbumRVAdapter(private val albumList:ArrayList):RecyclerView.Adapte holder.bind(albumList[position]) holder.itemView.setOnClickListener { mItemClickListener.onItemClick(albumList[position])} // holder.binding.itemAlbumTitleTv.setOnClickListener { mItemClickListener.onRemoveAlbum(position) } + + holder.binding.itemAlbumPlayImgIv.setOnClickListener { + mItemClickListener.onPlayButtonClick(albumList[position]) + } } override fun getItemCount(): Int = albumList.size diff --git a/app/src/main/java/com/example/umc/HomeFragment.kt b/app/src/main/java/com/example/umc/HomeFragment.kt index 922f32b..39d1662 100644 --- a/app/src/main/java/com/example/umc/HomeFragment.kt +++ b/app/src/main/java/com/example/umc/HomeFragment.kt @@ -1,6 +1,7 @@ package com.example.umc import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -8,43 +9,42 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.viewpager2.widget.ViewPager2 import com.example.umc.databinding.FragmentHomeBinding -import java.util.zip.Inflater -import com.example.umc.AlbumFragment - -import java.util.ArrayList import com.google.gson.Gson +import java.util.ArrayList class HomeFragment : Fragment() { - lateinit var binding : FragmentHomeBinding + lateinit var binding: FragmentHomeBinding private var albumDatas = ArrayList() + private lateinit var songDB: SongDatabase + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ) : View? { + ): View { binding = FragmentHomeBinding.inflate(inflater, container, false) -// binding.homePannelAlbumImgIv2.setOnClickListener { -// (context as MainActivity).supportFragmentManager.beginTransaction().replace(R.id.main_frm,AlbumFragment()).commitAllowingStateLoss() -// } +// binding.homeAlbumImgIv1.setOnClickListener { +// (context as MainActivity).supportFragmentManager.beginTransaction() +// .replace(R.id.main_frm , AlbumFragment()) +// .commitAllowingStateLoss() +// } + + songDB = SongDatabase.getInstance(requireContext())!! + albumDatas.addAll(songDB.albumDao().getAlbums()) // songDB에서 album list를 가져옵니다. + Log.d("albumlist", albumDatas.toString()) - albumDatas.apply{ - add(Album(1,"Butter", "방탄소년단 (BTS)", R.drawable.img_album_exp)) - add(Album(2,"Lilac", "아이유 (IU)", R.drawable.img_album_exp2)) - add(Album(3,"Next Level", "에스파 (AESPA)", R.drawable.img_album_exp3)) - add(Album(4,"Boy with Luv", "방탄소년단 (BTS)", R.drawable.img_album_exp4)) - add(Album(5,"BBoom BBoom", "모모랜드 (MOMOLAND)", R.drawable.img_album_exp5)) - add(Album(6,"Weekend", "태연 (Tae Yeon)", R.drawable.img_album_exp6)) - } + // 더미데이터랑 Adapter 연결 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) } @@ -53,7 +53,14 @@ class HomeFragment : Fragment() { albumRVAdapter.removeItem(position) } + override fun onPlayButtonClick(album: Album) { + val gson = Gson() + val albumJson = gson.toJson(album) + } }) + // 레이아웃 매니저 설정 + binding.homeTodayMusicAlbumRv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + val bannerAdapter = BannerVPAdapter(this) bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp)) bannerAdapter.addFragment(BannerFragment(R.drawable.img_home_viewpager_exp2)) @@ -62,16 +69,17 @@ class HomeFragment : Fragment() { return binding.root } -} -private fun HomeFragment.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() + 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() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/LockerFragment.kt b/app/src/main/java/com/example/umc/LockerFragment.kt index 895f09f..f8b5d51 100644 --- a/app/src/main/java/com/example/umc/LockerFragment.kt +++ b/app/src/main/java/com/example/umc/LockerFragment.kt @@ -1,13 +1,16 @@ package com.example.umc +import android.content.Intent import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button import androidx.fragment.app.Fragment import com.example.umc.databinding.FragmentLockerBinding import com.google.android.material.tabs.TabLayoutMediator +import kotlin.jvm.java class LockerFragment : Fragment() { @@ -29,11 +32,18 @@ class LockerFragment : Fragment() { val lockerAdapter = LockerVPAdapter(this) + val loginButton: Button = view.findViewById(R.id.locker_login_tv) + loginButton.setOnClickListener { + val intent = Intent(requireContext(), LoginActivity::class.java) - lockerAdapter.addFragment(SavedSongFragment()) - lockerAdapter.addFragment(MusicFileFragment()) - lockerAdapter.addFragment(SavedAlbumFragment()) + startActivity(intent) + + } + +// lockerAdapter.addFragment(SavedSongFragment()) +// lockerAdapter.addFragment(MusicFileFragment()) +// lockerAdapter.addFragment(SavedAlbumFragment()) binding.lockerContentVp.adapter = lockerAdapter @@ -42,7 +52,6 @@ class LockerFragment : Fragment() { tab.text = information[position] }.attach() - // 앱이 시작될 때 '저장앨범' 탭(인덱스 2)을 선택하도록 설정 binding.lockerContentVp.setCurrentItem(2, false) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/LoginActivtity.kt b/app/src/main/java/com/example/umc/LoginActivtity.kt new file mode 100644 index 0000000..37c73a7 --- /dev/null +++ b/app/src/main/java/com/example/umc/LoginActivtity.kt @@ -0,0 +1,28 @@ +package com.example.umc + +import android.content.Intent +import android.os.Bundle +import android.widget.Button +import androidx.appcompat.app.AppCompatActivity +import com.example.umc.databinding.ActivityLoginBinding + + +class LoginActivity : AppCompatActivity() { + lateinit var binding: ActivityLoginBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding.root) + + val loginButton: Button = findViewById(R.id.login_sign_up_tv) + + loginButton.setOnClickListener { + + val intent = Intent(this, SignupActivity::class.java) + + startActivity(intent) + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/MainActivity.kt b/app/src/main/java/com/example/umc/MainActivity.kt index 2f814d6..d0bfc23 100644 --- a/app/src/main/java/com/example/umc/MainActivity.kt +++ b/app/src/main/java/com/example/umc/MainActivity.kt @@ -1,44 +1,78 @@ package com.example.umc import android.content.Intent -import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import android.widget.TextView -import com.example.umc.databinding.ActivityMainBinding +import android.os.Bundle import android.util.Log -import com.example.umc.SongActivity +import com.example.umc.databinding.ActivityMainBinding +import com.google.gson.Gson +import com.google.android.material.chip.Chip + class MainActivity : AppCompatActivity() { - private lateinit var binding: ActivityMainBinding + lateinit var binding: ActivityMainBinding + + private var song:Song = Song() + private var gson: Gson = Gson() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - // View Binding 적용 + setTheme(R.style.Theme_Umc) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - val song = Song(binding.mainMiniplayerTitleTv.text.toString(),binding.mainMiniplayerSingerTv.text.toString(),0,60,false,"music_lilac") - + inputDummySongs() + inputDummyAlbums() initBottomNavigation() +// val song = Song(binding.mainMiniplayerTitleTv.text.toString(), binding.mainMiniplayerSingerTv.text.toString(),0,60,false) binding.mainPlayerCl.setOnClickListener { - //startActivity(Intent(this,SongActivity::class.java)) - 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) + val editor = getSharedPreferences("song", MODE_PRIVATE).edit() + editor.putInt("songId",song.id) + editor.apply() + + val intent = Intent(this,SongActivity::class.java) startActivity(intent) } + Log.d("MAIN/JWT_TO_SERVER", getJwt().toString()) - Log.d("Song",song.title+song.singer) } + override fun onStart() { + super.onStart() +// val sharedPreferences = getSharedPreferences("song", MODE_PRIVATE) +// val songJson = sharedPreferences.getString("songData", null) +// +// song = if(songJson == null){ +// Song("라일락", "아이유(IU)", 0,60, false, "music_lilac") +// } else { +// gson.fromJson(songJson, Song::class.java) +// } + val spf = getSharedPreferences("song", MODE_PRIVATE) + val songId = spf.getInt("songId",0) + + val songDB = SongDatabase.getInstance(this)!! + + song = if (songId == 0){ + songDB.songDao().getSong(1) + } else{ + songDB.songDao().getSong(songId) + } + + Log.d("song ID", song.id.toString()) + setMiniPlayer(song) + } + + + private fun getJwt(): String? { + val spf = this.getSharedPreferences("auth2" , AppCompatActivity.MODE_PRIVATE) + + return spf!!.getString("jwt", "") + } + + private fun initBottomNavigation(){ supportFragmentManager.beginTransaction() @@ -78,4 +112,147 @@ class MainActivity : AppCompatActivity() { } } -} + private fun setMiniPlayer(song : Song){ + binding.mainMiniplayerTitleTv.text = song.title + binding.mainMiniplayerSingerTv.text = song.singer + binding.mainMiniplayerProgressSb.progress = (song.second*100000)/song.playTime + } + + private fun inputDummySongs(){ + val songDB = SongDatabase.getInstance(this)!! + val songs = songDB.songDao().getSongs() + + if (songs.isNotEmpty()) return + + songDB.songDao().insert( + Song( + "Lilac", + "아이유 (IU)", + 0, + 200, + false, + "music_lilac", + R.drawable.img_album_exp2, + false, + ) + ) + + songDB.songDao().insert( + Song( + "Flu", + "아이유 (IU)", + 0, + 200, + false, + "music_flu", + R.drawable.img_album_exp2, + false, + ) + ) + + songDB.songDao().insert( + Song( + "Butter", + "방탄소년단 (BTS)", + 0, + 190, + false, + "music_butter", + R.drawable.img_album_exp, + false, + ) + ) + + songDB.songDao().insert( + Song( + "Next Level", + "에스파 (AESPA)", + 0, + 210, + false, + "music_next", + R.drawable.img_album_exp3, + false, + ) + ) + + + songDB.songDao().insert( + Song( + "Boy with Luv", + "music_boy", + 0, + 230, + false, + "music_lilac", + R.drawable.img_album_exp4, + false, + ) + ) + + + songDB.songDao().insert( + Song( + "BBoom BBoom", + "모모랜드 (MOMOLAND)", + 0, + 240, + false, + "music_bboom", + R.drawable.img_album_exp5, + false, + ) + ) + + val _songs = songDB.songDao().getSongs() + Log.d("DB data", _songs.toString()) + } + + //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)", R.drawable.img_album_exp2 + ) + ) + + songDB.albumDao().insert( + Album( + 1, + "Butter", "방탄소년단 (BTS)", R.drawable.img_album_exp + ) + ) + + songDB.albumDao().insert( + Album( + 2, + "iScreaM Vol.10 : Next Level Remixes", "에스파 (AESPA)", R.drawable.img_album_exp3 + ) + ) + + songDB.albumDao().insert( + Album( + 3, + "MAP OF THE SOUL : PERSONA", "방탄소년단 (BTS)", R.drawable.img_album_exp4 + ) + ) + + songDB.albumDao().insert( + Album( + 4, + "GREAT!", "모모랜드 (MOMOLAND)", R.drawable.img_album_exp5 + ) + ) + + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/SavedAlbumFragment.kt b/app/src/main/java/com/example/umc/SavedAlbumFragment.kt index a940d42..2233450 100644 --- a/app/src/main/java/com/example/umc/SavedAlbumFragment.kt +++ b/app/src/main/java/com/example/umc/SavedAlbumFragment.kt @@ -1,4 +1,5 @@ package com.example.umc + import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -7,7 +8,26 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager +import com.example.umc.databinding.FragmentLockerSavedalbumBinding class SavedAlbumFragment : Fragment() { + lateinit var binding: FragmentLockerSavedalbumBinding + lateinit var albumDB: SongDatabase + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentLockerSavedalbumBinding.inflate(inflater, container, false) + + albumDB = SongDatabase.getInstance(requireContext())!! + + return binding.root + } + + override fun onStart() { + super.onStart() + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/umc/SignupActivity.kt b/app/src/main/java/com/example/umc/SignupActivity.kt new file mode 100644 index 0000000..094d25f --- /dev/null +++ b/app/src/main/java/com/example/umc/SignupActivity.kt @@ -0,0 +1,17 @@ +package com.example.umc + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.example.umc.databinding.ActivitySignupBinding + +class SignupActivity : AppCompatActivity() { + + lateinit var binding: ActivitySignupBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivitySignupBinding.inflate(layoutInflater) + setContentView(binding.root) + } +} + diff --git a/app/src/main/java/com/example/umc/SongActivity.kt b/app/src/main/java/com/example/umc/SongActivity.kt index becc656..6eaa651 100644 --- a/app/src/main/java/com/example/umc/SongActivity.kt +++ b/app/src/main/java/com/example/umc/SongActivity.kt @@ -6,13 +6,8 @@ import android.util.Log import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import com.example.umc.R -import com.example.umc.Song -import com.example.umc.SongDatabase import com.example.umc.databinding.ActivitySongBinding import com.google.gson.Gson -private lateinit var songDB: SongDatabase -private lateinit var songs: List class SongActivity : AppCompatActivity() { @@ -93,27 +88,15 @@ class SongActivity : AppCompatActivity() { } private fun initSong(){ - // 💡 1. SongDatabase 인스턴스 초기화 - songDB = SongDatabase.getInstance(this)!! - - // 💡 2. songs 리스트를 데이터베이스에서 로드 (핵심 누락 코드) - val songs = songDB.songDao().getSongs() - - // 3. 안전 장치 (리스트가 비어있는 경우) - if (songs.isEmpty()) { - Toast.makeText(this, "재생할 노래 데이터가 없습니다. 데이터를 추가해주세요.", Toast.LENGTH_LONG).show() - finish() - return - } - - // 4. 기존 로직 실행 (이제 songs 리스트가 비어있지 않으므로 안전함) val spf = getSharedPreferences("song", MODE_PRIVATE) - val songId = spf.getInt("songId", 0) + val songId = spf.getInt("songId",0) nowPos = getPlayingSongPosition(songId) + Log.d("now Song ID",songs[nowPos].id.toString()) + startTimer() - setPlayer(songs[nowPos]) // <-- 이제 이 줄이 안전하게 실행됩니다. + setPlayer(songs[nowPos]) } private fun setLike(isLike: Boolean){ diff --git a/app/src/main/java/com/example/umc/SongDatabase.kt b/app/src/main/java/com/example/umc/SongDatabase.kt index f0b4ceb..17505b7 100644 --- a/app/src/main/java/com/example/umc/SongDatabase.kt +++ b/app/src/main/java/com/example/umc/SongDatabase.kt @@ -4,11 +4,13 @@ import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase +import androidx.room.TypeConverters @Database(entities = [Song::class, Album::class, User::class, Like::class], version = 1) +@TypeConverters(SongListConverter::class) + abstract class SongDatabase: RoomDatabase() { - abstract fun albumDao(): AlbumDao abstract fun songDao(): SongDao abstract fun userDao(): UserDao @@ -22,7 +24,7 @@ abstract class SongDatabase: RoomDatabase() { instance = Room.databaseBuilder( context.applicationContext, SongDatabase::class.java, - "song-database" //다른 데이터 베이스랑 이름겹치면 꼬임 + "song-database" ).allowMainThreadQueries().build() } } diff --git a/app/src/main/java/com/example/umc/SongListConverter.kt b/app/src/main/java/com/example/umc/SongListConverter.kt new file mode 100644 index 0000000..d722a12 --- /dev/null +++ b/app/src/main/java/com/example/umc/SongListConverter.kt @@ -0,0 +1,29 @@ +package com.example.umc + +import androidx.room.TypeConverter +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import java.util.* + +class SongListConverter { + + private val gson = Gson() + + @TypeConverter + fun fromSongList(songs: List?): String? { + if (songs == null) { + return null + } + val type = object : TypeToken>() {}.type + return gson.toJson(songs, type) + } + + @TypeConverter + fun toSongList(songListString: String?): List? { + if (songListString == null) { + return null + } + val type = object : TypeToken>() {}.type + return gson.fromJson(songListString, type) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_chip_background.xml b/app/src/main/res/drawable/selector_chip_background.xml new file mode 100644 index 0000000..86787bd --- /dev/null +++ b/app/src/main/res/drawable/selector_chip_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_chip_text.xml b/app/src/main/res/drawable/selector_chip_text.xml new file mode 100644 index 0000000..8a26daa --- /dev/null +++ b/app/src/main/res/drawable/selector_chip_text.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 7a3b16f..f7cc335 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -177,12 +177,13 @@ app:layout_constraintStart_toEndOf="@+id/login_division_tv" app:layout_constraintTop_toTopOf="@+id/login_division_tv" /> - - - + + - - - - - - - + + - + + + + + + - + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index 0718e83..b024e27 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -1,23 +1,112 @@ - + android:padding="16dp"> + + + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/titleTextView" + app:chipSpacingHorizontal="12dp" + app:chipSpacingVertical="8dp" + app:singleLine="false" + app:selectionRequired="false" + app:singleSelection="true"> + + + + + + + + + + + + + + + + \ No newline at end of file