diff --git a/app/build.gradle b/app/build.gradle index 6ea4a7eb..d4cce3c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,7 +26,7 @@ android { applicationId "com.hyeeyoung.wishboard" minSdkVersion 22 targetSdkVersion 32 - versionCode 13 + versionCode 14 versionName "1.1.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/hyeeyoung/wishboard/data/model/noti/NotiItem.kt b/app/src/main/java/com/hyeeyoung/wishboard/data/model/noti/NotiItem.kt index 7d9adc21..2efa618a 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/data/model/noti/NotiItem.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/data/model/noti/NotiItem.kt @@ -1,6 +1,7 @@ package com.hyeeyoung.wishboard.data.model.noti import com.google.gson.annotations.SerializedName +import com.hyeeyoung.wishboard.domain.entity.NotiItemInfo import com.hyeeyoung.wishboard.presentation.noti.types.NotiType data class NotiItem( @@ -19,4 +20,14 @@ data class NotiItem( val notiType: NotiType, @SerializedName("item_notification_date") val notiDate: String, -) \ No newline at end of file +) { + fun toNotiItemInfo(noti: NotiItem) = NotiItemInfo( + noti.itemId, + noti.itemImg, + noti.itemName, + if (noti.itemUrl.isNullOrBlank()) null else noti.itemUrl, + noti.readState, + noti.notiType, + notiDate, + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/domain/entity/NotiItemInfo.kt b/app/src/main/java/com/hyeeyoung/wishboard/domain/entity/NotiItemInfo.kt new file mode 100644 index 00000000..3d442cbc --- /dev/null +++ b/app/src/main/java/com/hyeeyoung/wishboard/domain/entity/NotiItemInfo.kt @@ -0,0 +1,17 @@ +package com.hyeeyoung.wishboard.domain.entity + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import com.hyeeyoung.wishboard.presentation.noti.types.NotiType +import kotlinx.parcelize.Parcelize + +@Parcelize +data class NotiItemInfo( // TODO 네이밍 수정 필요 + val itemId: Long, + val itemImg: String? = null, + val itemName: String, + val itemUrl: String? = null, + var readState: Int, + val notiType: NotiType, + val notiDate: String, +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/NotiViewModel.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/NotiViewModel.kt index b569404f..9c802c6e 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/NotiViewModel.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/NotiViewModel.kt @@ -5,15 +5,12 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.hyeeyoung.wishboard.WishBoardApp -import com.hyeeyoung.wishboard.data.model.noti.NotiItem -import com.hyeeyoung.wishboard.data.services.AWSS3Service +import com.hyeeyoung.wishboard.domain.entity.NotiItemInfo import com.hyeeyoung.wishboard.domain.repositories.NotiRepository import com.hyeeyoung.wishboard.presentation.noti.adapters.NotiListAdapter import com.hyeeyoung.wishboard.presentation.noti.types.NotiListViewType import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.joda.time.DateTime import java.util.* import javax.inject.Inject @@ -24,8 +21,8 @@ class NotiViewModel @Inject constructor( ) : ViewModel() { private val token = WishBoardApp.prefs.getUserToken() - private var notiList = MutableLiveData?>(listOf()) - private var selectedNotiList = MutableLiveData?>(listOf()) + private var notiList = MutableLiveData?>(listOf()) + private var selectedNotiList = MutableLiveData?>(listOf()) private var notiDateList = MutableLiveData?>(listOf()) private val notiListAdapter = NotiListAdapter(NotiListViewType.NOTI_TAB_VIEW_TYPE) private val calendarNotiListAdapter = NotiListAdapter(NotiListViewType.CALENDAR_VIEW_TYPE) @@ -39,36 +36,18 @@ class NotiViewModel @Inject constructor( fun fetchPreviousNotiList() { if (token == null) return viewModelScope.launch { - var items: List? - withContext(Dispatchers.IO) { - items = notiRepository.fetchPreviousNotiList(token) - items?.forEach { item -> - item.itemImg?.let { item.itemImageUrl = AWSS3Service().getImageUrl(it) } - } - } - withContext(Dispatchers.Main) { - notiList.postValue(items) - notiListAdapter.setData(items) - } + val items = notiRepository.fetchPreviousNotiList(token)?.map { it.toNotiItemInfo(it) } + notiList.value = items + notiListAdapter.setData(items) } } fun fetchAllNotiList() { if (token == null) return viewModelScope.launch { - var items: List? - withContext(Dispatchers.IO) { - items = notiRepository.fetchAllNotiList(token) - items?.forEach { item -> - item.itemImg?.let { item.itemImageUrl = AWSS3Service().getImageUrl(it) } - } - } - withContext(Dispatchers.Main) { - notiList.postValue(items) - - // 캘린더 뷰 알림 날짜 표시를 위한 notiDateList 만들기 - setNotiDateList(items) - } + val items = notiRepository.fetchAllNotiList(token)?.map { it.toNotiItemInfo(it) } + notiList.value = items + setNotiDateList(items) // 캘린더 뷰 알림 날짜 표시를 위한 notiDateList 만들기 } } @@ -89,7 +68,7 @@ class NotiViewModel @Inject constructor( calendarNotiListAdapter.setData(items) } - private fun setNotiDateList(notiList: List?) { + private fun setNotiDateList(notiList: List?) { notiDateList.value = notiList?.map { it.notiDate.substring(0, 10) } @@ -100,15 +79,11 @@ class NotiViewModel @Inject constructor( calendarMonthTitle.value = DateTime(millis).toString("MMMM yyyy", Locale("en")) } - fun getNotiList(): LiveData?> = notiList - fun getSelectedNotiList(): LiveData?> = selectedNotiList + fun getNotiList(): LiveData?> = notiList + fun getSelectedNotiList(): LiveData?> = selectedNotiList fun getNotiDateList(): LiveData?> = notiDateList fun getNotiListAdapter(): NotiListAdapter = notiListAdapter fun getCalendarNotiListAdapter(): NotiListAdapter = calendarNotiListAdapter fun getCalendarMonthTitle(): LiveData = calendarMonthTitle fun getSelectedDate(): LiveData = selectedDate - - companion object { - private const val TAG = "NotiViewModel" - } } \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/adapters/NotiListAdapter.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/adapters/NotiListAdapter.kt index e05999a2..cf9c0bce 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/adapters/NotiListAdapter.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/adapters/NotiListAdapter.kt @@ -5,18 +5,16 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import coil.load -import com.bumptech.glide.Glide -import com.hyeeyoung.wishboard.data.model.noti.NotiItem import com.hyeeyoung.wishboard.databinding.ItemCalendarNotiBinding import com.hyeeyoung.wishboard.databinding.ItemNotiBinding +import com.hyeeyoung.wishboard.domain.entity.NotiItemInfo import com.hyeeyoung.wishboard.presentation.noti.types.NotiListViewType import com.hyeeyoung.wishboard.presentation.noti.types.ReadStateType class NotiListAdapter( private val notiListViewType: NotiListViewType, -) : ListAdapter(diffCallback) { - private val dataSet = arrayListOf() +) : ListAdapter(diffCallback) { + private val dataSet = arrayListOf() private lateinit var listener: OnItemClickListener init { @@ -24,7 +22,7 @@ class NotiListAdapter( } interface OnItemClickListener { - fun onItemClick(position: Int, item: NotiItem) + fun onItemClick(position: Int, item: NotiItemInfo) } fun setOnItemClickListener(listener: OnItemClickListener) { @@ -37,12 +35,6 @@ class NotiListAdapter( val item = dataSet[position] with(binding) { this.item = item - - itemImage.clipToOutline = true - item.itemImg?.let { - itemImage.load(it) - } - notiContainer.setOnClickListener { listener.onItemClick(position, item) } @@ -56,12 +48,6 @@ class NotiListAdapter( val item = dataSet[position] with(binding) { this.item = item - - itemImage.clipToOutline = true - item.itemImageUrl?.let { - Glide.with(itemImage.context).load(it).into(itemImage) - } - notiContainer.setOnClickListener { listener.onItemClick(position, item) } @@ -106,25 +92,24 @@ class NotiListAdapter( notifyItemChanged(position) } - fun setData(items: List?) { + fun setData(items: List?) { dataSet.clear() items?.let { dataSet.addAll(it) } notifyDataSetChanged() } companion object { - private const val TAG = "notiListAdapter" - private val diffCallback = object : DiffUtil.ItemCallback() { + private val diffCallback = object : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: NotiItem, - newItem: NotiItem + oldItem: NotiItemInfo, + newItem: NotiItemInfo ): Boolean { return oldItem.itemId == newItem.itemId } override fun areContentsTheSame( - oldItem: NotiItem, - newItem: NotiItem + oldItem: NotiItemInfo, + newItem: NotiItemInfo ): Boolean { return oldItem == newItem } diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiCalendarFragment.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiCalendarFragment.kt index 2a3e6c8c..48f15db4 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiCalendarFragment.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiCalendarFragment.kt @@ -10,7 +10,7 @@ import androidx.fragment.app.Fragment import androidx.hilt.navigation.fragment.hiltNavGraphViewModels import com.hyeeyoung.wishboard.R import com.hyeeyoung.wishboard.databinding.FragmentNotiCalendarBinding -import com.hyeeyoung.wishboard.data.model.noti.NotiItem +import com.hyeeyoung.wishboard.domain.entity.NotiItemInfo import com.hyeeyoung.wishboard.util.custom.CustomSnackbar import com.hyeeyoung.wishboard.presentation.noti.adapters.CalendarAdapter import com.hyeeyoung.wishboard.presentation.noti.adapters.NotiListAdapter @@ -67,15 +67,11 @@ class NotiCalendarFragment : Fragment(), NotiListAdapter.OnItemClickListener { } } - override fun onItemClick(position: Int, item: NotiItem) { + override fun onItemClick(position: Int, item: NotiItemInfo) { if (item.itemUrl == null) { CustomSnackbar.make(binding.layout, getString(R.string.noti_item_url_snackbar_text)).show() } else { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(item.itemUrl))) } } - - companion object { - private const val TAG = "NotiCalendarFragment" - } } \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiFragment.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiFragment.kt index 9293f2c4..41263b6a 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiFragment.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/noti/screens/NotiFragment.kt @@ -10,10 +10,10 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import com.hyeeyoung.wishboard.R import com.hyeeyoung.wishboard.databinding.FragmentNotiBinding -import com.hyeeyoung.wishboard.data.model.noti.NotiItem -import com.hyeeyoung.wishboard.util.custom.CustomSnackbar -import com.hyeeyoung.wishboard.presentation.noti.adapters.NotiListAdapter +import com.hyeeyoung.wishboard.domain.entity.NotiItemInfo import com.hyeeyoung.wishboard.presentation.noti.NotiViewModel +import com.hyeeyoung.wishboard.presentation.noti.adapters.NotiListAdapter +import com.hyeeyoung.wishboard.util.custom.CustomSnackbar import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -58,7 +58,7 @@ class NotiFragment : Fragment(), NotiListAdapter.OnItemClickListener { } } - override fun onItemClick(position: Int, item: NotiItem) { + override fun onItemClick(position: Int, item: NotiItemInfo) { viewModel.updateNotiReadState(position, item.itemId) if (item.itemUrl == null) { CustomSnackbar.make(binding.layout, getString(R.string.noti_item_url_snackbar_text)).show() @@ -66,8 +66,4 @@ class NotiFragment : Fragment(), NotiListAdapter.OnItemClickListener { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(item.itemUrl))) } } - - companion object { - private const val TAG = "NotiFragment" - } } \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/viewmodels/WishItemRegistrationViewModel.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/viewmodels/WishItemRegistrationViewModel.kt index 29d61866..a2edbe9a 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/viewmodels/WishItemRegistrationViewModel.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/viewmodels/WishItemRegistrationViewModel.kt @@ -64,7 +64,6 @@ class WishItemRegistrationViewModel @Inject constructor( copyOriginItemInfo(value ?: return) } - private var isEnabledSaveButton = MediatorLiveData() private var isCompleteUpload = MutableLiveData() private var isCompleteFolderUpload = MutableLiveData() private var isExistFolderName = MutableLiveData() @@ -82,25 +81,38 @@ class WishItemRegistrationViewModel @Inject constructor( private val folderListSquareAdapter = FolderListAdapter(FolderListViewType.SQUARE_VIEW_TYPE) - val isEnabledUploadButton = MediatorLiveData().apply { - addSourceList(itemName, itemPrice) { checkValidItemInfoInput() } + private val _isEnabledSaveButton = MediatorLiveData().apply { + addSourceList( + itemName, + itemPrice, + itemImage, + selectedGalleryImageUri + ) { combineEnabledSaveButton() } } + val isEnabledSaveButton: LiveData get() = _isEnabledSaveButton - private fun checkValidItemInfoInput(): Boolean { - return !(itemName.value.isNullOrBlank() || itemPrice.value.isNullOrBlank() || token == null) + val isEnabledUploadButton = MediatorLiveData().apply { + addSourceList(itemName, itemPrice, itemImage) { checkValidItemInfoInput() } } init { - initEnabledSaveButton() fetchFolderList() } + private fun combineEnabledSaveButton() = + !(itemName.value.isNullOrBlank() || itemPrice.value.isNullOrBlank() || (itemImage.value.isNullOrBlank() && selectedGalleryImageUri.value == null)) + + private fun checkValidItemInfoInput(): Boolean { + return !(itemName.value.isNullOrBlank() || itemPrice.value.isNullOrBlank() || itemImage.value.isNullOrBlank() || token == null) + } + /** 오픈그래프 메타태그 파싱을 통해 아이템 정보 가져오기 */ fun getWishItemInfo(url: String) { viewModelScope.launch { val result = wishRepository.getItemParsingInfo(url) itemName.value = result?.first?.name - itemPrice.value = if (result?.first?.price == null || result.first?.price == "0") null else result.first?.price + itemPrice.value = + if (result?.first?.price == null || result.first?.price == "0") null else result.first?.price itemImage.value = result?.first?.image } } @@ -331,20 +343,6 @@ class WishItemRegistrationViewModel @Inject constructor( return decimalFormat.format(numPrice.toInt()) } - private fun initEnabledSaveButton() { - isEnabledSaveButton.addSource(itemName) { name -> - combineEnabledSaveButton(name, itemPrice.value) - } - - isEnabledSaveButton.addSource(itemPrice) { price -> - combineEnabledSaveButton(itemName.value, price) - } - } - - private fun combineEnabledSaveButton(name: String?, price: String?) { - isEnabledSaveButton.value = !(name.isNullOrBlank() || price.isNullOrBlank()) - } - fun removeWishItemImage() { wishItemDetail?.apply { this.image = null @@ -511,8 +509,6 @@ class WishItemRegistrationViewModel @Inject constructor( fun getFolderName(): LiveData = folderName fun getFolderListSquareAdapter(): FolderListAdapter = folderListSquareAdapter - - fun isEnabledSaveButton(): LiveData = isEnabledSaveButton fun isCompleteUpload(): LiveData = isCompleteUpload fun isCompleteFolderUpload(): LiveData = isCompleteFolderUpload diff --git a/app/src/main/res/drawable/ic_app_logo_black.xml b/app/src/main/res/drawable/ic_app_logo_black.xml new file mode 100644 index 00000000..ee7ba03a --- /dev/null +++ b/app/src/main/res/drawable/ic_app_logo_black.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/activity_wish_link_sharing.xml b/app/src/main/res/layout/activity_wish_link_sharing.xml index a6ca04cd..2ebd45f3 100644 --- a/app/src/main/res/layout/activity_wish_link_sharing.xml +++ b/app/src/main/res/layout/activity_wish_link_sharing.xml @@ -190,11 +190,11 @@ android:layout_gravity="center_horizontal" android:layout_marginBottom="-40dp" android:scaleType="centerCrop" + android:src="@drawable/ic_app_logo_black" app:layout_constraintBottom_toTopOf="@id/container" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:shapeAppearanceOverlay="@style/Style.CircleImageView.Half" - tools:src="@drawable/ic_app_logo_black" /> + app:shapeAppearanceOverlay="@style/Style.CircleImageView.Half" /> diff --git a/app/src/main/res/layout/item_calendar_noti.xml b/app/src/main/res/layout/item_calendar_noti.xml index 6581b197..ec82ff92 100644 --- a/app/src/main/res/layout/item_calendar_noti.xml +++ b/app/src/main/res/layout/item_calendar_noti.xml @@ -7,7 +7,7 @@ + type="com.hyeeyoung.wishboard.domain.entity.NotiItemInfo" /> @@ -27,15 +27,16 @@ android:backgroundTint="#EFEFEF" android:padding="@dimen/spacingBase"> - + type="com.hyeeyoung.wishboard.domain.entity.NotiItemInfo" /> @@ -24,17 +24,27 @@ android:layout_height="wrap_content" android:padding="@dimen/spacingBase"> - + + \ No newline at end of file