Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

7차 과제 구현 완....료는 아니고 중..... #5

Open
wants to merge 10 commits into
base: develop/view
Choose a base branch
from
6 changes: 5 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,9 @@ dependencies {
implementation("com.squareup.okhttp3:logging-interceptor")
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'androidx.fragment:fragment-ktx:1.5.4'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
implementation "androidx.fragment:fragment-ktx:1.5.3"
implementation "androidx.activity:activity-ktx:1.6.1"
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'io.coil-kt:coil:2.2.2'
}
29 changes: 18 additions & 11 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET"/>
<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:usesCleartextTraffic="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.INSOPTAndroidPractice"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
Expand All @@ -23,28 +23,35 @@
android:value="" />
</activity>
<activity
android:name=".SignUpActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".HomeActivity"
android:name=".SignUp.view.SignUpActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".SignInActivity"
android:name=".MusicList.view.MusicAddActivity"
android:exported="true">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />

<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".Home.HomeActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
Comment on lines +44 to +46

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얘모임???

</activity>
<activity
android:name=".SignIn.view.SignInActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>

</manifest>
52 changes: 52 additions & 0 deletions app/src/main/java/org/sopt/sample/ContentUriRequestBody.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.sopt.sample

import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okio.BufferedSink
import okio.source

class ContentUriRequestBody(
context: Context,
private val uri: Uri
) : RequestBody() {
private val contentResolver = context.contentResolver

private var fileName = ""
private var size = -1L

init {
contentResolver.query(
uri,
arrayOf(MediaStore.Images.Media.SIZE, MediaStore.Images.Media.DISPLAY_NAME),
null,
null,
null
)?.use { cursor ->
if (cursor.moveToFirst()) {
size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))
fileName =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))
}
}
}

fun getFileName() = fileName

override fun contentLength(): Long = size

override fun contentType(): MediaType? =
contentResolver.getType(uri)?.toMediaTypeOrNull()

override fun writeTo(sink: BufferedSink) {
contentResolver.openInputStream(uri)?.source()?.use { source ->
sink.writeAll(source)
}
}

fun toFormData() = MultipartBody.Part.createFormData("image", getFileName(), this)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sopt.sample
package org.sopt.sample.Home

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
Expand All @@ -11,12 +11,4 @@ class HomeActivity : AppCompatActivity() {
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)
}

