feat: 마이페이지
- 최근 들은 콘텐츠 추가
This commit is contained in:
		@@ -1,8 +1,6 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.audio_content.detail
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.app.Service
 | 
			
		||||
import android.content.BroadcastReceiver
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
@@ -56,6 +54,8 @@ import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentTempActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.RecentContentViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContent
 | 
			
		||||
import kr.co.vividnext.sodalive.report.ReportType
 | 
			
		||||
import org.koin.android.ext.android.inject
 | 
			
		||||
import kotlin.math.ceil
 | 
			
		||||
@@ -65,6 +65,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
 | 
			
		||||
    ActivityAudioContentDetailBinding::inflate
 | 
			
		||||
) {
 | 
			
		||||
    private val viewModel: AudioContentDetailViewModel by inject()
 | 
			
		||||
    private val recentContentViewModel: RecentContentViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
    private lateinit var creatorOtherContentAdapter: OtherContentAdapter
 | 
			
		||||
@@ -808,6 +809,15 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                recentContentViewModel.insertRecentContent(
 | 
			
		||||
                    RecentContent(
 | 
			
		||||
                        contentId = response.contentId,
 | 
			
		||||
                        coverImageUrl = response.coverImageUrl,
 | 
			
		||||
                        title = response.title,
 | 
			
		||||
                        creatorNickname = response.creator.nickname
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            binding.ivPlayOrPause.setImageResource(
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,9 @@ import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Utils
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentPlayerBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.RecentContentViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContent
 | 
			
		||||
import org.koin.android.ext.android.inject
 | 
			
		||||
import org.koin.androidx.viewmodel.ext.android.viewModel
 | 
			
		||||
 | 
			
		||||
@UnstableApi
 | 
			
		||||
@@ -53,6 +56,7 @@ class AudioContentPlayerFragment(
 | 
			
		||||
    private lateinit var binding: FragmentAudioContentPlayerBinding
 | 
			
		||||
 | 
			
		||||
    private val viewModel: AudioContentPlayerViewModel by viewModel()
 | 
			
		||||
    private val recentContentViewModel: RecentContentViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private var mediaController: MediaController? = null
 | 
			
		||||
    private val handler = Handler(Looper.getMainLooper())
 | 
			
		||||
@@ -451,7 +455,19 @@ class AudioContentPlayerFragment(
 | 
			
		||||
                transformations(RoundedCornersTransformation(8f.dpToPx()))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            adapter.updateCurrentPlayingId(it.extras?.getLong(Constants.EXTRA_AUDIO_CONTENT_ID))
 | 
			
		||||
            val contentId = it.extras?.getLong(Constants.EXTRA_AUDIO_CONTENT_ID)
 | 
			
		||||
            adapter.updateCurrentPlayingId(contentId)
 | 
			
		||||
 | 
			
		||||
            // Save to recent content
 | 
			
		||||
            contentId?.let { id ->
 | 
			
		||||
                val recentContent = RecentContent(
 | 
			
		||||
                    contentId = id,
 | 
			
		||||
                    coverImageUrl = it.artworkUri.toString(),
 | 
			
		||||
                    title = it.title.toString(),
 | 
			
		||||
                    creatorNickname = it.artist.toString()
 | 
			
		||||
                )
 | 
			
		||||
                recentContentViewModel.insertRecentContent(recentContent)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -137,6 +137,7 @@ import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagApi
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.recentContentModule
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.service_center.FaqApi
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.service_center.FaqRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterViewModel
 | 
			
		||||
@@ -387,10 +388,12 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
 | 
			
		||||
        factory { HomeRepository(get()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private val moduleList = listOf(
 | 
			
		||||
        networkModule,
 | 
			
		||||
        viewModelModule,
 | 
			
		||||
        repositoryModule,
 | 
			
		||||
        recentContentModule,
 | 
			
		||||
        otherModule
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,23 +2,28 @@ package kr.co.vividnext.sodalive.mypage
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.Rect
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.webkit.URLUtil
 | 
			
		||||
import android.widget.LinearLayout
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.media3.common.util.UnstableApi
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import coil.load
 | 
			
		||||
import coil.transform.CircleCropTransformation
 | 
			
		||||
import com.google.gson.Gson
 | 
			
		||||
import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.box.AudioContentBoxActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.base.BaseFragment
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Constants
 | 
			
		||||
import kr.co.vividnext.sodalive.common.FunctionButtonHelper
 | 
			
		||||
import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.FragmentMyBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
 | 
			
		||||
import kr.co.vividnext.sodalive.main.MainActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListActivity
 | 
			
		||||
@@ -31,6 +36,8 @@ import kr.co.vividnext.sodalive.mypage.can.coupon.CanCouponActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.point.PointStatusActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.RecentContentAdapter
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.RecentContentViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.settings.SettingsActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.settings.event.EventActivity
 | 
			
		||||
@@ -42,6 +49,7 @@ import org.koin.android.ext.android.inject
 | 
			
		||||
class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflate) {
 | 
			
		||||
 | 
			
		||||
    private val viewModel: MyPageViewModel by inject()
 | 
			
		||||
    private val recentContentViewModel: RecentContentViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
 | 
			
		||||
@@ -51,6 +59,73 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
 | 
			
		||||
 | 
			
		||||
        setupView()
 | 
			
		||||
        bindData()
 | 
			
		||||
        setupRecentContentSection()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupRecentContentSection() {
 | 
			
		||||
        val adapter = RecentContentAdapter {
 | 
			
		||||
            startActivity(
 | 
			
		||||
                Intent(
 | 
			
		||||
                    requireContext(),
 | 
			
		||||
                    AudioContentDetailActivity::class.java
 | 
			
		||||
                ).apply {
 | 
			
		||||
                    putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val rvRecentContent = binding.rvRecentContent
 | 
			
		||||
 | 
			
		||||
        rvRecentContent.layoutManager = LinearLayoutManager(
 | 
			
		||||
            requireContext(),
 | 
			
		||||
            LinearLayoutManager.HORIZONTAL,
 | 
			
		||||
            false
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        rvRecentContent.addItemDecoration(object : RecyclerView.ItemDecoration() {
 | 
			
		||||
            override fun getItemOffsets(
 | 
			
		||||
                outRect: Rect,
 | 
			
		||||
                view: View,
 | 
			
		||||
                parent: RecyclerView,
 | 
			
		||||
                state: RecyclerView.State
 | 
			
		||||
            ) {
 | 
			
		||||
                super.getItemOffsets(outRect, view, parent, state)
 | 
			
		||||
 | 
			
		||||
                when (parent.getChildAdapterPosition(view)) {
 | 
			
		||||
                    0 -> {
 | 
			
		||||
                        outRect.left = 0
 | 
			
		||||
                        outRect.right = 8f.dpToPx().toInt()
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    adapter.itemCount - 1 -> {
 | 
			
		||||
                        outRect.left = 8f.dpToPx().toInt()
 | 
			
		||||
                        outRect.right = 0
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    else -> {
 | 
			
		||||
                        outRect.left = 8f.dpToPx().toInt()
 | 
			
		||||
                        outRect.right = 8f.dpToPx().toInt()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        rvRecentContent.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        // Observe recent contents
 | 
			
		||||
        recentContentViewModel.getRecentContents(10).observe(viewLifecycleOwner) { contents ->
 | 
			
		||||
            if (contents.isNotEmpty()) {
 | 
			
		||||
                binding.llRecentContent.visibility = View.VISIBLE
 | 
			
		||||
                adapter.submitList(contents)
 | 
			
		||||
            } else {
 | 
			
		||||
                binding.llRecentContent.visibility = View.GONE
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Observe count
 | 
			
		||||
        recentContentViewModel.recentContentsCount.observe(viewLifecycleOwner) { count ->
 | 
			
		||||
            binding.tvRecentCount.text = count.toString()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStart() {
 | 
			
		||||
@@ -62,10 +137,6 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupView() {
 | 
			
		||||
//        val ivHowToUseLp = binding.ivIntroduceVoiceon.layoutParams as LinearLayout.LayoutParams
 | 
			
		||||
//        ivHowToUseLp.width = screenWidth
 | 
			
		||||
//        ivHowToUseLp.height = (120 * screenWidth) / 352
 | 
			
		||||
//        binding.ivIntroduceVoiceon.layoutParams = ivHowToUseLp
 | 
			
		||||
        binding.ivIntroduceVoiceon.setOnClickListener {
 | 
			
		||||
            val url = "https://blog.naver.com/sodalive_official"
 | 
			
		||||
            if (URLUtil.isValidUrl(url)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent
 | 
			
		||||
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.recyclerview.widget.DiffUtil
 | 
			
		||||
import androidx.recyclerview.widget.ListAdapter
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import coil.load
 | 
			
		||||
import coil.transform.RoundedCornersTransformation
 | 
			
		||||
import kr.co.vividnext.sodalive.R
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.ItemHomeContentBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.extensions.dpToPx
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContent
 | 
			
		||||
 | 
			
		||||
class RecentContentAdapter(
 | 
			
		||||
    private val onClickItem: (Long) -> Unit
 | 
			
		||||
) : ListAdapter<RecentContent, RecentContentAdapter.RecentContentViewHolder>(
 | 
			
		||||
    RecentContentDiffCallback()
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecentContentViewHolder {
 | 
			
		||||
        val binding = ItemHomeContentBinding.inflate(
 | 
			
		||||
            LayoutInflater.from(parent.context),
 | 
			
		||||
            parent,
 | 
			
		||||
            false
 | 
			
		||||
        )
 | 
			
		||||
        return RecentContentViewHolder(binding)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(holder: RecentContentViewHolder, position: Int) {
 | 
			
		||||
        val currentItem = getItem(position)
 | 
			
		||||
        holder.bind(currentItem)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inner class RecentContentViewHolder(
 | 
			
		||||
        private val binding: ItemHomeContentBinding
 | 
			
		||||
    ) : RecyclerView.ViewHolder(binding.root) {
 | 
			
		||||
        fun bind(item: RecentContent) {
 | 
			
		||||
            binding.ivPoint.visibility = View.GONE
 | 
			
		||||
 | 
			
		||||
            binding.ivContentCoverImage.load(item.coverImageUrl) {
 | 
			
		||||
                crossfade(true)
 | 
			
		||||
                placeholder(R.drawable.ic_place_holder)
 | 
			
		||||
                transformations(RoundedCornersTransformation(16f.dpToPx()))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            binding.tvContentTitle.text = item.title
 | 
			
		||||
            binding.tvNickname.text = item.creatorNickname
 | 
			
		||||
 | 
			
		||||
            binding.root.setOnClickListener { onClickItem(item.contentId) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class RecentContentDiffCallback : DiffUtil.ItemCallback<RecentContent>() {
 | 
			
		||||
        override fun areItemsTheSame(oldItem: RecentContent, newItem: RecentContent): Boolean {
 | 
			
		||||
            return oldItem.contentId == newItem.contentId
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun areContentsTheSame(oldItem: RecentContent, newItem: RecentContent): Boolean {
 | 
			
		||||
            return oldItem == newItem
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent
 | 
			
		||||
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContentDatabase
 | 
			
		||||
import org.koin.android.ext.koin.androidContext
 | 
			
		||||
import org.koin.androidx.viewmodel.dsl.viewModel
 | 
			
		||||
import org.koin.dsl.module
 | 
			
		||||
 | 
			
		||||
val recentContentModule = module {
 | 
			
		||||
    // Database
 | 
			
		||||
    single { RecentContentDatabase.getDatabase(androidContext()) }
 | 
			
		||||
 | 
			
		||||
    // DAO
 | 
			
		||||
    single { get<RecentContentDatabase>().recentContentDao() }
 | 
			
		||||
 | 
			
		||||
    // Repository
 | 
			
		||||
    factory { RecentContentRepository(get()) }
 | 
			
		||||
 | 
			
		||||
    // ViewModel
 | 
			
		||||
    viewModel { RecentContentViewModel(get()) }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent
 | 
			
		||||
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContent
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContentDao
 | 
			
		||||
 | 
			
		||||
class RecentContentRepository(private val recentContentDao: RecentContentDao) {
 | 
			
		||||
    val recentContentsCount: Flow<Int> = recentContentDao.getCount()
 | 
			
		||||
 | 
			
		||||
    fun getRecentContents(limit: Int): Flow<List<RecentContent>> {
 | 
			
		||||
        return recentContentDao.getRecentContents(limit)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun insertRecentContent(recentContent: RecentContent) {
 | 
			
		||||
        recentContentDao.insertRecentContent(recentContent)
 | 
			
		||||
        // Keep only the most recent 10 items
 | 
			
		||||
        recentContentDao.keepMostRecent(10)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun deleteByContentId(contentId: Long) {
 | 
			
		||||
        recentContentDao.deleteByContentId(contentId)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun truncate() {
 | 
			
		||||
        recentContentDao.deleteAllRecentContents()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.LiveData
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.asLiveData
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.db.RecentContent
 | 
			
		||||
 | 
			
		||||
class RecentContentViewModel(private val repository: RecentContentRepository) : ViewModel() {
 | 
			
		||||
    val recentContentsCount: LiveData<Int> = repository.recentContentsCount.asLiveData()
 | 
			
		||||
 | 
			
		||||
    fun getRecentContents(limit: Int): LiveData<List<RecentContent>> {
 | 
			
		||||
        return repository.getRecentContents(limit).asLiveData()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun insertRecentContent(recentContent: RecentContent) = viewModelScope.launch {
 | 
			
		||||
        repository.insertRecentContent(recentContent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun deleteByContentId(contentId: Long) = viewModelScope.launch {
 | 
			
		||||
        repository.deleteByContentId(contentId)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun truncate() = viewModelScope.launch {
 | 
			
		||||
        repository.truncate()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent.db
 | 
			
		||||
 | 
			
		||||
import androidx.room.Entity
 | 
			
		||||
import androidx.room.PrimaryKey
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "recent_contents")
 | 
			
		||||
data class RecentContent(
 | 
			
		||||
    @PrimaryKey
 | 
			
		||||
    val contentId: Long,
 | 
			
		||||
    val coverImageUrl: String,
 | 
			
		||||
    val title: String,
 | 
			
		||||
    val creatorNickname: String,
 | 
			
		||||
    val listenedAt: Long = System.currentTimeMillis() // For sorting by most recent
 | 
			
		||||
)
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent.db
 | 
			
		||||
 | 
			
		||||
import androidx.room.Dao
 | 
			
		||||
import androidx.room.Insert
 | 
			
		||||
import androidx.room.OnConflictStrategy
 | 
			
		||||
import androidx.room.Query
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
interface RecentContentDao {
 | 
			
		||||
    @Query("SELECT * FROM recent_contents ORDER BY listenedAt DESC LIMIT :limit")
 | 
			
		||||
    fun getRecentContents(limit: Int): Flow<List<RecentContent>>
 | 
			
		||||
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE)
 | 
			
		||||
    suspend fun insertRecentContent(recentContent: RecentContent)
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM recent_contents WHERE contentId = :contentId")
 | 
			
		||||
    suspend fun deleteByContentId(contentId: Long)
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT COUNT(*) FROM recent_contents")
 | 
			
		||||
    fun getCount(): Flow<Int>
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM recent_contents WHERE contentId NOT IN (SELECT contentId FROM recent_contents ORDER BY listenedAt DESC LIMIT :limit)")
 | 
			
		||||
    suspend fun keepMostRecent(limit: Int)
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM recent_contents")
 | 
			
		||||
    suspend fun deleteAllRecentContents()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.mypage.recent.db
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import androidx.room.Database
 | 
			
		||||
import androidx.room.Room
 | 
			
		||||
import androidx.room.RoomDatabase
 | 
			
		||||
import androidx.room.TypeConverters
 | 
			
		||||
import kr.co.vividnext.sodalive.common.Converter
 | 
			
		||||
 | 
			
		||||
@Database(entities = [RecentContent::class], version = 1)
 | 
			
		||||
@TypeConverters(Converter::class)
 | 
			
		||||
abstract class RecentContentDatabase : RoomDatabase() {
 | 
			
		||||
    abstract fun recentContentDao(): RecentContentDao
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        @Volatile
 | 
			
		||||
        private var INSTANCE: RecentContentDatabase? = null
 | 
			
		||||
 | 
			
		||||
        fun getDatabase(context: Context): RecentContentDatabase {
 | 
			
		||||
            return INSTANCE ?: synchronized(this) {
 | 
			
		||||
                val instance = Room.databaseBuilder(
 | 
			
		||||
                    context.applicationContext,
 | 
			
		||||
                    RecentContentDatabase::class.java,
 | 
			
		||||
                    "recent_content_database" // Different name from alarm database
 | 
			
		||||
                ).build()
 | 
			
		||||
                INSTANCE = instance
 | 
			
		||||
                instance
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -19,6 +19,7 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
 | 
			
		||||
import kr.co.vividnext.sodalive.databinding.ActivitySettingsBinding
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.alarm.AlarmViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.mypage.recent.RecentContentViewModel
 | 
			
		||||
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.settings.signout.SignOutActivity
 | 
			
		||||
import kr.co.vividnext.sodalive.settings.terms.TermsActivity
 | 
			
		||||
@@ -56,6 +57,7 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(ActivitySettingsB
 | 
			
		||||
 | 
			
		||||
    private val viewModel: SettingsViewModel by inject()
 | 
			
		||||
    private val alarmViewModel: AlarmViewModel by viewModels()
 | 
			
		||||
    private val recentContentViewModel: RecentContentViewModel by inject()
 | 
			
		||||
 | 
			
		||||
    private lateinit var loadingDialog: LoadingDialog
 | 
			
		||||
 | 
			
		||||
@@ -158,8 +160,11 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(ActivitySettingsB
 | 
			
		||||
 | 
			
		||||
        viewModel.logout {
 | 
			
		||||
            NotiflyClient.logout(context = applicationContext)
 | 
			
		||||
 | 
			
		||||
            SharedPreferenceManager.clear()
 | 
			
		||||
            alarmViewModel.truncate()
 | 
			
		||||
            recentContentViewModel.truncate()
 | 
			
		||||
 | 
			
		||||
            finishAffinity()
 | 
			
		||||
            startActivity(Intent(applicationContext, SplashActivity::class.java))
 | 
			
		||||
        }
 | 
			
		||||
@@ -181,9 +186,12 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(ActivitySettingsB
 | 
			
		||||
 | 
			
		||||
        viewModel.logoutAllDevice() {
 | 
			
		||||
            NotiflyClient.logout(context = applicationContext)
 | 
			
		||||
 | 
			
		||||
            SharedPreferenceManager.clear()
 | 
			
		||||
            alarmViewModel.truncate()
 | 
			
		||||
            finishAffinity()
 | 
			
		||||
            recentContentViewModel.truncate()
 | 
			
		||||
 | 
			
		||||
             finishAffinity()
 | 
			
		||||
            startActivity(Intent(applicationContext, SplashActivity::class.java))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -385,9 +385,7 @@
 | 
			
		||||
                <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
                    android:id="@+id/rv_recent_content"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:clipToPadding="false"
 | 
			
		||||
                    android:paddingHorizontal="24dp" />
 | 
			
		||||
                    android:layout_height="wrap_content" />
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
        </LinearLayout>
 | 
			
		||||
    </androidx.core.widget.NestedScrollView>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user