From b331048decb9ec5caec09eac2f1f4acf034e9ff2 Mon Sep 17 00:00:00 2001 From: klaus Date: Fri, 14 Feb 2025 15:31:01 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20-=20=EB=AC=B4=EB=A3=8C=20=ED=83=AD=20-=20=ED=81=AC?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=9D=B4=ED=84=B0=20=EC=86=8C=EA=B0=9C=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=EB=B3=B4=EA=B8=B0=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 1 + .../sodalive/audio_content/AudioContentApi.kt | 7 ++ .../curation/AudioContentCurationActivity.kt | 3 - .../free/AudioContentMainTabFreeFragment.kt | 7 ++ .../free/AudioContentMainTabFreeRepository.kt | 5 + .../IntroduceCreatorActivity.kt | 104 ++++++++++++++++++ .../IntroduceCreatorViewModel.kt | 74 +++++++++++++ .../java/kr/co/vividnext/sodalive/di/AppDI.kt | 2 + .../res/layout/activity_introduce_creator.xml | 17 +++ .../fragment_audio_content_main_tab_free.xml | 2 +- 10 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/introduce_creator/IntroduceCreatorActivity.kt create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/introduce_creator/IntroduceCreatorViewModel.kt create mode 100644 app/src/main/res/layout/activity_introduce_creator.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6307490..c3ff5e7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -154,6 +154,7 @@ + diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt index 75f7626..4373f32 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/AudioContentApi.kt @@ -326,4 +326,11 @@ interface AudioContentApi { fun getContentMainFree( @Header("Authorization") authHeader: String ): Single> + + @GET("/v2/audio-content/main/free/introduce-creator") + fun getIntroduceCreatorList( + @Query("page") page: Int, + @Query("size") size: Int, + @Header("Authorization") authHeader: String + ): Single>> } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/curation/AudioContentCurationActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/curation/AudioContentCurationActivity.kt index a69f73d..733143d 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/curation/AudioContentCurationActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/curation/AudioContentCurationActivity.kt @@ -2,9 +2,7 @@ package kr.co.vividnext.sodalive.audio_content.curation import android.annotation.SuppressLint import android.content.Intent -import android.graphics.Rect import android.os.Bundle -import android.view.View import android.widget.TextView import android.widget.Toast import androidx.core.content.ContextCompat @@ -21,7 +19,6 @@ import kr.co.vividnext.sodalive.common.GridSpacingItemDecoration import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.databinding.ActivityAudioContentCurationBinding import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity -import kr.co.vividnext.sodalive.extensions.dpToPx import org.koin.android.ext.android.inject class AudioContentCurationActivity : BaseActivity( diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/AudioContentMainTabFreeFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/AudioContentMainTabFreeFragment.kt index 8c5baee..47b3929 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/AudioContentMainTabFreeFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/AudioContentMainTabFreeFragment.kt @@ -23,6 +23,7 @@ import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainContentAdapte import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerAdapter import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentThemeAdapter import kr.co.vividnext.sodalive.audio_content.main.v2.AudioContentMainContentCurationAdapter +import kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator.IntroduceCreatorActivity import kr.co.vividnext.sodalive.audio_content.main.v2.series.new_series.AudioContentMainNewSeriesAdapter import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity import kr.co.vividnext.sodalive.base.BaseFragment @@ -152,6 +153,12 @@ class AudioContentMainTabFreeFragment : BaseFragment( + ActivityIntroduceCreatorBinding::inflate +) { + private val viewModel: IntroduceCreatorViewModel by inject() + + private lateinit var loadingDialog: LoadingDialog + private lateinit var adapter: AudioContentNewAllAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + bindData() + viewModel.getIntroduceCreatorList() + } + + override fun setupView() { + loadingDialog = LoadingDialog(this, layoutInflater) + binding.toolbar.tvBack.text = "크리에이터 소개" + binding.toolbar.tvBack.setOnClickListener { finish() } + + val spanCount = 3 + val spacing = 13.3f.dpToPx().roundToInt() + adapter = AudioContentNewAllAdapter( + itemWidth = (screenWidth - (spacing * (spanCount + 1))) / 3, + onClickItem = { + startActivity( + Intent(this, AudioContentDetailActivity::class.java).apply { + putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it) + } + ) + }, + onClickCreator = { + startActivity( + Intent(this, UserProfileActivity::class.java).apply { + putExtra(Constants.EXTRA_USER_ID, it) + } + ) + } + ) + + binding.rvContent.layoutManager = GridLayoutManager(this, spanCount) + binding.rvContent.addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, true)) + + binding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + + val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!! + .findLastCompletelyVisibleItemPosition() + val itemTotalCount = recyclerView.adapter!!.itemCount - 1 + + // 스크롤이 끝에 도달했는지 확인 + if (!recyclerView.canScrollVertically(1) && + lastVisibleItemPosition == itemTotalCount + ) { + viewModel.getIntroduceCreatorList() + } + } + }) + + binding.rvContent.adapter = adapter + } + + private fun bindData() { + viewModel.isLoading.observe(this) { + if (it) { + loadingDialog.show(screenWidth) + } else { + loadingDialog.dismiss() + } + } + + viewModel.toastLiveData.observe(this) { + it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() } + } + + viewModel.introduceCreatorListLiveData.observe(this) { + adapter.addItems(it) + } + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/introduce_creator/IntroduceCreatorViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/introduce_creator/IntroduceCreatorViewModel.kt new file mode 100644 index 0000000..224ff93 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/free/introduce_creator/IntroduceCreatorViewModel.kt @@ -0,0 +1,74 @@ +package kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.orhanobut.logger.Logger +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.schedulers.Schedulers +import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem +import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeRepository +import kr.co.vividnext.sodalive.base.BaseViewModel +import kr.co.vividnext.sodalive.common.SharedPreferenceManager + +class IntroduceCreatorViewModel( + private val repository: AudioContentMainTabFreeRepository +) : BaseViewModel() { + private val _toastLiveData = MutableLiveData() + val toastLiveData: LiveData + get() = _toastLiveData + + private var _isLoading = MutableLiveData(false) + val isLoading: LiveData + get() = _isLoading + + private var _introduceCreatorListLiveData = MutableLiveData>() + val introduceCreatorListLiveData: LiveData> + get() = _introduceCreatorListLiveData + + private var isLast = false + private var page = 1 + private val size = 10 + + fun getIntroduceCreatorList() { + if (!_isLoading.value!! && !isLast) { + _isLoading.value = true + + compositeDisposable.add( + repository.getIntroduceCreatorList( + page = page, + size = size, + token = "Bearer ${SharedPreferenceManager.token}" + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + if (it.success && it.data != null) { + if (it.data.isNotEmpty()) { + page += 1 + _introduceCreatorListLiveData.postValue(it.data!!) + } else { + isLast = true + } + } else { + if (it.message != null) { + _toastLiveData.postValue(it.message) + } else { + _toastLiveData.postValue( + "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + ) + } + } + + _isLoading.value = false + }, + { + _isLoading.value = false + it.message?.let { message -> Logger.e(message) } + _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") + } + ) + ) + } + } +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt index b2c0795..112e705 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt @@ -31,6 +31,7 @@ import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTa import kr.co.vividnext.sodalive.audio_content.main.v2.content.AudioContentMainTabContentViewModel import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeRepository import kr.co.vividnext.sodalive.audio_content.main.v2.free.AudioContentMainTabFreeViewModel +import kr.co.vividnext.sodalive.audio_content.main.v2.free.introduce_creator.IntroduceCreatorViewModel import kr.co.vividnext.sodalive.audio_content.main.v2.home.AudioContentMainTabHomeRepository import kr.co.vividnext.sodalive.audio_content.main.v2.home.AudioContentMainTabHomeViewModel import kr.co.vividnext.sodalive.audio_content.main.v2.replay.AudioContentMainTabReplayRepository @@ -314,6 +315,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) { viewModel { AudioContentMainTabReplayViewModel(get()) } viewModel { AudioContentMainTabFreeViewModel(get()) } viewModel { OriginalAudioDramaContentAllViewModel(get()) } + viewModel { IntroduceCreatorViewModel(get()) } } private val repositoryModule = module { diff --git a/app/src/main/res/layout/activity_introduce_creator.xml b/app/src/main/res/layout/activity_introduce_creator.xml new file mode 100644 index 0000000..3b1676c --- /dev/null +++ b/app/src/main/res/layout/activity_introduce_creator.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/app/src/main/res/layout/fragment_audio_content_main_tab_free.xml b/app/src/main/res/layout/fragment_audio_content_main_tab_free.xml index 022e47c..518beb5 100644 --- a/app/src/main/res/layout/fragment_audio_content_main_tab_free.xml +++ b/app/src/main/res/layout/fragment_audio_content_main_tab_free.xml @@ -58,7 +58,7 @@ android:id="@+id/rv_introduce_creator" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="30dp" + android:layout_marginTop="13.3dp" android:clipToPadding="false" android:paddingHorizontal="13.3dp" />