private fun setProfile() {
val profileId = intent.getStringExtra("userId")
val profileMbti = intent.getStringExtra("userMbti")

binding.tvProfileName.text = "이름 : $profileId"
binding.tvProfileMbti.text = "MBTI : $profileMbti"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sopt.sample
package org.sopt.sample.Home

import android.os.Bundle
import android.util.Log
Expand All @@ -8,17 +8,18 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.snackbar.Snackbar
import org.sopt.sample.MusicList.MusicAdapter
import org.sopt.sample.MusicList.viewmodel.MusicShowViewModel
import org.sopt.sample.databinding.FragmentHomeBinding
import org.sopt.sample.model.UserViewModel
import org.sopt.sample.remote.ResponseUser
import org.sopt.sample.remote.UserServicePool
import org.sopt.sample.remote.api.MusicServicePool
import org.sopt.sample.remote.api.ResponseMusicShowDTO
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class HomeFragment : Fragment() {
private val userService = UserServicePool.userService
private val userViewModel by viewModels<UserViewModel>()
private val musicShowService = MusicServicePool.musicShowService
private val musicShowViewModel by viewModels<MusicShowViewModel>()
Comment on lines +21 to +22

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

홈 프래그먼트 버리고 이거로 바꿨네 ㅋㅋㅋㅋ 안아까워??


private var _binding: FragmentHomeBinding? = null
private val binding get() = requireNotNull(_binding) { "여기서 오류" }
Expand All @@ -39,15 +40,16 @@ class HomeFragment : Fragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?){
super.onViewCreated(view, savedInstanceState)
userService.getUser().enqueue(object : Callback<ResponseUser>{
override fun onResponse(call: Call<ResponseUser>, response: Response<ResponseUser>) {

musicShowService.showMusic().enqueue(object : Callback<ResponseMusicShowDTO>{
override fun onResponse(call: Call<ResponseMusicShowDTO>, response: Response<ResponseMusicShowDTO>) {
if (response.isSuccessful) {
userViewModel.userList.addAll(response.body()?.data!!)
musicShowViewModel.musicList.addAll(response.body()?.data!!)

val adapter = UserAdapter(requireContext())
val adapter = MusicAdapter(requireContext())
binding.rvHome.adapter = adapter
adapter.setRepoList(userViewModel.userList)
Log.e("Response", "onResponse: ${userViewModel.userList}" )
adapter.setMusicList(musicShowViewModel.musicList)
Log.e("Response", "onResponse: ${musicShowViewModel.musicList}" )

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Log.e("Response", "onResponse: ${musicShowViewModel.musicList}" )
Log.d("Response", "onResponse: ${musicShowViewModel.musicList}" )

대개 e는 에러가 발생했을 때 사용하는거여서 d를 사용하는게 좋아

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 하나 배워갑니다 !!


} else if (response.code() == 404) {
Snackbar.make(binding.root, "404 error", Snackbar.LENGTH_LONG)
Expand All @@ -58,9 +60,10 @@ class HomeFragment : Fragment() {
}
}

override fun onFailure(call: Call<ResponseUser>, t: Throwable) {
override fun onFailure(call: Call<ResponseMusicShowDTO>, t: Throwable) {
Snackbar.make(binding.root, "서버 통신 장애가 발생", Snackbar.LENGTH_LONG).show()
}

})
}
}
1 change: 1 addition & 0 deletions app/src/main/java/org/sopt/sample/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.sopt.sample

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.sopt.sample.Home.HomeFragment

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Expand Down
39 changes: 39 additions & 0 deletions app/src/main/java/org/sopt/sample/MusicList/MusicAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.sopt.sample.MusicList

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import org.sopt.sample.databinding.ItemLayoutBinding
import org.sopt.sample.remote.api.ResponseMusicShowDTO

class MusicAdapter(context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val inflater by lazy { LayoutInflater.from(context) }
private var musicList: List<ResponseMusicShowDTO.Data> = emptyList()

class MusicViewHolder(private val binding: ItemLayoutBinding)
: RecyclerView.ViewHolder(binding.root) {
Comment on lines +15 to +16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class MusicViewHolder(private val binding: ItemLayoutBinding)
: RecyclerView.ViewHolder(binding.root) {
class MusicViewHolder(
private val binding: ItemLayoutBinding
) : RecyclerView.ViewHolder(binding.root) {

fun setMusic(data: ResponseMusicShowDTO.Data) {
binding.ivAlbum.load(data.image)
binding.tvTitle.text = data.title
binding.tvSinger.text = data.singer
Comment on lines +18 to +20

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
binding.ivAlbum.load(data.image)
binding.tvTitle.text = data.title
binding.tvSinger.text = data.singer
with(binding) {
ivAlbum.load(data.image)
tvTitle.text = data.title
tvSinger.text = data.singer
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와,, 배워갑니다

}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binding = ItemLayoutBinding.inflate(inflater, parent, false)
return MusicViewHolder(binding)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is MusicViewHolder) holder.setMusic(musicList[position])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (holder is MusicViewHolder) holder.setMusic(musicList[position])
(holder is MusicViewHolder).let{ it.setMusic(musicList[position]) }

이렇게도 작성할 수 있어!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코틀린의 확장함수,, let, with, run, apply, also
시험끝나고 공부해 봐야지

}

override fun getItemCount() = musicList.size

fun setMusicList(musicList: MutableList<ResponseMusicShowDTO.Data>){
this.musicList = musicList.toList()
notifyDataSetChanged()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.sopt.sample.MusicList.view

import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.content.ContentProviderCompat.requireContext
import coil.load
import okhttp3.RequestBody
import org.sopt.sample.ContentUriRequestBody
import org.sopt.sample.Home.HomeActivity
import org.sopt.sample.MusicList.viewmodel.MusicAddViewModel
import org.sopt.sample.databinding.ActivityMusicAddBinding
import androidx.core.content.ContentProviderCompat.requireContext
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.sopt.sample.MainActivity

class MusicAddActivity : AppCompatActivity() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 새 창 띄워서 입력하기 ㅋㅋㅋ 성실한데?

private lateinit var binding: ActivityMusicAddBinding
private val viewModel by viewModels<MusicAddViewModel>()
private val map: HashMap<String, RequestBody> = hashMapOf()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMusicAddBinding.inflate(layoutInflater)
setContentView(binding.root)

binding.ivAlbum.setOnClickListener{
imagePickerLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo))
}

binding.btnAdd.setOnClickListener{
val title = binding.edtTitle.text.toString()
val singer = binding.edtSinger.text.toString()

map["request"] = "{\"title\": \"$title\", \"singer\": \"$singer\"}".toRequestBody("application/json".toMediaTypeOrNull())
viewModel.addMusic(map)
Comment on lines +42 to +43

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 그 실패의 흔적....!

Toast.makeText(this@MusicAddActivity, "음악 추가 성공", Toast.LENGTH_SHORT).show()
}

binding.btnList.setOnClickListener{
val intent = Intent(this@MusicAddActivity, MainActivity::class.java)
startActivity(intent)
finish()
}
}


private val imagePickerLauncher = registerForActivityResult(
ActivityResultContracts.PickVisualMedia()
) {
if (it != null) {
binding.ivAlbum.load(it)
} else {
Log.d("PhotoPicker", "사진 선택 안댐..")
}
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.sopt.sample.MusicList.viewmodel

import android.net.Uri
import android.util.Log
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import okhttp3.RequestBody
import org.sopt.sample.ContentUriRequestBody
import org.sopt.sample.remote.api.MusicServicePool
import org.sopt.sample.remote.api.ResponseMusicAddDTO
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MusicAddViewModel : ViewModel() {
private val _image = MutableLiveData<ContentUriRequestBody>()
val image : LiveData<ContentUriRequestBody>
get() = _image
private var musicAddService = MusicServicePool.musicAddService

fun setRequestBody(requestBody: ContentUriRequestBody){
_image.value = requestBody
}

fun addMusic(requestBody: RequestBody){
musicAddService.addMusic(
image.value!!.toFormData()
).enqueue(object: Callback<ResponseMusicAddDTO>{
override fun onResponse(
call: Call<ResponseMusicAddDTO>,
response: Response<ResponseMusicAddDTO>
) {
if(response.isSuccessful){
Log.d("tag","success")
}else{
Log.d("tag","fail")
}
}

override fun onFailure(call: Call<ResponseMusicAddDTO>, t: Throwable) {
Log.e("emergency","서버오류")
}

})
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.sample.MusicList.viewmodel

import androidx.lifecycle.ViewModel
import org.sopt.sample.remote.api.ResponseMusicShowDTO

class MusicShowViewModel : ViewModel() {
val musicList = mutableListOf< ResponseMusicShowDTO.Data>()
}
Loading