From f931f2feb7cb36b94d0879b25dc2702bf6391997 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 16:26:49 +0900 Subject: [PATCH 01/26] =?UTF-8?q?DESIGN=20:=20=EC=BB=AC=EB=9F=AC=20?= =?UTF-8?q?=EB=A6=AC=EC=8F=98=EC=93=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- presentation/src/main/res/values/colors.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/presentation/src/main/res/values/colors.xml b/presentation/src/main/res/values/colors.xml index 9602c786..b86d09d2 100644 --- a/presentation/src/main/res/values/colors.xml +++ b/presentation/src/main/res/values/colors.xml @@ -30,5 +30,15 @@ #6B6B6B #959595 #DBDBDB - #EEEEEE + #6B6B6B + #828282 + #959595 + #9B9B9B + #BCBCBC + #C4C4C4 + #DBDBDB + #EBEBEB + #F2F2F2 + #ACB4BE + #EEEEEE From ede10394926ee5db3af1d1484993fb6efaa64b5a Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 16:27:14 +0900 Subject: [PATCH 02/26] =?UTF-8?q?FEAT=20:=20=EC=95=A8=EB=B2=94=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=ED=99=94=EB=A9=B4=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/res/layout/fragment_album_select.xml | 17 ++++++ .../main/res/layout/recycler_album_select.xml | 59 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 presentation/src/main/res/layout/fragment_album_select.xml create mode 100644 presentation/src/main/res/layout/recycler_album_select.xml diff --git a/presentation/src/main/res/layout/fragment_album_select.xml b/presentation/src/main/res/layout/fragment_album_select.xml new file mode 100644 index 00000000..0dd364e6 --- /dev/null +++ b/presentation/src/main/res/layout/fragment_album_select.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/presentation/src/main/res/layout/recycler_album_select.xml b/presentation/src/main/res/layout/recycler_album_select.xml new file mode 100644 index 00000000..b480876b --- /dev/null +++ b/presentation/src/main/res/layout/recycler_album_select.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + From df4c5a6425a3192431aff2cfe2020dd1af392cab Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 16:53:22 +0900 Subject: [PATCH 03/26] =?UTF-8?q?FEAT=20:=20AlbumSelectAdapter=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/model/AlbumInfo.kt | 8 ++ .../albumSelect/AlbumSelectAdapter.kt | 53 ++++++++ .../main/res/layout/recycler_album_select.xml | 118 ++++++++++-------- 3 files changed, 126 insertions(+), 53 deletions(-) create mode 100644 presentation/src/main/java/com/fakedevelopers/presentation/model/AlbumInfo.kt create mode 100644 presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/model/AlbumInfo.kt b/presentation/src/main/java/com/fakedevelopers/presentation/model/AlbumInfo.kt new file mode 100644 index 00000000..40c27b28 --- /dev/null +++ b/presentation/src/main/java/com/fakedevelopers/presentation/model/AlbumInfo.kt @@ -0,0 +1,8 @@ +package com.fakedevelopers.presentation.model + +data class AlbumInfo( + val path: String, + val firstImage: String, + val name: String, + val count: Int +) diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt new file mode 100644 index 00000000..62be1f17 --- /dev/null +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt @@ -0,0 +1,53 @@ +package com.fakedevelopers.presentation.ui.productEditor.albumSelect + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.fakedevelopers.presentation.R +import com.fakedevelopers.presentation.databinding.RecyclerAlbumSelectBinding +import com.fakedevelopers.presentation.model.AlbumInfo + +class AlbumSelectAdapter( + private val onClick: () -> Unit +) : ListAdapter(diffUtil) { + + class ViewHolder( + private val binding: RecyclerAlbumSelectBinding, + private val onClick: () -> Unit + ) : RecyclerView.ViewHolder(binding.root) { + fun bind(item: AlbumInfo) { + binding.albumInfo = item + binding.root.setOnClickListener { + onClick() + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = + ViewHolder( + DataBindingUtil.inflate( + LayoutInflater.from(parent.context), + R.layout.recycler_album_select, + parent, + false + ), + onClick + ) + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + companion object { + private val diffUtil = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: AlbumInfo, newItem: AlbumInfo) = + oldItem.path == newItem.path + + override fun areContentsTheSame(oldItem: AlbumInfo, newItem: AlbumInfo) = + oldItem == newItem + } + } +} diff --git a/presentation/src/main/res/layout/recycler_album_select.xml b/presentation/src/main/res/layout/recycler_album_select.xml index b480876b..971cd687 100644 --- a/presentation/src/main/res/layout/recycler_album_select.xml +++ b/presentation/src/main/res/layout/recycler_album_select.xml @@ -1,59 +1,71 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + + + - + - + - - + + + + + + + From c7fef9b9479c12fec5ea7917d6f670bfe61343fb Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 17:31:50 +0900 Subject: [PATCH 04/26] =?UTF-8?q?FEAT=20:=20=EC=95=A8=EB=B2=94=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=99=94=EB=A9=B4=20=EC=8A=A4=ED=94=BC?= =?UTF-8?q?=EB=84=88=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../albumList/AlbumListFragment.kt | 23 +------------------ .../main/res/layout/fragment_album_list.xml | 11 --------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt index 39501c05..a4f60307 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt @@ -7,8 +7,6 @@ import android.os.Handler import android.os.Looper import android.provider.MediaStore import android.view.View -import android.widget.AdapterView -import android.widget.ArrayAdapter import androidx.activity.OnBackPressedCallback import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController @@ -126,7 +124,7 @@ class AlbumListFragment : BaseFragment( private fun handleEvent(event: AlbumListViewModel.Event) { when (event) { - is AlbumListViewModel.Event.AlbumList -> initSpinner(event.albums) + is AlbumListViewModel.Event.AlbumList -> viewModel.updateAlbumList(event.albums[0]) is AlbumListViewModel.Event.ImageCount -> handleImageCount(event.count) is AlbumListViewModel.Event.OnListChange -> onAlbumChanged(event.state) is AlbumListViewModel.Event.ScrollToTop -> scrollAlbumListToTop() @@ -162,25 +160,6 @@ class AlbumListFragment : BaseFragment( } } - private fun initSpinner(albums: List) { - binding.spinnerAlbumList.apply { - adapter = ArrayAdapter( - requireContext(), - android.R.layout.simple_spinner_item, - albums.map { album -> album.substringAfterLast("/") } - ) - onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - viewModel.updateAlbumList(albums[position]) - } - - override fun onNothingSelected(parent: AdapterView<*>?) { - // 안쓸거야!! - } - } - } - } - private fun initViewPagerIndex(idx: Int) { if (viewModel.currentViewPagerIdx == idx) { setPagerUI(idx) diff --git a/presentation/src/main/res/layout/fragment_album_list.xml b/presentation/src/main/res/layout/fragment_album_list.xml index 80ab871f..88d46135 100644 --- a/presentation/src/main/res/layout/fragment_album_list.xml +++ b/presentation/src/main/res/layout/fragment_album_list.xml @@ -35,17 +35,6 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - - Date: Thu, 9 Feb 2023 18:10:09 +0900 Subject: [PATCH 05/26] =?UTF-8?q?FEAT=20:=20=ED=8A=B9=EC=A0=95=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EC=9D=98=20=EC=9D=B4=EB=AF=B8=EC=A7=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20getImages=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/ImageRepositoryImpl.kt | 26 +++++-------------- .../domain/repository/ImageRepository.kt | 2 +- .../domain/usecase/GetImagesUseCase.kt | 12 +++++++++ 3 files changed, 19 insertions(+), 21 deletions(-) create mode 100644 domain/src/main/java/com/fakedevelopers/domain/usecase/GetImagesUseCase.kt diff --git a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt index 630b2d4e..9a493053 100644 --- a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt +++ b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt @@ -25,11 +25,10 @@ class ImageRepositoryImpl @Inject constructor( return false } - override suspend fun getAllImages(): Map> { + override suspend fun getImages(path: String?): List { val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI - val albums = mutableMapOf>().apply { - this[ALL_PICTURES] = mutableListOf() - } + val where = path?.let { MediaStore.Images.Media.DATA + it } + val images = mutableListOf() contentResolver.query( uri, arrayOf( @@ -37,7 +36,7 @@ class ImageRepositoryImpl @Inject constructor( MediaStore.Images.Media.DATA, MediaStore.Images.ImageColumns.DATE_MODIFIED ), - null, + where, null, MediaStore.Images.ImageColumns.DATE_MODIFIED + " DESC" )?.use { cursor -> @@ -49,19 +48,10 @@ class ImageRepositoryImpl @Inject constructor( ).toString() // 최근 수정 날짜 val date = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED)) - val albumItem = AlbumItem(imageUri, date) - // 전체보기에 저장 - albums[ALL_PICTURES]?.add(albumItem) - // 이미지 상대 경로에 저장 - cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)).let { path -> - val url = path.substringBeforeLast("/") - albums[url]?.add(albumItem) ?: run { - albums[url] = mutableListOf(albumItem) - } - } + images.add(AlbumItem(imageUri, date)) } } - return albums + return images } override fun getValidUris(uris: List): List = @@ -138,8 +128,4 @@ class ImageRepositoryImpl @Inject constructor( } updatedAlbumItem } - - companion object { - private const val ALL_PICTURES = "전체보기" - } } diff --git a/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt b/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt index 19a6ad21..5ec45fab 100644 --- a/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt +++ b/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.Dispatchers interface ImageRepository { fun isValid(uri: String): Boolean - suspend fun getAllImages(): Map> + suspend fun getImages(path: String?): List fun getValidUris(uris: List): List fun getDateModifiedByUri(uri: String): AlbumItem? suspend fun getBytesByUri(uri: String, dispatcher: CoroutineDispatcher = Dispatchers.IO): ByteArray? diff --git a/domain/src/main/java/com/fakedevelopers/domain/usecase/GetImagesUseCase.kt b/domain/src/main/java/com/fakedevelopers/domain/usecase/GetImagesUseCase.kt new file mode 100644 index 00000000..cc16eb61 --- /dev/null +++ b/domain/src/main/java/com/fakedevelopers/domain/usecase/GetImagesUseCase.kt @@ -0,0 +1,12 @@ +package com.fakedevelopers.domain.usecase + +import com.fakedevelopers.domain.model.AlbumItem +import com.fakedevelopers.domain.repository.ImageRepository +import javax.inject.Inject + +class GetImagesUseCase @Inject constructor( + private val repository: ImageRepository +) { + suspend operator fun invoke(path: String? = null): List = + repository.getImages(path) +} From 64c735d51ad9e43169825151dc8682c43827be14 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 18:31:28 +0900 Subject: [PATCH 06/26] =?UTF-8?q?REFACTOR=20:=20=EC=95=A8=EB=B2=94=20?= =?UTF-8?q?=EC=A0=84=ED=99=98=20=EA=B8=B0=EB=8A=A5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/usecase/GetAllImagesUseCase.kt | 10 --- .../albumList/AlbumListFragment.kt | 2 +- .../albumList/AlbumListViewModel.kt | 81 +++++++------------ .../src/main/res/navigation/nav_graph.xml | 5 ++ 4 files changed, 34 insertions(+), 64 deletions(-) delete mode 100644 domain/src/main/java/com/fakedevelopers/domain/usecase/GetAllImagesUseCase.kt diff --git a/domain/src/main/java/com/fakedevelopers/domain/usecase/GetAllImagesUseCase.kt b/domain/src/main/java/com/fakedevelopers/domain/usecase/GetAllImagesUseCase.kt deleted file mode 100644 index 53bdc7e2..00000000 --- a/domain/src/main/java/com/fakedevelopers/domain/usecase/GetAllImagesUseCase.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.fakedevelopers.domain.usecase - -import com.fakedevelopers.domain.repository.ImageRepository -import javax.inject.Inject - -class GetAllImagesUseCase @Inject constructor( - private val repository: ImageRepository -) { - suspend operator fun invoke() = repository.getAllImages() -} diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt index a4f60307..615ade96 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt @@ -124,7 +124,7 @@ class AlbumListFragment : BaseFragment( private fun handleEvent(event: AlbumListViewModel.Event) { when (event) { - is AlbumListViewModel.Event.AlbumList -> viewModel.updateAlbumList(event.albums[0]) + is AlbumListViewModel.Event.AlbumList -> viewModel.updateAlbumList() is AlbumListViewModel.Event.ImageCount -> handleImageCount(event.count) is AlbumListViewModel.Event.OnListChange -> onAlbumChanged(event.state) is AlbumListViewModel.Event.ScrollToTop -> scrollAlbumListToTop() diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt index ac5965de..22259651 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt @@ -1,10 +1,11 @@ package com.fakedevelopers.presentation.ui.productEditor.albumList +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.fakedevelopers.domain.model.AlbumItem -import com.fakedevelopers.domain.usecase.GetAllImagesUseCase import com.fakedevelopers.domain.usecase.GetDateModifiedByUriUseCase +import com.fakedevelopers.domain.usecase.GetImagesUseCase import com.fakedevelopers.domain.usecase.GetValidUrisUseCase import com.fakedevelopers.domain.usecase.IsValidUriUseCase import com.fakedevelopers.presentation.ui.productEditor.SelectedPictureListAdapter @@ -21,10 +22,11 @@ import kotlin.math.roundToInt @HiltViewModel class AlbumListViewModel @Inject constructor( + args: SavedStateHandle, isValidUriUseCase: IsValidUriUseCase, private val getDateModifiedFromUriUseCase: GetDateModifiedByUriUseCase, private val getValidUrisUseCase: GetValidUrisUseCase, - private val getAllImagesUseCase: GetAllImagesUseCase + private val getImagesUseCase: GetImagesUseCase ) : ViewModel() { private val _albumViewMode = MutableStateFlow(AlbumViewState.GRID) val albumViewMode: StateFlow get() = _albumViewMode @@ -37,9 +39,8 @@ class AlbumListViewModel @Inject constructor( private val updatedImageList = hashSetOf() - private var currentAlbum = "" private var totalPictureCount = 0 - private var allImages = mapOf>() + private var allImages = mutableListOf() val selectedImageInfo = SelectedImageInfo() // 현재 뷰 페이저 인덱스 @@ -51,8 +52,8 @@ class AlbumListViewModel @Inject constructor( init { viewModelScope.launch { - allImages = getAllImagesUseCase() - sendEvent(Event.AlbumList(allImages.keys.toList())) + allImages = getImagesUseCase(args.get("albumName")).toMutableList() + sendEvent(Event.AlbumList(allImages)) } } @@ -99,7 +100,7 @@ class AlbumListViewModel @Inject constructor( } fun rotateCurrentImage() { - val uri = getCurrentUri() + val uri = allImages[currentViewPagerIdx].uri // 로테이트된 비트맵이 있으면 그걸 돌림 // 없다면 새로 추가 selectedImageInfo.changeBitmaps[uri]?.let { bitmapInfo -> @@ -123,7 +124,7 @@ class AlbumListViewModel @Inject constructor( fun setCurrentViewPagerIdx(idx: Int) { currentViewPagerIdx = idx - sendEvent(Event.ImageCount(findSelectedImageIndex(getCurrentUri()))) + sendEvent(Event.ImageCount(findSelectedImageIndex(allImages[currentViewPagerIdx].uri))) } fun setAlbumViewMode(state: AlbumViewState) { @@ -161,9 +162,7 @@ class AlbumListViewModel @Inject constructor( // 수정된 내용(BitmapInfo)도 같이 삭제 if (selectedImageInfo.changeBitmaps.remove(uri) != null) { // 페이저에 보이는 이미지 원상 복구 - allImages[currentAlbum]?.let { list -> - albumPagerAdapter.notifyItemChanged(list.indexOfFirst { it.uri == uri }) - } + albumPagerAdapter.notifyItemChanged(allImages.indexOfFirst { it.uri == uri }) } // 첫번째 사진이 삭제 된다면 다음 사진에게 대표직을 물려줌 if (selectedImageInfo.uris.isNotEmpty() && idx == 0) { @@ -186,7 +185,7 @@ class AlbumListViewModel @Inject constructor( } fun scrollToTop() { - if (scrollToTopFlag && albumListAdapter.currentList[0] == allImages[currentAlbum]?.get(0)) { + if (scrollToTopFlag && albumListAdapter.currentList[0] == allImages[0]) { sendEvent(Event.ScrollToTop(true)) scrollToTopFlag = false } @@ -196,11 +195,6 @@ class AlbumListViewModel @Inject constructor( fun getCurrentPositionString(position: Int) = "$position / $totalPictureCount" - private fun getCurrentUri() = allImages[currentAlbum]?.get(currentViewPagerIdx)?.uri ?: "" - - private fun getPictureUri(albumName: String = currentAlbum, position: Int) = - allImages[albumName]?.get(position)?.uri ?: "" - fun onAlbumListUpdated(uri: String) { updatedImageList.add(uri) } @@ -210,25 +204,21 @@ class AlbumListViewModel @Inject constructor( showViewPager(selectedImageInfo.uris.last()) } - fun updateAlbumList(albumName: String? = null) { + fun updateAlbumList() { val updatedAlbumItems = updatedImageList.mapNotNull { getDateModifiedFromUriUseCase(it) } updatedImageList.forEach { uri -> removeImage(uri) } // 앨범 리스트 갱신 updatedAlbumItems.forEach { item -> - val albumItem = AlbumItem(item.uri, item.modified) - allImages[ALL_PICTURES]?.add(albumItem) - allImages[item.path]?.add(albumItem) + allImages.add(AlbumItem(item.uri, item.modified)) } // 수정된 날짜 기준으로 소팅 if (updatedAlbumItems.isNotEmpty()) { - for (key in allImages.keys) { - allImages[key]?.sortByDescending { it.modified } - } + allImages.sortByDescending { it.modified } } updatedImageList.clear() - setAdapterList(albumName ?: currentAlbum) + setAdapterList() } fun checkSelectedImages(idx: Int? = null) { @@ -237,40 +227,29 @@ class AlbumListViewModel @Inject constructor( // 유효한 선택 이미지 리스트로 갱신 setSelectedImage(getValidUrisUseCase(selectedImageInfo.uris)) if (albumViewMode.value == AlbumViewState.PAGER && idx != null) { - sendEvent(Event.ImageCount(findSelectedImageIndex(getPictureUri(position = idx)))) + sendEvent(Event.ImageCount(findSelectedImageIndex(allImages[idx].uri))) } } } private fun removeImage(uri: String) { - val targetImage = allImages[ALL_PICTURES]?.find { it.uri == uri } ?: return - for (key in allImages.keys) { - allImages[key]?.remove(targetImage) - } + val targetImage = allImages.find { it.uri == uri } ?: return + allImages.remove(targetImage) } - private fun setAdapterList(albumName: String = currentAlbum) { - allImages[albumName]?.let { list -> - val currentList = mutableListOf().apply { addAll(list) } - albumListAdapter.submitList(currentList) - albumPagerAdapter.submitList(currentList) - totalPictureCount = list.size - } - if (albumName != currentAlbum) { - currentAlbum = albumName - // 앨범을 바꿀 때 최상위 스크롤을 해주는 플래그를 true로 바꿔준다. - scrollToTopFlag = true - } + private fun setAdapterList() { + val currentList = mutableListOf().apply { addAll(allImages) } + albumListAdapter.submitList(currentList) + albumPagerAdapter.submitList(currentList) + totalPictureCount = allImages.size } // 앨범 뷰 페이저 private fun showViewPager(uri: String) { - allImages[currentAlbum]?.let { album -> - val idx = album.indexOf(album.find { it.uri == uri }) - if (idx != -1) { - sendEvent(Event.StartViewPagerIndex(idx)) - setAlbumViewMode(AlbumViewState.PAGER) - } + val idx = allImages.indexOfFirst { it.uri == uri } + if (idx != -1) { + sendEvent(Event.StartViewPagerIndex(idx)) + setAlbumViewMode(AlbumViewState.PAGER) } } @@ -297,10 +276,6 @@ class AlbumListViewModel @Inject constructor( data class StartViewPagerIndex(val idx: Int) : Event() data class ImageCount(val count: Int) : Event() data class ScrollToTop(val state: Boolean) : Event() - data class AlbumList(val albums: List) : Event() - } - - companion object { - private const val ALL_PICTURES = "전체보기" + data class AlbumList(val albums: List) : Event() } } diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index b5382c53..ded1dd78 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -88,6 +88,11 @@ app:destination="@id/productRegistrationFragment" app:launchSingleTop="true" app:popUpTo="@id/pictureSelectFragment" /> + From 995e8aad7e751b70052429972b08b3f0c0cfdfeb Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 18:33:52 +0900 Subject: [PATCH 07/26] =?UTF-8?q?REFACTOR=20:=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../albumList/AlbumListFragment.kt | 23 +------------------ .../albumList/AlbumListViewModel.kt | 11 --------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt index 615ade96..e2ddeddd 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt @@ -11,9 +11,7 @@ import androidx.activity.OnBackPressedCallback import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import com.fakedevelopers.presentation.R import com.fakedevelopers.presentation.databinding.FragmentAlbumListBinding @@ -63,15 +61,6 @@ class AlbumListFragment : BaseFragment( } } - private val albumLayoutManager by lazy { - object : GridLayoutManager(requireContext(), 3) { - override fun onLayoutCompleted(state: RecyclerView.State?) { - super.onLayoutCompleted(state) - viewModel.scrollToTop() - } - } - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.vm = viewModel @@ -84,10 +73,7 @@ class AlbumListFragment : BaseFragment( true, contentObserver ) - binding.recyclerAlbumList.run { - layoutManager = albumLayoutManager - itemAnimator = null - } + binding.recyclerAlbumList.itemAnimator = null initListener() } @@ -127,7 +113,6 @@ class AlbumListFragment : BaseFragment( is AlbumListViewModel.Event.AlbumList -> viewModel.updateAlbumList() is AlbumListViewModel.Event.ImageCount -> handleImageCount(event.count) is AlbumListViewModel.Event.OnListChange -> onAlbumChanged(event.state) - is AlbumListViewModel.Event.ScrollToTop -> scrollAlbumListToTop() is AlbumListViewModel.Event.SelectErrorImage -> sendSnackBar(getString(R.string.album_selected_error_image)) is AlbumListViewModel.Event.StartViewPagerIndex -> initViewPagerIndex(event.idx) } @@ -154,12 +139,6 @@ class AlbumListFragment : BaseFragment( } } - private fun scrollAlbumListToTop() { - binding.recyclerAlbumList.run { - post { scrollToPosition(0) } - } - } - private fun initViewPagerIndex(idx: Int) { if (viewModel.currentViewPagerIdx == idx) { setPagerUI(idx) diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt index 22259651..77ed3695 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt @@ -47,9 +47,6 @@ class AlbumListViewModel @Inject constructor( var currentViewPagerIdx = 0 private set - // 앨범 전환 시 리스트를 탑으로 올리기 위한 플래그 - private var scrollToTopFlag = false - init { viewModelScope.launch { allImages = getImagesUseCase(args.get("albumName")).toMutableList() @@ -184,13 +181,6 @@ class AlbumListViewModel @Inject constructor( setSelectedImageList() } - fun scrollToTop() { - if (scrollToTopFlag && albumListAdapter.currentList[0] == allImages[0]) { - sendEvent(Event.ScrollToTop(true)) - scrollToTopFlag = false - } - } - private fun findSelectedImageIndex(uri: String) = selectedImageInfo.uris.indexOf(uri) fun getCurrentPositionString(position: Int) = "$position / $totalPictureCount" @@ -275,7 +265,6 @@ class AlbumListViewModel @Inject constructor( data class SelectErrorImage(val state: Boolean) : Event() data class StartViewPagerIndex(val idx: Int) : Event() data class ImageCount(val count: Int) : Event() - data class ScrollToTop(val state: Boolean) : Event() data class AlbumList(val albums: List) : Event() } } From 060caea37ea085c5f2fdcfeb640bed633095cc31 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 20:11:16 +0900 Subject: [PATCH 08/26] =?UTF-8?q?REFACTOR=20:=20contentObserver=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/ImageRepositoryImpl.kt | 26 +++++++++++++++++++ .../domain/repository/ImageRepository.kt | 2 ++ .../domain/usecase/GetImageObserverUseCase.kt | 11 ++++++++ .../albumList/AlbumListFragment.kt | 23 ---------------- .../albumList/AlbumListViewModel.kt | 11 ++++---- 5 files changed, 45 insertions(+), 28 deletions(-) create mode 100644 domain/src/main/java/com/fakedevelopers/domain/usecase/GetImageObserverUseCase.kt diff --git a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt index 9a493053..98609759 100644 --- a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt +++ b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt @@ -2,13 +2,19 @@ package com.fakedevelopers.data.repository import android.content.ContentResolver import android.content.ContentUris +import android.database.ContentObserver import android.net.Uri +import android.os.Handler +import android.os.Looper import android.provider.MediaStore import androidx.exifinterface.media.ExifInterface import com.fakedevelopers.domain.model.AlbumItem import com.fakedevelopers.domain.model.MediaInfo import com.fakedevelopers.domain.repository.ImageRepository import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.withContext import java.util.Locale import javax.inject.Inject @@ -16,6 +22,7 @@ import javax.inject.Inject class ImageRepositoryImpl @Inject constructor( private val contentResolver: ContentResolver ) : ImageRepository { + override fun isValid(uri: String): Boolean { contentResolver.runCatching { openFileDescriptor(Uri.parse(uri), "r")?.use { @@ -54,6 +61,25 @@ class ImageRepositoryImpl @Inject constructor( return images } + override fun getImageObserver(): Flow = callbackFlow { + val contentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { + override fun onChange(selfChange: Boolean, uri: Uri?) { + super.onChange(selfChange, uri) + if (uri != null) { + trySend(uri.toString()) + } + } + } + contentResolver.registerContentObserver( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + true, + contentObserver + ) + awaitClose { + contentResolver.unregisterContentObserver(contentObserver) + } + } + override fun getValidUris(uris: List): List = uris.filter { uri -> isValid(uri) } diff --git a/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt b/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt index 5ec45fab..658f52b1 100644 --- a/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt +++ b/domain/src/main/java/com/fakedevelopers/domain/repository/ImageRepository.kt @@ -4,10 +4,12 @@ import com.fakedevelopers.domain.model.AlbumItem import com.fakedevelopers.domain.model.MediaInfo import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow interface ImageRepository { fun isValid(uri: String): Boolean suspend fun getImages(path: String?): List + fun getImageObserver(): Flow fun getValidUris(uris: List): List fun getDateModifiedByUri(uri: String): AlbumItem? suspend fun getBytesByUri(uri: String, dispatcher: CoroutineDispatcher = Dispatchers.IO): ByteArray? diff --git a/domain/src/main/java/com/fakedevelopers/domain/usecase/GetImageObserverUseCase.kt b/domain/src/main/java/com/fakedevelopers/domain/usecase/GetImageObserverUseCase.kt new file mode 100644 index 00000000..92b10858 --- /dev/null +++ b/domain/src/main/java/com/fakedevelopers/domain/usecase/GetImageObserverUseCase.kt @@ -0,0 +1,11 @@ +package com.fakedevelopers.domain.usecase + +import com.fakedevelopers.domain.repository.ImageRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetImageObserverUseCase @Inject constructor( + private val repository: ImageRepository +) { + operator fun invoke(): Flow = repository.getImageObserver() +} diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt index e2ddeddd..f34d8928 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt @@ -1,11 +1,6 @@ package com.fakedevelopers.presentation.ui.productEditor.albumList -import android.database.ContentObserver -import android.net.Uri import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.provider.MediaStore import android.view.View import androidx.activity.OnBackPressedCallback import androidx.fragment.app.viewModels @@ -49,18 +44,6 @@ class AlbumListFragment : BaseFragment( } } - // 외부 저장소에 변화가 생기면 얘가 호출이 됩니다. - private val contentObserver by lazy { - object : ContentObserver(Handler(Looper.getMainLooper())) { - override fun onChange(selfChange: Boolean, uri: Uri?) { - super.onChange(selfChange, uri) - if (uri != null) { - viewModel.onAlbumListUpdated(uri.toString()) - } - } - } - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.vm = viewModel @@ -68,11 +51,6 @@ class AlbumListFragment : BaseFragment( viewModel.initSelectedImageList(args.selectedImageInfo) binding.buttonAlbumListComplete.visibility = View.VISIBLE } - requireActivity().contentResolver.registerContentObserver( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - true, - contentObserver - ) binding.recyclerAlbumList.itemAnimator = null initListener() } @@ -154,7 +132,6 @@ class AlbumListFragment : BaseFragment( override fun onDestroyView() { binding.viewpagerPictureSelect.unregisterOnPageChangeCallback(onPageChangeCallback) - requireActivity().contentResolver.unregisterContentObserver(contentObserver) backPressedCallback.remove() super.onDestroyView() } diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt index 77ed3695..86bc5774 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.fakedevelopers.domain.model.AlbumItem import com.fakedevelopers.domain.usecase.GetDateModifiedByUriUseCase +import com.fakedevelopers.domain.usecase.GetImageObserverUseCase import com.fakedevelopers.domain.usecase.GetImagesUseCase import com.fakedevelopers.domain.usecase.GetValidUrisUseCase import com.fakedevelopers.domain.usecase.IsValidUriUseCase @@ -26,7 +27,8 @@ class AlbumListViewModel @Inject constructor( isValidUriUseCase: IsValidUriUseCase, private val getDateModifiedFromUriUseCase: GetDateModifiedByUriUseCase, private val getValidUrisUseCase: GetValidUrisUseCase, - private val getImagesUseCase: GetImagesUseCase + private val getImagesUseCase: GetImagesUseCase, + private val getImageObserverUseCase: GetImageObserverUseCase ) : ViewModel() { private val _albumViewMode = MutableStateFlow(AlbumViewState.GRID) val albumViewMode: StateFlow get() = _albumViewMode @@ -51,6 +53,9 @@ class AlbumListViewModel @Inject constructor( viewModelScope.launch { allImages = getImagesUseCase(args.get("albumName")).toMutableList() sendEvent(Event.AlbumList(allImages)) + getImageObserverUseCase().collect { uri -> + updatedImageList.add(uri) + } } } @@ -185,10 +190,6 @@ class AlbumListViewModel @Inject constructor( fun getCurrentPositionString(position: Int) = "$position / $totalPictureCount" - fun onAlbumListUpdated(uri: String) { - updatedImageList.add(uri) - } - // 편집 버튼 클릭 fun onEditButtonClick() { showViewPager(selectedImageInfo.uris.last()) From c6342fcc80b3c1189199190d34afff5de25e701a Mon Sep 17 00:00:00 2001 From: minseonglove Date: Thu, 9 Feb 2023 21:22:34 +0900 Subject: [PATCH 09/26] =?UTF-8?q?FEAT=20:=20=EC=95=A8=EB=B2=94=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=ED=99=94=EB=A9=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../albumSelect/AlbumSelectAdapter.kt | 6 +-- .../albumSelect/AlbumSelectFragment.kt | 45 ++++++++++++++++ .../albumSelect/AlbumSelectViewModel.kt | 52 +++++++++++++++++++ .../main/res/layout/fragment_album_select.xml | 2 + .../src/main/res/navigation/nav_graph.xml | 14 +++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt create mode 100644 presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt index 62be1f17..f919e19f 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectAdapter.kt @@ -11,17 +11,17 @@ import com.fakedevelopers.presentation.databinding.RecyclerAlbumSelectBinding import com.fakedevelopers.presentation.model.AlbumInfo class AlbumSelectAdapter( - private val onClick: () -> Unit + private val onClick: (String) -> Unit ) : ListAdapter(diffUtil) { class ViewHolder( private val binding: RecyclerAlbumSelectBinding, - private val onClick: () -> Unit + private val onClick: (String) -> Unit ) : RecyclerView.ViewHolder(binding.root) { fun bind(item: AlbumInfo) { binding.albumInfo = item binding.root.setOnClickListener { - onClick() + onClick(item.path) } } } diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt new file mode 100644 index 00000000..cf321622 --- /dev/null +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt @@ -0,0 +1,45 @@ +package com.fakedevelopers.presentation.ui.productEditor.albumSelect + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import com.fakedevelopers.presentation.R +import com.fakedevelopers.presentation.databinding.FragmentAlbumSelectBinding +import com.fakedevelopers.presentation.ui.base.BaseFragment +import com.fakedevelopers.presentation.ui.util.repeatOnStarted +import kotlinx.coroutines.flow.collectLatest + +class AlbumSelectFragment : BaseFragment( + R.layout.fragment_album_select +) { + + private val viewModel: AlbumSelectViewModel by viewModels() + private val args: AlbumSelectFragmentArgs by navArgs() + + private val adapter: AlbumSelectAdapter by lazy { + AlbumSelectAdapter { path -> + findNavController().navigate( + AlbumSelectFragmentDirections.actionAlbumSelectFragmentToPictureSelectFragment( + albumName = path, + selectedImageInfo = args.selectedImageInfo + ) + ) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initCollector() + binding.recyclerAlbumSelect.adapter = adapter + } + + private fun initCollector() { + repeatOnStarted(viewLifecycleOwner) { + viewModel.albumInfoEvent.collectLatest { + adapter.submitList(it) + } + } + } +} diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt new file mode 100644 index 00000000..4534c26b --- /dev/null +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt @@ -0,0 +1,52 @@ +package com.fakedevelopers.presentation.ui.productEditor.albumSelect + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.fakedevelopers.domain.model.AlbumItem +import com.fakedevelopers.domain.usecase.GetImagesUseCase +import com.fakedevelopers.presentation.model.AlbumInfo +import com.fakedevelopers.presentation.ui.util.MutableEventFlow +import com.fakedevelopers.presentation.ui.util.asEventFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +class AlbumSelectViewModel @Inject constructor( + private val getImagesUseCase: GetImagesUseCase +) : ViewModel() { + + private val _albumInfoEvent = MutableEventFlow>() + val albumInfoEvent = _albumInfoEvent.asEventFlow() + + init { + viewModelScope.launch { + initAlbumInfo(getImagesUseCase()) + } + } + + private suspend fun initAlbumInfo(albumItems: List) { + val albumInfo = mutableListOf() + albumInfo.add( + AlbumInfo( + path = "", + firstImage = albumItems[0].uri, + name = "최근 항목", + count = albumItems.size + ) + ) + val countMap = mutableMapOf() + albumItems.forEach { albumItem -> + countMap[albumItem.path] = (countMap[albumItem.path] ?: 0) + 1 + } + countMap.keys.forEach { path -> + albumInfo.add( + AlbumInfo( + path = path, + firstImage = albumItems.find { it.path == path }?.uri ?: "", + name = path.substringAfterLast('/'), + count = countMap[path] ?: 0 + ) + ) + } + _albumInfoEvent.emit(albumInfo) + } +} diff --git a/presentation/src/main/res/layout/fragment_album_select.xml b/presentation/src/main/res/layout/fragment_album_select.xml index 0dd364e6..0cf9cebc 100644 --- a/presentation/src/main/res/layout/fragment_album_select.xml +++ b/presentation/src/main/res/layout/fragment_album_select.xml @@ -7,11 +7,13 @@ android:layout_height="match_parent"> diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index ded1dd78..221e1fbb 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -96,6 +96,9 @@ + + + + + From 879faa2e0cf2ebad548f8e184280cc7100934f6f Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 00:54:42 +0900 Subject: [PATCH 10/26] =?UTF-8?q?FIX=20:=20getImages=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=EC=97=90=EC=84=9C=20AlbumItem=EC=9D=84=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=A0=20=EB=95=8C=20path=20=ED=95=84=EB=93=9C?= =?UTF-8?q?=EB=A5=BC=20=EB=B9=BC=EB=A8=B9=EC=9D=80=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fakedevelopers/data/repository/ImageRepositoryImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt index 98609759..035755c9 100644 --- a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt +++ b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt @@ -55,7 +55,8 @@ class ImageRepositoryImpl @Inject constructor( ).toString() // 최근 수정 날짜 val date = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED)) - images.add(AlbumItem(imageUri, date)) + val realPath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)) + images.add(AlbumItem(imageUri, date, realPath)) } } return images From f223e927ccd9bef56abcd08a3b951a8383acd9df Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 00:57:39 +0900 Subject: [PATCH 11/26] =?UTF-8?q?FIX=20:=20getImages=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=EC=97=90=EC=84=9C=20path=EA=B0=80=20empty=EC=9D=BC?= =?UTF-8?q?=EB=95=8C=EB=8F=84=20=EB=AA=A8=EB=93=A0=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fakedevelopers/data/repository/ImageRepositoryImpl.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt index 035755c9..1bec1480 100644 --- a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt +++ b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt @@ -34,7 +34,11 @@ class ImageRepositoryImpl @Inject constructor( override suspend fun getImages(path: String?): List { val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI - val where = path?.let { MediaStore.Images.Media.DATA + it } + val where = if (path.isNullOrEmpty().not()) { + MediaStore.Images.Media.DATA + path + } else { + null + } val images = mutableListOf() contentResolver.query( uri, From 0a3a309a11b84ee907013dce0c5f07d6a837c027 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 01:03:04 +0900 Subject: [PATCH 12/26] =?UTF-8?q?FIX=20:=20where=EC=A0=88=EC=9D=84=20?= =?UTF-8?q?=EB=8B=A8=EB=94=94=20=EC=95=88=EC=A0=81=EC=9D=80=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fakedevelopers/data/repository/ImageRepositoryImpl.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt index 1bec1480..5244be88 100644 --- a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt +++ b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt @@ -11,6 +11,7 @@ import androidx.exifinterface.media.ExifInterface import com.fakedevelopers.domain.model.AlbumItem import com.fakedevelopers.domain.model.MediaInfo import com.fakedevelopers.domain.repository.ImageRepository +import com.orhanobut.logger.Logger import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -35,10 +36,11 @@ class ImageRepositoryImpl @Inject constructor( override suspend fun getImages(path: String?): List { val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val where = if (path.isNullOrEmpty().not()) { - MediaStore.Images.Media.DATA + path + MediaStore.Images.Media.DATA + " LIKE '%$path%'" } else { null } + Logger.t("albumtest").i(where.toString()) val images = mutableListOf() contentResolver.query( uri, From 937067d6a71c15cdaf13303dee2495354a8fb45f Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 01:08:06 +0900 Subject: [PATCH 13/26] =?UTF-8?q?FIX=20:=20albumName=20argument=EC=9D=98?= =?UTF-8?q?=20nullable=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- presentation/src/main/res/navigation/nav_graph.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index 221e1fbb..e04a6bf3 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -89,10 +89,9 @@ app:launchSingleTop="true" app:popUpTo="@id/pictureSelectFragment" /> + android:defaultValue="" /> From 8d33c94efedfa9a7161ab3affaaf8f0523896e69 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 01:15:21 +0900 Subject: [PATCH 14/26] =?UTF-8?q?FEAT=20:=20=EC=95=A8=EB=B2=94=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=ED=99=94=EB=A9=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../albumList/AlbumListFragment.kt | 17 +++++++++++++++++ .../albumList/AlbumListViewModel.kt | 7 ++++++- .../albumSelect/AlbumSelectFragment.kt | 6 ++++-- .../albumSelect/AlbumSelectViewModel.kt | 15 +++++++++------ .../src/main/res/layout/fragment_album_list.xml | 10 ++++++++++ .../main/res/layout/recycler_album_select.xml | 2 +- presentation/src/main/res/values/strings.xml | 1 + 7 files changed, 48 insertions(+), 10 deletions(-) diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt index f34d8928..dd45db12 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt @@ -14,6 +14,7 @@ import com.fakedevelopers.presentation.ui.base.BaseFragment import com.fakedevelopers.presentation.ui.productEditor.DragAndDropCallback import com.fakedevelopers.presentation.ui.util.repeatOnStarted import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.collectLatest @AndroidEntryPoint class AlbumListFragment : BaseFragment( @@ -53,6 +54,7 @@ class AlbumListFragment : BaseFragment( } binding.recyclerAlbumList.itemAnimator = null initListener() + initCollector() } override fun onStart() { @@ -76,14 +78,29 @@ class AlbumListFragment : BaseFragment( binding.buttonAlbumListComplete.setOnClickListener { toProductRegistration(args.selectedImageInfo) } + binding.textviewAlbumListTitle.setOnClickListener { + findNavController().navigate( + AlbumListFragmentDirections.actionPictureSelectFragmentToAlbumSelectFragment(viewModel.selectedImageInfo) + ) + } binding.viewpagerPictureSelect.registerOnPageChangeCallback(onPageChangeCallback) ItemTouchHelper(DragAndDropCallback(viewModel.selectedPictureAdapter)) .attachToRecyclerView(binding.recyclerSelectedPicture) + } + + private fun initCollector() { repeatOnStarted(viewLifecycleOwner) { viewModel.event.collect { event -> handleEvent(event) } } + repeatOnStarted(viewLifecycleOwner) { + viewModel.albumTitle.collectLatest { title -> + binding.textviewAlbumListTitle.text = title.ifEmpty { + getString(R.string.album_select_recent_images) + } + } + } } private fun handleEvent(event: AlbumListViewModel.Event) { diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt index 86bc5774..f88c26ba 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt @@ -39,6 +39,9 @@ class AlbumListViewModel @Inject constructor( private val _editButtonEnableState = MutableStateFlow(false) val editButtonEnableState: StateFlow get() = _editButtonEnableState + private val _albumTitle = MutableStateFlow("") + val albumTitle: StateFlow get() = _albumTitle + private val updatedImageList = hashSetOf() private var totalPictureCount = 0 @@ -51,7 +54,9 @@ class AlbumListViewModel @Inject constructor( init { viewModelScope.launch { - allImages = getImagesUseCase(args.get("albumName")).toMutableList() + val path = args.get("albumPath") ?: "" + _albumTitle.emit(path.substringAfterLast('/')) + allImages = getImagesUseCase(path).toMutableList() sendEvent(Event.AlbumList(allImages)) getImageObserverUseCase().collect { uri -> updatedImageList.add(uri) diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt index cf321622..f67ac58b 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectFragment.kt @@ -9,8 +9,10 @@ import com.fakedevelopers.presentation.R import com.fakedevelopers.presentation.databinding.FragmentAlbumSelectBinding import com.fakedevelopers.presentation.ui.base.BaseFragment import com.fakedevelopers.presentation.ui.util.repeatOnStarted +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest +@AndroidEntryPoint class AlbumSelectFragment : BaseFragment( R.layout.fragment_album_select ) { @@ -22,7 +24,7 @@ class AlbumSelectFragment : BaseFragment( AlbumSelectAdapter { path -> findNavController().navigate( AlbumSelectFragmentDirections.actionAlbumSelectFragmentToPictureSelectFragment( - albumName = path, + albumPath = path, selectedImageInfo = args.selectedImageInfo ) ) @@ -31,8 +33,8 @@ class AlbumSelectFragment : BaseFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initCollector() binding.recyclerAlbumSelect.adapter = adapter + initCollector() } private fun initCollector() { diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt index 4534c26b..723e18e0 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumSelect/AlbumSelectViewModel.kt @@ -7,9 +7,11 @@ import com.fakedevelopers.domain.usecase.GetImagesUseCase import com.fakedevelopers.presentation.model.AlbumInfo import com.fakedevelopers.presentation.ui.util.MutableEventFlow import com.fakedevelopers.presentation.ui.util.asEventFlow +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject +@HiltViewModel class AlbumSelectViewModel @Inject constructor( private val getImagesUseCase: GetImagesUseCase ) : ViewModel() { @@ -35,15 +37,16 @@ class AlbumSelectViewModel @Inject constructor( ) val countMap = mutableMapOf() albumItems.forEach { albumItem -> - countMap[albumItem.path] = (countMap[albumItem.path] ?: 0) + 1 + val relPath = albumItem.path.substringBeforeLast('/') + countMap[relPath] = (countMap[relPath] ?: 0) + 1 } - countMap.keys.forEach { path -> + countMap.keys.forEach { relPath -> albumInfo.add( AlbumInfo( - path = path, - firstImage = albumItems.find { it.path == path }?.uri ?: "", - name = path.substringAfterLast('/'), - count = countMap[path] ?: 0 + path = relPath, + firstImage = albumItems.find { it.path.contains(relPath) }?.uri ?: "", + name = relPath.substringAfterLast('/'), + count = countMap[relPath] ?: 0 ) ) } diff --git a/presentation/src/main/res/layout/fragment_album_list.xml b/presentation/src/main/res/layout/fragment_album_list.xml index 88d46135..447e518b 100644 --- a/presentation/src/main/res/layout/fragment_album_list.xml +++ b/presentation/src/main/res/layout/fragment_album_list.xml @@ -35,6 +35,16 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> + + 내 물건 등록 완료 + 최근 항목 불러올 수 없는 이미지 입니다. From ec31794933773b57f47c5752765a4d5db3d75500 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 12:23:27 +0900 Subject: [PATCH 15/26] =?UTF-8?q?FEAT=20:=20AlbumSelect=20<->=20PictureSel?= =?UTF-8?q?ect=20=ED=99=94=EB=A9=B4=20=EC=A0=84=ED=99=98=20=EC=8B=9C=20?= =?UTF-8?q?=EB=B0=B1=EC=8A=A4=ED=83=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- presentation/src/main/res/navigation/nav_graph.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index e04a6bf3..a93b715b 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -97,7 +97,9 @@ app:argType="com.fakedevelopers.presentation.ui.productEditor.albumList.SelectedImageInfo" /> + app:destination="@id/albumSelectFragment" + app:popUpTo="@id/pictureSelectFragment" + app:popUpToInclusive="true" /> + app:destination="@id/pictureSelectFragment" + app:popUpTo="@id/albumSelectFragment" + app:popUpToInclusive="true" /> From daf26f89475253860e0fdb001394dc3aed3747ec Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 17:31:33 +0900 Subject: [PATCH 16/26] =?UTF-8?q?CHORE=20:=20Logger=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fakedevelopers/data/repository/ImageRepositoryImpl.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt index 5244be88..3cda6023 100644 --- a/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt +++ b/data/src/main/java/com/fakedevelopers/data/repository/ImageRepositoryImpl.kt @@ -11,7 +11,6 @@ import androidx.exifinterface.media.ExifInterface import com.fakedevelopers.domain.model.AlbumItem import com.fakedevelopers.domain.model.MediaInfo import com.fakedevelopers.domain.repository.ImageRepository -import com.orhanobut.logger.Logger import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -40,7 +39,6 @@ class ImageRepositoryImpl @Inject constructor( } else { null } - Logger.t("albumtest").i(where.toString()) val images = mutableListOf() contentResolver.query( uri, From 6e59bf372d48b75007b4f7c8601875950f0d03f6 Mon Sep 17 00:00:00 2001 From: minseonglove Date: Fri, 10 Feb 2023 17:55:06 +0900 Subject: [PATCH 17/26] =?UTF-8?q?FEAT=20:=20=EC=82=AC=EC=A7=84=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=ED=99=94=EB=A9=B4=20=ED=88=B4=EB=B0=94=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../albumList/AlbumListFragment.kt | 57 +++++++------- .../albumList/AlbumListViewModel.kt | 38 +++++----- .../main/res/layout/fragment_album_list.xml | 45 ++--------- .../src/main/res/layout/toolbar_album.xml | 74 +++++++++++++++++++ 4 files changed, 131 insertions(+), 83 deletions(-) create mode 100644 presentation/src/main/res/layout/toolbar_album.xml diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt index dd45db12..6882081a 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListFragment.kt @@ -3,6 +3,8 @@ package com.fakedevelopers.presentation.ui.productEditor.albumList import android.os.Bundle import android.view.View import androidx.activity.OnBackPressedCallback +import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -31,7 +33,7 @@ class AlbumListFragment : BaseFragment( if (viewModel.albumViewMode.value == AlbumViewState.PAGER) { viewModel.setAlbumViewMode(AlbumViewState.GRID) } else { - toProductRegistration(args.selectedImageInfo) + findNavController().popBackStack() } } } @@ -40,7 +42,7 @@ class AlbumListFragment : BaseFragment( object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) - setPagerUI(position) + viewModel.setCurrentViewPagerIdx(position) } } } @@ -50,7 +52,7 @@ class AlbumListFragment : BaseFragment( binding.vm = viewModel if (args.selectedImageInfo.uris.isNotEmpty()) { viewModel.initSelectedImageList(args.selectedImageInfo) - binding.buttonAlbumListComplete.visibility = View.VISIBLE + setCompleteTextVisibility(args.selectedImageInfo.uris.size) } binding.recyclerAlbumList.itemAnimator = null initListener() @@ -75,13 +77,20 @@ class AlbumListFragment : BaseFragment( } private fun initListener() { - binding.buttonAlbumListComplete.setOnClickListener { - toProductRegistration(args.selectedImageInfo) - } - binding.textviewAlbumListTitle.setOnClickListener { - findNavController().navigate( - AlbumListFragmentDirections.actionPictureSelectFragmentToAlbumSelectFragment(viewModel.selectedImageInfo) - ) + binding.toolbarAlbumList.run { + textviewAlbumComplete.setOnClickListener { + if (viewModel.albumViewMode.value == AlbumViewState.GRID) { + toProductRegistration(args.selectedImageInfo) + } + } + textviewAlbumTitle.setOnClickListener { + findNavController().navigate( + AlbumListFragmentDirections.actionPictureSelectFragmentToAlbumSelectFragment(viewModel.selectedImageInfo) + ) + } + buttonAlbumClose.setOnClickListener { + findNavController().popBackStack() + } } binding.viewpagerPictureSelect.registerOnPageChangeCallback(onPageChangeCallback) ItemTouchHelper(DragAndDropCallback(viewModel.selectedPictureAdapter)) @@ -96,7 +105,7 @@ class AlbumListFragment : BaseFragment( } repeatOnStarted(viewLifecycleOwner) { viewModel.albumTitle.collectLatest { title -> - binding.textviewAlbumListTitle.text = title.ifEmpty { + binding.toolbarAlbumList.textviewAlbumTitle.text = title.ifEmpty { getString(R.string.album_select_recent_images) } } @@ -107,7 +116,7 @@ class AlbumListFragment : BaseFragment( when (event) { is AlbumListViewModel.Event.AlbumList -> viewModel.updateAlbumList() is AlbumListViewModel.Event.ImageCount -> handleImageCount(event.count) - is AlbumListViewModel.Event.OnListChange -> onAlbumChanged(event.state) + is AlbumListViewModel.Event.OnListChange -> setCompleteTextVisibility(event.count) is AlbumListViewModel.Event.SelectErrorImage -> sendSnackBar(getString(R.string.album_selected_error_image)) is AlbumListViewModel.Event.StartViewPagerIndex -> initViewPagerIndex(event.idx) } @@ -125,28 +134,24 @@ class AlbumListFragment : BaseFragment( } } - private fun onAlbumChanged(state: Boolean) { - binding.buttonAlbumListComplete.visibility = - if (state) { - View.INVISIBLE - } else { - View.VISIBLE - } + private fun setCompleteTextVisibility(count: Int) { + val state = count != 0 + val colorId = if (state) R.color.black else R.color.gray_80 + binding.toolbarAlbumList.run { + textviewAlbumCount.isVisible = state + textviewAlbumCount.text = count.toString() + textviewAlbumComplete.isEnabled = state + textviewAlbumComplete.setTextColor(ContextCompat.getColor(requireContext(), colorId)) + } } private fun initViewPagerIndex(idx: Int) { if (viewModel.currentViewPagerIdx == idx) { - setPagerUI(idx) + viewModel.setCurrentViewPagerIdx(idx) } binding.viewpagerPictureSelect.setCurrentItem(idx, false) } - private fun setPagerUI(position: Int) { - // 사진 편집 대상을 알기 위해 현재 보고 있는 이미지의 인덱스 저장 - viewModel.setCurrentViewPagerIdx(position) - binding.textviewAlbumListIndex.text = viewModel.getCurrentPositionString(position + 1) - } - override fun onDestroyView() { binding.viewpagerPictureSelect.unregisterOnPageChangeCallback(onPageChangeCallback) backPressedCallback.remove() diff --git a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt index f88c26ba..b92dfdda 100644 --- a/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt +++ b/presentation/src/main/java/com/fakedevelopers/presentation/ui/productEditor/albumList/AlbumListViewModel.kt @@ -44,7 +44,6 @@ class AlbumListViewModel @Inject constructor( private val updatedImageList = hashSetOf() - private var totalPictureCount = 0 private var allImages = mutableListOf() val selectedImageInfo = SelectedImageInfo() @@ -52,10 +51,12 @@ class AlbumListViewModel @Inject constructor( var currentViewPagerIdx = 0 private set + private val path = args.get("albumPath") ?: "" + val title = path.substringAfterLast('/') + init { viewModelScope.launch { - val path = args.get("albumPath") ?: "" - _albumTitle.emit(path.substringAfterLast('/')) + _albumTitle.emit(title) allImages = getImagesUseCase(path).toMutableList() sendEvent(Event.AlbumList(allImages)) getImageObserverUseCase().collect { uri -> @@ -67,7 +68,7 @@ class AlbumListViewModel @Inject constructor( // 그리드 앨범 리스트 어뎁터 val albumListAdapter = AlbumListAdapter( isValidUri = { uri -> isValidUriUseCase(uri) }, - findSelectedImageIndex = { findSelectedImageIndex(it) }, + findSelectedImageIndex = { selectedImageInfo.uris.indexOf(it) }, sendErrorToast = { sendEvent(Event.SelectErrorImage(true)) }, showViewPager = { uri -> showViewPager(uri) } ) { uri, state -> @@ -80,7 +81,7 @@ class AlbumListViewModel @Inject constructor( sendErrorToast = { sendEvent(Event.SelectErrorImage(true)) }, getEditedImage = { uri -> selectedImageInfo.changeBitmaps[uri] } ) { uri -> - setSelectedState(uri, findSelectedImageIndex(uri) == -1) + setSelectedState(uri, selectedImageInfo.uris.indexOf(uri) == -1) } // 선택 사진 리스트 어뎁터 @@ -89,7 +90,7 @@ class AlbumListViewModel @Inject constructor( setSelectedState(it) albumListAdapter.refreshSelectedOrder() }, - findSelectedImageIndex = { findSelectedImageIndex(it) }, + findSelectedImageIndex = { selectedImageInfo.uris.indexOf(it) }, swapSelectedImage = { fromPosition, toPosition -> swapSelectedImage(fromPosition, toPosition) } ) @@ -123,7 +124,7 @@ class AlbumListViewModel @Inject constructor( // 수정된 이미지 비트맵 추가 private fun addEditedBitmapInfo(uri: String) { - if (findSelectedImageIndex(uri) == -1) { + if (selectedImageInfo.uris.indexOf(uri) == -1) { setSelectedState(uri, true) } selectedImageInfo.changeBitmaps[uri] = BitmapInfo(ROTATE_DEGREE) @@ -131,13 +132,19 @@ class AlbumListViewModel @Inject constructor( fun setCurrentViewPagerIdx(idx: Int) { currentViewPagerIdx = idx - sendEvent(Event.ImageCount(findSelectedImageIndex(allImages[currentViewPagerIdx].uri))) + sendEvent(Event.ImageCount(selectedImageInfo.uris.indexOf(allImages[currentViewPagerIdx].uri))) + viewModelScope.launch { + _albumTitle.emit("${idx + 1} / ${allImages.size}") + } } fun setAlbumViewMode(state: AlbumViewState) { // 보기 모드를 전환하기 전에 변경 사항을 반영해준다 if (state == AlbumViewState.GRID) { albumListAdapter.refreshAll() + viewModelScope.launch { + _albumTitle.emit(title) + } } viewModelScope.launch { _albumViewMode.emit(state) @@ -152,7 +159,7 @@ class AlbumListViewModel @Inject constructor( viewModelScope.launch { selectedPictureAdapter.submitList(list.toMutableList()) if (list.isNotEmpty() && !list.contains(selectedImageInfo.uris[0])) { - selectedPictureAdapter.notifyItemChanged(findSelectedImageIndex(list[0])) + selectedPictureAdapter.notifyItemChanged(selectedImageInfo.uris.indexOf(list[0])) } setAdapterList() } @@ -164,7 +171,7 @@ class AlbumListViewModel @Inject constructor( if (state) { selectedImageInfo.uris.add(uri) } else { - val idx = findSelectedImageIndex(uri) + val idx = selectedImageInfo.uris.indexOf(uri) selectedImageInfo.uris.removeAt(idx) // 수정된 내용(BitmapInfo)도 같이 삭제 if (selectedImageInfo.changeBitmaps.remove(uri) != null) { @@ -191,10 +198,6 @@ class AlbumListViewModel @Inject constructor( setSelectedImageList() } - private fun findSelectedImageIndex(uri: String) = selectedImageInfo.uris.indexOf(uri) - - fun getCurrentPositionString(position: Int) = "$position / $totalPictureCount" - // 편집 버튼 클릭 fun onEditButtonClick() { showViewPager(selectedImageInfo.uris.last()) @@ -223,7 +226,7 @@ class AlbumListViewModel @Inject constructor( // 유효한 선택 이미지 리스트로 갱신 setSelectedImage(getValidUrisUseCase(selectedImageInfo.uris)) if (albumViewMode.value == AlbumViewState.PAGER && idx != null) { - sendEvent(Event.ImageCount(findSelectedImageIndex(allImages[idx].uri))) + sendEvent(Event.ImageCount(selectedImageInfo.uris.indexOf(allImages[idx].uri))) } } } @@ -237,7 +240,6 @@ class AlbumListViewModel @Inject constructor( val currentList = mutableListOf().apply { addAll(allImages) } albumListAdapter.submitList(currentList) albumPagerAdapter.submitList(currentList) - totalPictureCount = allImages.size } // 앨범 뷰 페이저 @@ -251,7 +253,7 @@ class AlbumListViewModel @Inject constructor( private fun setSelectedImageList() { selectedPictureAdapter.submitList(selectedImageInfo.uris.toMutableList()) - sendEvent(Event.OnListChange(selectedImageInfo.uris.isEmpty())) + sendEvent(Event.OnListChange(selectedImageInfo.uris.size)) } private fun swapSelectedImage(fromPosition: Int, toPosition: Int) { @@ -267,7 +269,7 @@ class AlbumListViewModel @Inject constructor( } sealed class Event { - data class OnListChange(val state: Boolean) : Event() + data class OnListChange(val count: Int) : Event() data class SelectErrorImage(val state: Boolean) : Event() data class StartViewPagerIndex(val idx: Int) : Event() data class ImageCount(val count: Int) : Event() diff --git a/presentation/src/main/res/layout/fragment_album_list.xml b/presentation/src/main/res/layout/fragment_album_list.xml index 447e518b..dcbec44f 100644 --- a/presentation/src/main/res/layout/fragment_album_list.xml +++ b/presentation/src/main/res/layout/fragment_album_list.xml @@ -15,47 +15,14 @@ android:layout_height="match_parent" android:orientation="vertical"> - - -