Compare commits
156 Commits
78c9b24bb9
...
d13769861d
| Author | SHA1 | Date | |
|---|---|---|---|
| d13769861d | |||
| 5d15f74575 | |||
| 5f445872c8 | |||
| d44853055a | |||
| 4ddee2b1c1 | |||
| 6031638260 | |||
| 39f647d05a | |||
| a1b464e864 | |||
| d657e8827a | |||
| 6cb89ef09f | |||
| 00941d8082 | |||
| cf612fa0c7 | |||
| 6d5018c3fd | |||
| f333d301b8 | |||
| 11c5d57c4e | |||
| f269044c69 | |||
| b1075eee16 | |||
| 5adfecf689 | |||
| f44eacaf52 | |||
| 258f0036a6 | |||
| 4d33d459ee | |||
| 1cdbd92d35 | |||
| 871603f1bb | |||
| 032640b068 | |||
| 2e7c3a5352 | |||
| c78370ec2a | |||
| 6813a74c13 | |||
| 3980673322 | |||
| 0b99235ec2 | |||
| 906881dc9c | |||
| d5b6a3f2d6 | |||
| 4b4e47d17c | |||
| 6e2fcc53a5 | |||
| dfaa3961bf | |||
| 1d002c4045 | |||
| 4e80d91c20 | |||
| 2525811db4 | |||
| 5583004515 | |||
| a4a11b5801 | |||
| 9adc45095b | |||
| c66fdf63db | |||
| 23a98b399c | |||
| 0ddf416b9d | |||
| f0a2e2c46f | |||
| 3bd8061a93 | |||
| b67a3fd0b4 | |||
| e9df2bfa03 | |||
| a75a11c9f6 | |||
| ebd557ff71 | |||
| 0854b76dfa | |||
| 2e7b1ac09e | |||
| 4e15557949 | |||
| e2c7134f61 | |||
| 6f67c4e8e1 | |||
| d8d6509668 | |||
| c9a1417d60 | |||
| 6cb8616c00 | |||
| 26ad8c39dc | |||
| f2f406d581 | |||
| b4ced77d57 | |||
| 5ee57b1b2f | |||
| 57e3edc24e | |||
| fc984cef22 | |||
| 81b6cbe655 | |||
| e838085291 | |||
| 0f6ebbfa76 | |||
| ae081994c3 | |||
| e67251c9ba | |||
| 270d697ce6 | |||
| a050a56c19 | |||
| ab7f837bb4 | |||
| f2e682c3d3 | |||
| 237d112dec | |||
| f8769e97f9 | |||
| 5ef7896f1d | |||
| 4a5627bf36 | |||
| b521b79fe4 | |||
| 35f95aa0f2 | |||
| de042abd79 | |||
| ad1c58bbf5 | |||
| 764ca0f892 | |||
| 1018b6426e | |||
| c74503beca | |||
| 7988b8c63e | |||
| 6ef19d53f4 | |||
| dc00fd0277 | |||
| 96d14356be | |||
| a3fb090593 | |||
| 5a4b833516 | |||
| 82b09f2c63 | |||
| fd6a025de9 | |||
| 99bc5f14f7 | |||
| ddc7b9a76f | |||
| af03d4dafd | |||
| 09bc25f035 | |||
| 072b206035 | |||
| af04ff9bf7 | |||
| 6bd63fc751 | |||
| 4ed6437ce3 | |||
| b356591aba | |||
| 00db1d7bfd | |||
| cc517eb4d3 | |||
| 4a8442cb33 | |||
| 7023324920 | |||
| 3cfab2c57b | |||
| 4caaeff0f0 | |||
| 98a6fb6637 | |||
| 50edf85de5 | |||
| 19b74b2671 | |||
| 7b6d2cd782 | |||
| b457cf0b4d | |||
| 7f27f461f3 | |||
| 3909920a4c | |||
| 5ff35b1da4 | |||
| 90c71026da | |||
| 707107328a | |||
| 958244c9b2 | |||
| adc2f759c4 | |||
| c3c1a83e97 | |||
| 61fa6d5f74 | |||
| 9782462345 | |||
| 480b47ee3d | |||
| 2e528f8c7d | |||
| 7e4202db1b | |||
| 09a8019c66 | |||
| e44bd68152 | |||
| 2066dbc716 | |||
| 73b2eba1f8 | |||
| 101c396ac2 | |||
| 3cf24c2ab6 | |||
| 4e0e6708e6 | |||
| ebe5c342c9 | |||
| 37c1bc06d0 | |||
| 98209d0d5f | |||
| 159a5ae8b3 | |||
| e9afa55aa0 | |||
| e727658b24 | |||
| eb0aa9473f | |||
| 981859de1f | |||
| 1889c6ae10 | |||
| 7e74bd1e4d | |||
| 4d1e859bbf | |||
| 492077ddb2 | |||
| bca527eca0 | |||
| 707dc351ba | |||
| cc55a19e1d | |||
| 8b215e553d | |||
| af1679c92b | |||
| 41c11d763e | |||
| 1efd968b09 | |||
| ede2dc201c | |||
| 2740522f05 | |||
| 6e3edd1e96 | |||
| 0326fa89ea | |||
| dcdf3b21bc | |||
| 748da3ec0c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -60,6 +60,7 @@ captures/
|
||||
|
||||
.idea/AndroidProjectSystem.xml
|
||||
.idea/runConfigurations.xml
|
||||
.idea/deploymentTargetSelector.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
|
||||
18
.idea/deploymentTargetSelector.xml
generated
18
.idea/deploymentTargetSelector.xml
generated
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetSelector">
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2025-10-23T14:41:22.468459Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=ce0917195d15ab39017e" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/markdown.xml
generated
Normal file
8
.idea/markdown.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownSettings">
|
||||
<option name="previewPanelProviderInfo">
|
||||
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
18
AGENTS.md
Normal file
18
AGENTS.md
Normal file
@@ -0,0 +1,18 @@
|
||||
질문에 대한 답변과 설명은 한국어로 한다.
|
||||
|
||||
## Quality Assurance Guidelines
|
||||
|
||||
### Commit Standards
|
||||
1. Write in Korean.
|
||||
2. Use the present tense in the subject line (e.g., "Add feature" not "Added feature").
|
||||
3. Keep the subject line to 50 characters or less.
|
||||
4. Add a blank line between the subject and body.
|
||||
5. Keep the body to 72 characters or less per line.
|
||||
6. Within a paragraph, only break lines when the text exceeds 72 characters.
|
||||
7. Describe changes to public API features and do not include implementation details such as package-private code.
|
||||
8. Do not mention test code in commit messages.
|
||||
9. Do not use any prefix (such as "fix:", "update:", "docs:", "feat:", etc.) in the subject line.
|
||||
10. Do not start the subject line with a lowercase letter unless the first word is a function name or another identifier that is conventionally lowercase and there is a clear, justifiable reason for the exception. Otherwise, always start with an uppercase letter.
|
||||
11. Do not include tool advertisements, branding, or promotional content in commit messages.
|
||||
12. Use separate git commands to stage files before committing.
|
||||
13. Always validate commits using `work/scripts/check-commit-message-rules.sh` and fix until validation passes.
|
||||
@@ -63,8 +63,8 @@ android {
|
||||
applicationId "kr.co.vividnext.sodalive"
|
||||
minSdk 23
|
||||
targetSdk 35
|
||||
versionCode 204
|
||||
versionName "1.44.0"
|
||||
versionCode 218
|
||||
versionName "1.48.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -83,6 +83,7 @@ android {
|
||||
buildConfigField 'String', 'KAKAO_APP_KEY', '"231cf78acfa8252fca38b9eedf87c5cb"'
|
||||
buildConfigField 'String', 'GOOGLE_CLIENT_ID', '"983594297130-5hrmkh6vpskeq6v34350kmilf74574h2.apps.googleusercontent.com"'
|
||||
buildConfigField 'String', 'APPSCHEME', '"voiceon"'
|
||||
buildConfigField 'String', 'LINE_CHANNEL_ID', '"2008995539"'
|
||||
manifestPlaceholders = [
|
||||
URISCHEME : "voiceon",
|
||||
APPLINK_HOST : "voiceon.onelink.me",
|
||||
@@ -109,6 +110,7 @@ android {
|
||||
buildConfigField 'String', 'KAKAO_APP_KEY', '"20cf19413d63bfdfd30e8e6dff933d33"'
|
||||
buildConfigField 'String', 'GOOGLE_CLIENT_ID', '"758414412471-mosodbj2chno7l1j0iihldh6edmk0gk9.apps.googleusercontent.com"'
|
||||
buildConfigField 'String', 'APPSCHEME', '"voiceon-test"'
|
||||
buildConfigField 'String', 'LINE_CHANNEL_ID', '"2008995582"'
|
||||
manifestPlaceholders = [
|
||||
URISCHEME : "voiceon-test",
|
||||
APPLINK_HOST : "voiceon-test.onelink.me",
|
||||
@@ -234,6 +236,11 @@ dependencies {
|
||||
|
||||
implementation 'com.github.orbitalsonic:Sonic-Water-Wave-Animation:2.0.1'
|
||||
|
||||
// Line
|
||||
implementation("com.linecorp.linesdk:linesdk:5.6.1") {
|
||||
exclude group: "org.jetbrains.kotlin", module: "kotlin-android-extensions-runtime"
|
||||
}
|
||||
|
||||
// ----- Test dependencies -----
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.mockito:mockito-core:5.20.0'
|
||||
|
||||
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
@@ -243,3 +243,5 @@
|
||||
-dontwarn com.yalantis.ucrop**
|
||||
-keep class com.yalantis.ucrop** { *; }
|
||||
-keep interface com.yalantis.ucrop** { *; }
|
||||
|
||||
-dontwarn com.linecorp.linesdk.BR
|
||||
|
||||
4
app/src/debug/res/values-en/strings.xml
Normal file
4
app/src/debug/res/values-en/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">VoiceOn-Test</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-ja/strings.xml
Normal file
4
app/src/debug/res/values-ja/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">ボイスオン-テスト</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values/strings.xml
Normal file
4
app/src/debug/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">보이스온-테스트</string>
|
||||
</resources>
|
||||
@@ -63,6 +63,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.SodaLive"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:replace="android:allowBackup"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".main.DeepLinkActivity"
|
||||
@@ -109,6 +110,7 @@
|
||||
<activity android:name=".main.MainActivity" />
|
||||
<activity android:name=".user.login.LoginActivity" />
|
||||
<activity android:name=".audio_content.all.AudioContentAllActivity" />
|
||||
<activity android:name=".settings.language.LanguageSettingsActivity" />
|
||||
<activity
|
||||
android:name=".user.signup.SignUpActivity"
|
||||
android:windowSoftInputMode="stateVisible" />
|
||||
@@ -160,7 +162,6 @@
|
||||
<activity android:name=".live.reservation.all.LiveReservationAllActivity" />
|
||||
<activity android:name=".mypage.service_center.ServiceCenterActivity" />
|
||||
<activity android:name=".message.MessageActivity" />
|
||||
<activity android:name=".onboarding.OnBoardingActivity" />
|
||||
<activity android:name=".mypage.profile.ProfileUpdateActivity" />
|
||||
<activity android:name=".mypage.profile.nickname.NicknameUpdateActivity" />
|
||||
<activity android:name=".mypage.profile.password.ModifyPasswordActivity" />
|
||||
|
||||
@@ -15,8 +15,10 @@ import com.kakao.sdk.common.KakaoSdk
|
||||
import com.orhanobut.logger.AndroidLogAdapter
|
||||
import com.orhanobut.logger.Logger
|
||||
import kr.co.vividnext.sodalive.BuildConfig
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.ImageLoaderProvider
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.di.AppDI
|
||||
import kr.co.vividnext.sodalive.tracking.FirebaseTracking
|
||||
import tech.notifly.Notifly
|
||||
@@ -36,6 +38,7 @@ class SodaLiveApp : Application(), DefaultLifecycleObserver {
|
||||
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
|
||||
SodaLiveApplicationHolder.init(this)
|
||||
SharedPreferenceManager.init(applicationContext)
|
||||
|
||||
ImageLoaderProvider.init(applicationContext)
|
||||
@@ -108,8 +111,13 @@ class SodaLiveApp : Application(), DefaultLifecycleObserver {
|
||||
logUtmInFirebase()
|
||||
}
|
||||
|
||||
DeepLinkResult.Status.NOT_FOUND -> Logger.d("딥링크를 찾을 수 없습니다.")
|
||||
DeepLinkResult.Status.ERROR -> Logger.d("딥링크 처리 중 오류 발생: ${deepLinkResult.error}")
|
||||
DeepLinkResult.Status.NOT_FOUND -> Logger.d(
|
||||
getString(R.string.deeplink_not_found)
|
||||
)
|
||||
|
||||
DeepLinkResult.Status.ERROR -> Logger.d(
|
||||
getString(R.string.deeplink_error, deepLinkResult.error)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
||||
|
||||
private var userId: Long = 0
|
||||
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
|
||||
private val allCategoryLabel by lazy { getString(R.string.audio_content_label_all) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
|
||||
@@ -53,7 +54,11 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (userId <= 0) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.screen_audio_content_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -64,7 +69,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.toolbar.tvBack.text = "콘텐츠 전체보기"
|
||||
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_title)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
audioContentAdapter = AudioContentAdapter {
|
||||
@@ -75,7 +80,9 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
categoryAdapter = AudioContentCategoryAdapter {
|
||||
categoryAdapter = AudioContentCategoryAdapter(
|
||||
allCategoryLabel = allCategoryLabel
|
||||
) {
|
||||
viewModel.selectCategory(it, userId = userId)
|
||||
}
|
||||
|
||||
@@ -259,7 +266,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
||||
if (it.isNotEmpty()) {
|
||||
binding.rvCategory.visibility = View.VISIBLE
|
||||
val items = it as MutableList<GetCategoryListResponse>
|
||||
items.add(0, GetCategoryListResponse(0, "전체"))
|
||||
items.add(0, GetCategoryListResponse(0, allCategoryLabel))
|
||||
categoryAdapter.addItems(items = items)
|
||||
} else {
|
||||
binding.rvCategory.visibility = View.GONE
|
||||
|
||||
@@ -66,7 +66,8 @@ class AudioContentAdapter(
|
||||
} else {
|
||||
binding.tvPrice.visibility = View.VISIBLE
|
||||
if (item.price < 1) {
|
||||
binding.tvPrice.text = "무료"
|
||||
binding.tvPrice.text =
|
||||
binding.root.context.getString(R.string.audio_content_price_free)
|
||||
binding.tvPrice.setCompoundDrawables(null, null, null, null)
|
||||
} else {
|
||||
binding.tvPrice.text = item.price.moneyFormat()
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package kr.co.vividnext.sodalive.audio_content
|
||||
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.category.CategoryApi
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest
|
||||
import kr.co.vividnext.sodalive.audio_content.donation.AudioContentDonationRequest
|
||||
import kr.co.vividnext.sodalive.audio_content.order.OrderRequest
|
||||
import kr.co.vividnext.sodalive.audio_content.order.OrderType
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.settings.ContentType
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
@@ -70,7 +72,10 @@ class AudioContentRepository(
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun getAudioContentDetail(audioContentId: Long, token: String) = api.getAudioContentDetail(
|
||||
fun getAudioContentDetail(
|
||||
audioContentId: Long,
|
||||
token: String
|
||||
) = api.getAudioContentDetail(
|
||||
id = audioContentId,
|
||||
timezone = TimeZone.getDefault().id,
|
||||
authHeader = token
|
||||
@@ -150,7 +155,8 @@ class AudioContentRepository(
|
||||
fun getContentRanking(
|
||||
page: Int,
|
||||
size: Int,
|
||||
sortType: String = "매출",
|
||||
sortType: String = SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.screen_home_sort_revenue),
|
||||
token: String
|
||||
) = api.getContentRanking(
|
||||
page = page - 1,
|
||||
|
||||
@@ -6,9 +6,11 @@ import com.google.gson.annotations.SerializedName
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.category.GetCategoryListResponse
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.explorer.profile.GetAudioContentListResponse
|
||||
|
||||
class AudioContentViewModel(private val repository: AudioContentRepository) : BaseViewModel() {
|
||||
@@ -80,7 +82,8 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,7 +97,10 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
@@ -134,7 +140,8 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -144,7 +151,10 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -35,6 +35,7 @@ class AudioContentAllActivity : BaseActivity<ActivityAudioContentAllBinding>(
|
||||
|
||||
private var isFree: Boolean = false
|
||||
private var isPointOnly: Boolean = false
|
||||
private val allThemeLabel by lazy { getString(R.string.screen_home_theme_all) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
isFree = intent.getBooleanExtra(Constants.EXTRA_AUDIO_CONTENT_FREE, false)
|
||||
@@ -56,9 +57,9 @@ class AudioContentAllActivity : BaseActivity<ActivityAudioContentAllBinding>(
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.toolbar.tvBack.text = when {
|
||||
isPointOnly -> "포인트 대여 전체"
|
||||
isFree -> "무료 콘텐츠 전체"
|
||||
else -> "콘텐츠 전체보기"
|
||||
isPointOnly -> getString(R.string.screen_audio_content_all_title_point_only)
|
||||
isFree -> getString(R.string.screen_audio_content_all_title_free)
|
||||
else -> getString(R.string.screen_audio_content_title)
|
||||
}
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
@@ -75,9 +76,10 @@ class AudioContentAllActivity : BaseActivity<ActivityAudioContentAllBinding>(
|
||||
}
|
||||
|
||||
private fun setupTheme() {
|
||||
themeAdapter = HomeContentThemeAdapter {
|
||||
themeAdapter = HomeContentThemeAdapter(allThemeLabel) { selectedTheme ->
|
||||
adapter.addItems(emptyList())
|
||||
viewModel.selectTheme(it, isFree = isFree, isPointOnly = isPointOnly)
|
||||
val theme = if (selectedTheme == allThemeLabel) "" else selectedTheme
|
||||
viewModel.selectTheme(theme, isFree = isFree, isPointOnly = isPointOnly)
|
||||
}
|
||||
|
||||
binding.rvTheme.layoutManager = LinearLayoutManager(
|
||||
@@ -169,7 +171,9 @@ class AudioContentAllActivity : BaseActivity<ActivityAudioContentAllBinding>(
|
||||
}
|
||||
|
||||
viewModel.themeListLiveData.observe(this) {
|
||||
themeAdapter.addItems(it)
|
||||
val themes = mutableListOf(allThemeLabel)
|
||||
themes.addAll(it)
|
||||
themeAdapter.addItems(themes)
|
||||
}
|
||||
|
||||
viewModel.itemsLiveData.observe(this) { list ->
|
||||
|
||||
@@ -5,10 +5,12 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.home.AudioContentMainItem
|
||||
|
||||
class AudioContentAllViewModel(
|
||||
@@ -35,7 +37,7 @@ class AudioContentAllViewModel(
|
||||
private var page = 1
|
||||
private val size = 20
|
||||
private var isLast = false
|
||||
private var selectedTheme = "전체"
|
||||
private var selectedTheme = ""
|
||||
|
||||
fun reset() {
|
||||
page = 1
|
||||
@@ -46,6 +48,7 @@ class AudioContentAllViewModel(
|
||||
isFree: Boolean? = null,
|
||||
isPointAvailableOnly: Boolean? = null
|
||||
) {
|
||||
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
compositeDisposable.add(
|
||||
repository.getAudioContentActiveThemeList(
|
||||
isFree = isFree,
|
||||
@@ -57,15 +60,12 @@ class AudioContentAllViewModel(
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
val themeList = listOf("전체").union(it.data).toList()
|
||||
_themeListLiveData.postValue(themeList)
|
||||
_themeListLiveData.postValue(it.data)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class AudioContentAllViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -86,6 +86,7 @@ class AudioContentAllViewModel(
|
||||
) {
|
||||
if (_isLoading.value == true || isLast) return
|
||||
_isLoading.value = true
|
||||
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.getAllAudioContents(
|
||||
@@ -94,11 +95,7 @@ class AudioContentAllViewModel(
|
||||
isFree = isFree,
|
||||
isPointAvailableOnly = isPointAvailableOnly,
|
||||
sortType = _sortLiveData.value!!,
|
||||
theme = if (selectedTheme == "전체") {
|
||||
null
|
||||
} else {
|
||||
selectedTheme
|
||||
},
|
||||
theme = selectedTheme.ifBlank { null },
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -115,7 +112,7 @@ class AudioContentAllViewModel(
|
||||
_isLoading.value = false
|
||||
}, { t ->
|
||||
_isLoading.value = false
|
||||
_toastLiveData.postValue(t.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(t.message ?: unknownError)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
@@ -32,6 +33,7 @@ class AudioContentNewAllActivity : BaseActivity<ActivityAudioContentNewAllBindin
|
||||
|
||||
private lateinit var newContentThemeAdapter: HomeContentThemeAdapter
|
||||
private lateinit var newContentAdapter: AudioContentNewAllAdapter
|
||||
private val allThemeLabel by lazy { getString(R.string.screen_home_theme_all) }
|
||||
|
||||
private var isFree: Boolean = false
|
||||
|
||||
@@ -47,16 +49,16 @@ class AudioContentNewAllActivity : BaseActivity<ActivityAudioContentNewAllBindin
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.toolbar.tvBack.text = if (isFree) {
|
||||
"새로운 무료 콘텐츠"
|
||||
getString(R.string.screen_audio_content_new_all_title_free)
|
||||
} else {
|
||||
"새로운 단편"
|
||||
getString(R.string.screen_audio_content_new_all_title)
|
||||
}
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
binding.tvNotice.text = if (isFree) {
|
||||
"※ 최근 2주간 등록된 새로운 콘텐츠 입니다."
|
||||
getString(R.string.screen_audio_content_new_all_notice_free)
|
||||
} else {
|
||||
"※ 최근 2주간 등록된 새로운 단편 입니다."
|
||||
getString(R.string.screen_audio_content_new_all_notice)
|
||||
}
|
||||
|
||||
setupNewContentTheme()
|
||||
@@ -65,10 +67,11 @@ class AudioContentNewAllActivity : BaseActivity<ActivityAudioContentNewAllBindin
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun setupNewContentTheme() {
|
||||
newContentThemeAdapter = HomeContentThemeAdapter {
|
||||
newContentThemeAdapter = HomeContentThemeAdapter(allThemeLabel) { selectedTheme ->
|
||||
newContentAdapter.clear()
|
||||
newContentAdapter.notifyDataSetChanged()
|
||||
viewModel.selectTheme(it, isFree = isFree)
|
||||
val theme = if (selectedTheme == allThemeLabel) "" else selectedTheme
|
||||
viewModel.selectTheme(theme, isFree = isFree)
|
||||
}
|
||||
|
||||
binding.rvNewContentTheme.layoutManager = LinearLayoutManager(
|
||||
@@ -171,7 +174,9 @@ class AudioContentNewAllActivity : BaseActivity<ActivityAudioContentNewAllBindin
|
||||
}
|
||||
|
||||
viewModel.themeListLiveData.observe(this) {
|
||||
newContentThemeAdapter.addItems(it)
|
||||
val themes = mutableListOf(allThemeLabel)
|
||||
themes.addAll(it)
|
||||
newContentThemeAdapter.addItems(themes)
|
||||
}
|
||||
|
||||
viewModel.newContentListLiveData.observe(this) {
|
||||
|
||||
@@ -68,7 +68,7 @@ class AudioContentNewAllAdapter(
|
||||
binding.tvCan.text = item.price.moneyFormat()
|
||||
} else {
|
||||
binding.ivCan.visibility = View.GONE
|
||||
binding.tvCan.text = "무료"
|
||||
binding.tvCan.text = context.getString(R.string.audio_content_price_free)
|
||||
}
|
||||
|
||||
binding.tvTime.text = item.duration
|
||||
|
||||
@@ -8,7 +8,9 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AudioContentNewAllViewModel(
|
||||
private val repository: AudioContentRepository
|
||||
@@ -41,15 +43,12 @@ class AudioContentNewAllViewModel(
|
||||
fun getNewContentList(isFree: Boolean = false) {
|
||||
if (!_isLoading.value!! && !isLast) {
|
||||
_isLoading.value = true
|
||||
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.getNewContentAllOfTheme(
|
||||
isFree = isFree,
|
||||
theme = if (selectedTheme == "전체") {
|
||||
""
|
||||
} else {
|
||||
selectedTheme
|
||||
},
|
||||
theme = selectedTheme,
|
||||
page = page,
|
||||
size = size,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
@@ -71,9 +70,7 @@ class AudioContentNewAllViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +79,7 @@ class AudioContentNewAllViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -90,6 +87,7 @@ class AudioContentNewAllViewModel(
|
||||
}
|
||||
|
||||
fun getThemeList() {
|
||||
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
compositeDisposable.add(
|
||||
repository.getNewContentThemeList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -97,15 +95,12 @@ class AudioContentNewAllViewModel(
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
val themeList = listOf("전체").union(it.data).toList()
|
||||
_themeListLiveData.postValue(themeList)
|
||||
_themeListLiveData.postValue(it.data)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +109,7 @@ class AudioContentNewAllViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentThemeAdapter
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
@@ -37,7 +38,7 @@ class AudioContentRankingAllActivity : BaseActivity<ActivityAudioContentRankingA
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
binding.toolbar.tvBack.text = "인기 콘텐츠"
|
||||
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_ranking_title)
|
||||
|
||||
adapter = AudioContentRankingAllAdapter {
|
||||
val intent = Intent(applicationContext, AudioContentDetailActivity::class.java)
|
||||
|
||||
@@ -43,7 +43,7 @@ class AudioContentRankingAllAdapter(
|
||||
binding.tvNickname.text = item.creatorNickname
|
||||
|
||||
if (item.price < 1) {
|
||||
binding.tvPrice.text = "무료"
|
||||
binding.tvPrice.text = context.getString(R.string.audio_content_price_free)
|
||||
binding.tvPrice.setTextColor(ContextCompat.getColor(context, R.color.white))
|
||||
binding.tvPrice.setCompoundDrawables(null, null, null, null)
|
||||
binding.tvPrice.setPadding(
|
||||
|
||||
@@ -5,10 +5,12 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class AudioContentRankingAllViewModel(
|
||||
private val repository: AudioContentRepository
|
||||
@@ -37,11 +39,14 @@ class AudioContentRankingAllViewModel(
|
||||
private var pageSize = 10
|
||||
private var isLast = false
|
||||
|
||||
private var selectedSort = "매출"
|
||||
private var selectedSort =
|
||||
SodaLiveApplicationHolder.get().getString(R.string.screen_home_sort_revenue)
|
||||
|
||||
fun getAudioContentRanking() {
|
||||
if (!_isLoading.value!! && !isLast && page <= 5) {
|
||||
_isLoading.value = true
|
||||
val unknownError =
|
||||
SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
compositeDisposable.add(
|
||||
repository.getContentRanking(
|
||||
page = page,
|
||||
@@ -69,15 +74,13 @@ class AudioContentRankingAllViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -85,6 +88,7 @@ class AudioContentRankingAllViewModel(
|
||||
}
|
||||
|
||||
fun getAudioContentRankingSortType() {
|
||||
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
compositeDisposable.add(
|
||||
repository.getContentRankingSortType(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -97,15 +101,13 @@ class AudioContentRankingAllViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -38,7 +38,7 @@ class AudioContentAllByThemeActivity : BaseActivity<ActivityAudioContentAllByThe
|
||||
if (themeId <= 0) {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
"잘못된 요청입니다.\n다시 시도해 주세요.",
|
||||
getString(R.string.screen_audio_content_error_invalid_request_retry),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AudioContentAllByThemeViewModel(
|
||||
private val repository: AudioContentRepository
|
||||
@@ -61,7 +63,8 @@ class AudioContentAllByThemeViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -71,7 +74,10 @@ class AudioContentAllByThemeViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.box
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.widget.LinearLayout
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import kr.co.vividnext.sodalive.R
|
||||
@@ -37,14 +35,14 @@ class AudioContentBoxActivity : BaseActivity<ActivityAudioContentBoxBinding>(
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
binding.toolbar.tvBack.text = "내 보관함"
|
||||
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_box_title)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
}
|
||||
|
||||
private fun setupTabs() {
|
||||
val tabs = binding.tabs
|
||||
tabs.addTab(tabs.newTab().setText("구매목록"))
|
||||
tabs.addTab(tabs.newTab().setText("재생목록"))
|
||||
tabs.addTab(tabs.newTab().setText(R.string.screen_audio_content_box_tab_orders))
|
||||
tabs.addTab(tabs.newTab().setText(R.string.screen_audio_content_box_tab_playlists))
|
||||
|
||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemContentCategoryBinding
|
||||
|
||||
class AudioContentCategoryAdapter(
|
||||
private val allCategoryLabel: String,
|
||||
private val onClick: (Long) -> Unit
|
||||
) : RecyclerView.Adapter<AudioContentCategoryAdapter.ViewHolder>() {
|
||||
|
||||
@@ -24,7 +25,7 @@ class AudioContentCategoryAdapter(
|
||||
fun bind(item: GetCategoryListResponse) {
|
||||
if (
|
||||
item.category == selectedCategory ||
|
||||
(selectedCategory == "" && item.category == "전체")
|
||||
(selectedCategory.isEmpty() && item.category == allCategoryLabel)
|
||||
) {
|
||||
binding.tvCategory.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
|
||||
@@ -99,9 +99,12 @@ class AudioContentCommentAdapter(
|
||||
binding.tvCommentNickname.text = item.nickname
|
||||
|
||||
binding.tvWriteReply.text = if (item.replyCount > 0) {
|
||||
"답글 ${item.replyCount}개"
|
||||
context.getString(
|
||||
R.string.audio_content_comment_reply_count_format,
|
||||
item.replyCount
|
||||
)
|
||||
} else {
|
||||
"답글 쓰기"
|
||||
context.getString(R.string.audio_content_comment_write_reply)
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -106,9 +106,9 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
|
||||
SodaDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "댓글 삭제",
|
||||
desc = "삭제하시겠습니까?",
|
||||
confirmButtonTitle = "삭제",
|
||||
title = getString(R.string.audio_content_comment_delete_title),
|
||||
desc = getString(R.string.audio_content_comment_delete_message),
|
||||
confirmButtonTitle = getString(R.string.screen_audio_content_detail_delete),
|
||||
confirmButtonClick = {
|
||||
viewModel.modifyComment(
|
||||
commentId = it,
|
||||
@@ -116,7 +116,7 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
|
||||
isActive = false
|
||||
)
|
||||
},
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonTitle = getString(R.string.cancel),
|
||||
cancelButtonClick = {}
|
||||
).show(screenWidth)
|
||||
},
|
||||
|
||||
@@ -6,7 +6,9 @@ import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AudioContentCommentListViewModel(
|
||||
private val repository: AudioContentCommentRepository
|
||||
@@ -27,6 +29,17 @@ class AudioContentCommentListViewModel(
|
||||
val totalCommentCount: LiveData<Int>
|
||||
get() = _totalCommentCount
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
private val noChangeMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.audio_content_comment_no_change)
|
||||
|
||||
private val inputRequiredMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_comment_input_required
|
||||
)
|
||||
|
||||
var page = 1
|
||||
private var isLast = false
|
||||
private val size = 10
|
||||
@@ -59,9 +72,7 @@ class AudioContentCommentListViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
@@ -74,7 +85,7 @@ class AudioContentCommentListViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
@@ -110,16 +121,14 @@ class AudioContentCommentListViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -132,12 +141,12 @@ class AudioContentCommentListViewModel(
|
||||
isActive: Boolean? = null
|
||||
) {
|
||||
if (comment == null && isActive == null) {
|
||||
_toastLiveData.postValue("변경사항이 없습니다.")
|
||||
_toastLiveData.postValue(noChangeMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if (comment != null && comment.isBlank()) {
|
||||
_toastLiveData.postValue("내용을 입력하세요")
|
||||
_toastLiveData.postValue(inputRequiredMessage)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -169,14 +178,14 @@ class AudioContentCommentListViewModel(
|
||||
isLast = false
|
||||
getCommentList(audioContentId)
|
||||
} else {
|
||||
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = it.message ?: unknownErrorMessage
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -112,9 +112,9 @@ class AudioContentCommentReplyFragment : BaseFragment<FragmentAudioContentCommen
|
||||
SodaDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "댓글 삭제",
|
||||
desc = "삭제하시겠습니까?",
|
||||
confirmButtonTitle = "삭제",
|
||||
title = getString(R.string.audio_content_comment_delete_title),
|
||||
desc = getString(R.string.audio_content_comment_delete_message),
|
||||
confirmButtonTitle = getString(R.string.screen_audio_content_detail_delete),
|
||||
confirmButtonClick = {
|
||||
viewModel.modifyComment(
|
||||
commentId = it,
|
||||
@@ -122,7 +122,7 @@ class AudioContentCommentReplyFragment : BaseFragment<FragmentAudioContentCommen
|
||||
isActive = false
|
||||
)
|
||||
},
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonTitle = getString(R.string.cancel),
|
||||
cancelButtonClick = {}
|
||||
).show(screenWidth)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AudioContentCommentReplyViewModel(
|
||||
private val repository: AudioContentCommentRepository
|
||||
@@ -23,6 +25,17 @@ class AudioContentCommentReplyViewModel(
|
||||
val commentList: LiveData<List<GetAudioContentCommentListItem>>
|
||||
get() = _commentList
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
private val noChangeMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.audio_content_comment_no_change)
|
||||
|
||||
private val inputRequiredMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_comment_input_required
|
||||
)
|
||||
|
||||
var page = 1
|
||||
private var isLast = false
|
||||
private val size = 10
|
||||
@@ -53,9 +66,7 @@ class AudioContentCommentReplyViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
@@ -68,7 +79,7 @@ class AudioContentCommentReplyViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
@@ -104,16 +115,14 @@ class AudioContentCommentReplyViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -126,12 +135,12 @@ class AudioContentCommentReplyViewModel(
|
||||
isActive: Boolean? = null
|
||||
) {
|
||||
if (comment == null && isActive == null) {
|
||||
_toastLiveData.postValue("변경사항이 없습니다.")
|
||||
_toastLiveData.postValue(noChangeMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if (comment != null && comment.isBlank()) {
|
||||
_toastLiveData.postValue("내용을 입력하세요")
|
||||
_toastLiveData.postValue(inputRequiredMessage)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -163,14 +172,14 @@ class AudioContentCommentReplyViewModel(
|
||||
isLast = false
|
||||
getCommentReplyList(parentCommentId)
|
||||
} else {
|
||||
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = it.message ?: unknownErrorMessage
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.LayoutInflater
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.DialogAudioContentDeleteBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
|
||||
@@ -31,7 +32,10 @@ class AudioContentDeleteDialog(
|
||||
alertDialog.setCancelable(false)
|
||||
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
|
||||
dialogView.tvTitle.text = "[$title]을 삭제하시겠습니까?"
|
||||
dialogView.tvTitle.text = activity.getString(
|
||||
R.string.screen_audio_content_detail_delete_confirm_message,
|
||||
title
|
||||
)
|
||||
dialogView.tvCancel.setOnClickListener {
|
||||
alertDialog.dismiss()
|
||||
}
|
||||
@@ -43,7 +47,9 @@ class AudioContentDeleteDialog(
|
||||
} else {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"동의하셔야 삭제할 수 있습니다.",
|
||||
activity.getString(
|
||||
R.string.screen_audio_content_detail_delete_consent_required
|
||||
),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import kr.co.vividnext.sodalive.base.SodaDialog
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.Utils
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
|
||||
@@ -94,8 +95,13 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
binding.scrollView.scrollTo(0, 0)
|
||||
binding.sbProgress.progress = 0
|
||||
binding.ivPlayOrPause.setImageResource(0)
|
||||
binding.tvTotalDuration.text = " / 00:00:00"
|
||||
binding.tvCurrentDuration.text = "00:00:00"
|
||||
binding.ivPlayOrPause.visibility = View.GONE
|
||||
binding.llPreview.visibility = View.GONE
|
||||
binding.tvTotalDuration.text = getString(
|
||||
R.string.screen_audio_content_detail_time_total_default
|
||||
)
|
||||
binding.tvCurrentDuration.text =
|
||||
getString(R.string.screen_audio_content_detail_time_default)
|
||||
binding.rlPreviewAlert.visibility = View.GONE
|
||||
|
||||
audioContentId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
|
||||
@@ -109,7 +115,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
if (audioContentId <= 0) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.screen_audio_content_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -148,7 +158,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.tvBack.text = "콘텐츠 상세"
|
||||
binding.tvBack.text = getString(R.string.screen_audio_content_detail_title)
|
||||
binding.tvBack.setOnClickListener { finish() }
|
||||
binding.ivClosePreviewAlert.setOnClickListener { viewModel.toggleShowPreviewAlert() }
|
||||
binding.ivMenu.setOnClickListener {
|
||||
@@ -292,9 +302,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
LayoutInflater.from(this)
|
||||
) { can, message, _ ->
|
||||
if (can <= 0) {
|
||||
showToast("1캔 이상 후원하실 수 있습니다.")
|
||||
showToast(getString(R.string.screen_audio_content_detail_donation_minimum))
|
||||
} else if (message.isBlank()) {
|
||||
showToast("함께 보낼 메시지를 입력하세요.")
|
||||
showToast(
|
||||
getString(R.string.screen_audio_content_detail_donation_empty_message)
|
||||
)
|
||||
} else {
|
||||
donation(can, message)
|
||||
}
|
||||
@@ -355,13 +367,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
SodaDialog(
|
||||
this@AudioContentDetailActivity,
|
||||
layoutInflater,
|
||||
"고정 한도 도달",
|
||||
"이 콘텐츠를 고정하시겠어요? " +
|
||||
"채널에 콘텐츠를 최대 3개까지 고정할 수 있습니다." +
|
||||
"이 콘텐츠를 고정하면 가장 오래된 콘텐츠가 대체됩니다.",
|
||||
"확인",
|
||||
getString(R.string.screen_audio_content_detail_pin_limit_title),
|
||||
getString(R.string.screen_audio_content_detail_pin_limit_message),
|
||||
getString(R.string.confirm),
|
||||
{ viewModel.pinContent(audioContentId) },
|
||||
"취소",
|
||||
getString(R.string.cancel),
|
||||
{}
|
||||
).show(screenWidth)
|
||||
}
|
||||
@@ -446,7 +456,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
}
|
||||
)
|
||||
|
||||
title = it.title
|
||||
title = it.translated?.title ?: it.title
|
||||
setupCreatorArea(it.creator)
|
||||
setupMosaicArea(it.isMosaic)
|
||||
setupPlayArea(it)
|
||||
@@ -694,28 +704,31 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
}
|
||||
|
||||
binding.tvUnit.text = if (SharedPreferenceManager.userId == 17958L) {
|
||||
"원으로"
|
||||
getString(R.string.screen_audio_content_detail_purchase_unit_won)
|
||||
} else {
|
||||
"캔으로"
|
||||
getString(R.string.screen_audio_content_detail_purchase_unit_can)
|
||||
}
|
||||
|
||||
when (response.purchaseOption) {
|
||||
PurchaseOption.BOTH -> {
|
||||
binding.tvStrPurchaseOrRental.text = " 구매하기"
|
||||
binding.tvStrPurchaseOrRental.text =
|
||||
getString(R.string.screen_audio_content_detail_action_buy)
|
||||
binding.llPurchase.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_5_3_3bb9f1
|
||||
)
|
||||
}
|
||||
|
||||
PurchaseOption.BUY_ONLY -> {
|
||||
binding.tvStrPurchaseOrRental.text = " 소장하기"
|
||||
binding.tvStrPurchaseOrRental.text =
|
||||
getString(R.string.screen_audio_content_detail_action_keep)
|
||||
binding.llPurchase.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_5_3_59548f
|
||||
)
|
||||
}
|
||||
|
||||
PurchaseOption.RENT_ONLY -> {
|
||||
binding.tvStrPurchaseOrRental.text = " 대여하기"
|
||||
binding.tvStrPurchaseOrRental.text =
|
||||
getString(R.string.screen_audio_content_detail_action_rental)
|
||||
binding.llPurchase.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_5_3_548f7d
|
||||
)
|
||||
@@ -754,10 +767,14 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
binding.flSoldOut.visibility = View.GONE
|
||||
binding.tvSoldOutBig.visibility = View.GONE
|
||||
binding.ivPlayOrPause.visibility = View.GONE
|
||||
binding.llPreview.visibility = View.GONE
|
||||
binding.ivSeekBackward10.visibility = View.GONE
|
||||
binding.ivSeekForward10.visibility = View.GONE
|
||||
binding.tvPreviewNo.visibility = View.GONE
|
||||
binding.tvTotalDuration.text = " / ${response.duration}"
|
||||
binding.llPreviewNo.visibility = View.GONE
|
||||
binding.tvTotalDuration.text = getString(
|
||||
R.string.screen_audio_content_detail_total_duration_format,
|
||||
response.duration
|
||||
)
|
||||
|
||||
isAlertPreview = response.creator.creatorId != SharedPreferenceManager.userId &&
|
||||
!response.existOrdered &&
|
||||
@@ -775,8 +792,13 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
!isAlertPreview ||
|
||||
(response.isActivePreview && response.contentUrl.isNotBlank())
|
||||
) {
|
||||
if (isAlertPreview) {
|
||||
binding.llPreview.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.ivPlayOrPause.visibility = View.VISIBLE
|
||||
binding.ivPlayOrPause.setOnClickListener {
|
||||
}
|
||||
|
||||
val playClickAction = View.OnClickListener {
|
||||
startService(
|
||||
Intent(
|
||||
applicationContext,
|
||||
@@ -820,13 +842,9 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
)
|
||||
}
|
||||
|
||||
binding.ivPlayOrPause.setImageResource(
|
||||
if (!isAlertPreview) {
|
||||
R.drawable.btn_audio_content_play
|
||||
} else {
|
||||
R.drawable.btn_audio_content_preview_play
|
||||
}
|
||||
)
|
||||
binding.ivPlayOrPause.setImageResource(R.drawable.btn_audio_content_play)
|
||||
binding.ivPlayOrPause.setOnClickListener(playClickAction)
|
||||
binding.llPreview.setOnClickListener(playClickAction)
|
||||
|
||||
if (!isAlertPreview) {
|
||||
binding.ivSeekForward10.visibility = View.VISIBLE
|
||||
@@ -855,7 +873,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
}
|
||||
}
|
||||
} else if (response.releaseDate == null) {
|
||||
binding.tvPreviewNo.visibility = View.VISIBLE
|
||||
binding.llPreviewNo.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
binding.ivPoint.visibility = if (response.isAvailableUsePoint) {
|
||||
@@ -894,13 +912,13 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
binding.tvRemainingTime.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.tvTitle.text = response.title
|
||||
binding.tvDetail.text = response.detail
|
||||
binding.tvTitle.text = response.translated?.title ?: response.title
|
||||
binding.tvDetail.text = response.translated?.detail ?: response.detail
|
||||
binding.tvDetail.setOnClickListener { viewModel.toggleExpandDetail() }
|
||||
|
||||
if (response.tag.isNotBlank()) {
|
||||
binding.tvTag.visibility = View.VISIBLE
|
||||
binding.tvTag.text = response.tag
|
||||
binding.tvTag.text = response.translated?.tags ?: response.tag
|
||||
} else {
|
||||
binding.tvTag.visibility = View.GONE
|
||||
}
|
||||
@@ -925,7 +943,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_pressed)
|
||||
} else {
|
||||
binding.tvLike.text = if (likeCount - 1 < 0) {
|
||||
"0"
|
||||
SodaLiveApplicationHolder.get().getString(R.string.common_zero)
|
||||
} else {
|
||||
"${likeCount - 1}"
|
||||
}
|
||||
@@ -941,7 +959,10 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
intent.type = "text/plain"
|
||||
intent.putExtra(Intent.EXTRA_TEXT, it)
|
||||
|
||||
val shareIntent = Intent.createChooser(intent, "오디오 콘텐츠 공유")
|
||||
val shareIntent = Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.screen_audio_content_detail_share_title)
|
||||
)
|
||||
startActivity(shareIntent)
|
||||
}
|
||||
}
|
||||
@@ -1203,23 +1224,29 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||
if (this@AudioContentDetailActivity.audioContentId == contentId) {
|
||||
runOnUiThread {
|
||||
if (changeUi != null && changeUi) {
|
||||
binding.ivPlayOrPause.setImageResource(
|
||||
if (isPlaying != null && isPlaying) {
|
||||
R.drawable.btn_audio_content_pause
|
||||
binding.ivPlayOrPause.visibility = View.VISIBLE
|
||||
binding.llPreview.visibility = View.GONE
|
||||
binding.ivPlayOrPause.setImageResource(R.drawable.btn_audio_content_pause)
|
||||
} else {
|
||||
if (isAlertPreview) {
|
||||
R.drawable.btn_audio_content_preview_play
|
||||
binding.ivPlayOrPause.visibility = View.GONE
|
||||
binding.llPreview.visibility = View.VISIBLE
|
||||
} else {
|
||||
R.drawable.btn_audio_content_play
|
||||
binding.ivPlayOrPause.visibility = View.VISIBLE
|
||||
binding.llPreview.visibility = View.GONE
|
||||
binding.ivPlayOrPause.setImageResource(R.drawable.btn_audio_content_play)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (duration != null && duration > 0) {
|
||||
binding.sbProgress.max = duration
|
||||
binding.tvTotalDuration.text = " / ${Utils.convertDurationToString(duration)}"
|
||||
binding.tvTotalDuration.text = getString(
|
||||
R.string.screen_audio_content_detail_total_duration_format,
|
||||
Utils.convertDurationToString(duration)
|
||||
)
|
||||
}
|
||||
|
||||
if (progress != null && progress > 0) {
|
||||
|
||||
@@ -36,10 +36,11 @@ class AudioContentDetailMenuBottomSheetDialog(
|
||||
|
||||
if (isPin) {
|
||||
dialog.ivPin.setImageResource(R.drawable.ic_pin_cancel)
|
||||
dialog.tvPin.text = "내 채널에 고정 취소"
|
||||
dialog.tvPin.text =
|
||||
getString(R.string.screen_audio_content_detail_pin_cancel)
|
||||
} else {
|
||||
dialog.ivPin.setImageResource(R.drawable.ic_pin)
|
||||
dialog.tvPin.text = "내 채널에 고정"
|
||||
dialog.tvPin.text = getString(R.string.screen_audio_content_detail_pin)
|
||||
}
|
||||
|
||||
dialog.llPin.setOnClickListener {
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.detail
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.order.OrderType
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.Utils
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.mypage.auth.AuthRepository
|
||||
@@ -52,7 +55,13 @@ class AudioContentDetailViewModel(
|
||||
val isContentPlayLoopLiveData: LiveData<Boolean>
|
||||
get() = _isContentPlayLoopLiveData
|
||||
|
||||
fun getAudioContentDetail(audioContentId: Long, onFailure: (() -> Unit)? = null) {
|
||||
private fun getString(@StringRes resId: Int, vararg args: Any) =
|
||||
SodaLiveApplicationHolder.get().getString(resId, *args)
|
||||
|
||||
fun getAudioContentDetail(
|
||||
audioContentId: Long,
|
||||
onFailure: (() -> Unit)? = null
|
||||
) {
|
||||
if (!isLoading.value!!) {
|
||||
isLoading.value = true
|
||||
}
|
||||
@@ -73,7 +82,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,7 +96,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
@@ -116,7 +125,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -125,7 +134,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -155,9 +164,13 @@ class AudioContentDetailViewModel(
|
||||
getAudioContentDetail(audioContentId = contentId)
|
||||
_toastLiveData.postValue(
|
||||
if (orderType == OrderType.RENTAL) {
|
||||
"대여가 완료되었습니다."
|
||||
getString(
|
||||
R.string.screen_audio_content_detail_order_rental_success
|
||||
)
|
||||
} else {
|
||||
"구매가 완료되었습니다."
|
||||
getString(
|
||||
R.string.screen_audio_content_detail_order_keep_success
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
@@ -168,7 +181,7 @@ class AudioContentDetailViewModel(
|
||||
}
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -177,7 +190,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -201,7 +214,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -211,7 +224,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -240,7 +253,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -250,7 +263,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -283,7 +296,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -291,7 +304,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -327,7 +340,7 @@ class AudioContentDetailViewModel(
|
||||
|
||||
if (it.success) {
|
||||
_toastLiveData.postValue(
|
||||
"삭제되었습니다."
|
||||
getString(R.string.screen_audio_content_detail_delete_success)
|
||||
)
|
||||
onSuccess()
|
||||
} else {
|
||||
@@ -335,7 +348,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -343,7 +356,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -365,7 +378,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"신고가 접수되었습니다."
|
||||
getString(R.string.screen_audio_content_detail_report_submitted)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -374,7 +387,9 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("신고가 접수되었습니다.")
|
||||
_toastLiveData.postValue(
|
||||
getString(R.string.screen_audio_content_detail_report_submitted)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -404,7 +419,10 @@ class AudioContentDetailViewModel(
|
||||
if (it.success) {
|
||||
SharedPreferenceManager.can -= can
|
||||
_toastLiveData.postValue(
|
||||
"${can.moneyFormat()}캔을 후원하였습니다."
|
||||
getString(
|
||||
R.string.screen_audio_content_detail_donation_success,
|
||||
can.moneyFormat()
|
||||
)
|
||||
)
|
||||
onSuccess()
|
||||
} else {
|
||||
@@ -412,7 +430,7 @@ class AudioContentDetailViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -420,7 +438,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -440,14 +458,16 @@ class AudioContentDetailViewModel(
|
||||
isLoading.value = false
|
||||
|
||||
if (it.success) {
|
||||
_toastLiveData.postValue("고정되었습니다.")
|
||||
_toastLiveData.postValue(
|
||||
getString(R.string.screen_audio_content_detail_pin_success)
|
||||
)
|
||||
getAudioContentDetail(audioContentId)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -455,7 +475,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -475,14 +495,16 @@ class AudioContentDetailViewModel(
|
||||
isLoading.value = false
|
||||
|
||||
if (it.success) {
|
||||
_toastLiveData.postValue("해제되었습니다.")
|
||||
_toastLiveData.postValue(
|
||||
getString(R.string.screen_audio_content_detail_unpin_success)
|
||||
)
|
||||
getAudioContentDetail(audioContentId)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -490,7 +512,7 @@ class AudioContentDetailViewModel(
|
||||
{
|
||||
isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(getString(R.string.common_error_unknown))
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.WindowManager
|
||||
import android.widget.RadioButton
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.DialogAudioContentReportBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
|
||||
@@ -37,7 +38,13 @@ class AudioContentReportDialog(
|
||||
alertDialog.dismiss()
|
||||
confirmButtonClick(reason)
|
||||
} else {
|
||||
Toast.makeText(activity, "신고 이유를 선택하세요.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
activity,
|
||||
activity.getString(
|
||||
R.string.screen_audio_content_detail_report_reason_required
|
||||
),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ data class GetAudioContentDetailResponse(
|
||||
@SerializedName("previousContent") val previousContent: OtherContentResponse?,
|
||||
@SerializedName("nextContent") val nextContent: OtherContentResponse?,
|
||||
@SerializedName("buyerList") val buyerList: List<ContentBuyer>,
|
||||
@SerializedName("isAvailableUsePoint") val isAvailableUsePoint: Boolean
|
||||
@SerializedName("isAvailableUsePoint") val isAvailableUsePoint: Boolean,
|
||||
@SerializedName("translated") val translated: TranslatedContent?
|
||||
)
|
||||
|
||||
@Keep
|
||||
@@ -68,3 +69,10 @@ data class ContentBuyer(
|
||||
@SerializedName("nickname") val nickname: String,
|
||||
@SerializedName("profileImageUrl") val profileImageUrl: String
|
||||
)
|
||||
|
||||
@Keep
|
||||
data class TranslatedContent(
|
||||
@SerializedName("title") val title: String?,
|
||||
@SerializedName("detail") val detail: String?,
|
||||
@SerializedName("tags") val tags: String?
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainNewContentThemeBinding
|
||||
|
||||
class AudioContentMainNewContentThemeAdapter(
|
||||
@@ -24,8 +25,10 @@ class AudioContentMainNewContentThemeAdapter(
|
||||
fun bind(theme: String) {
|
||||
if (
|
||||
theme == selectedTheme ||
|
||||
(selectedTheme == "" && theme == "전체") ||
|
||||
(selectedTheme == "" && theme == "매출")
|
||||
(selectedTheme == "" && theme == SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.audio_content_label_all)) ||
|
||||
(selectedTheme == "" && theme == SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.screen_home_sort_revenue))
|
||||
) {
|
||||
binding.tvTheme.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
|
||||
@@ -25,6 +25,7 @@ import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.ImagePickerCropper
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.RealPathUtil
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentModifyBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
@@ -42,7 +43,12 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||
super.onCreate(savedInstanceState)
|
||||
val audioContentId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
|
||||
if (audioContentId <= 0) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.screen_audio_content_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,11 @@ import com.google.gson.Gson
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
@@ -111,7 +113,8 @@ class AudioContentModifyViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -125,7 +128,10 @@ class AudioContentModifyViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
@@ -201,7 +207,8 @@ class AudioContentModifyViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -211,7 +218,8 @@ class AudioContentModifyViewModel(
|
||||
_isLoading.postValue(false)
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -221,12 +229,18 @@ class AudioContentModifyViewModel(
|
||||
|
||||
private fun validateData(): Boolean {
|
||||
if (title != null && title!!.isBlank()) {
|
||||
_toastLiveData.postValue("제목을 입력해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.audio_content_upload_error_title_required)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (detail != null && (detail!!.isBlank() || detail!!.length < 5)) {
|
||||
_toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.audio_content_upload_error_detail_min_length)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.order
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
@@ -17,7 +16,6 @@ import kr.co.vividnext.sodalive.databinding.DialogAudioContentOrderConfirmBindin
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
class AudioContentOrderConfirmDialog(
|
||||
activity: Activity,
|
||||
layoutInflater: LayoutInflater,
|
||||
@@ -38,6 +36,7 @@ class AudioContentOrderConfirmDialog(
|
||||
val dialogView = DialogAudioContentOrderConfirmBinding.inflate(layoutInflater)
|
||||
|
||||
init {
|
||||
val context = dialogView.root.context
|
||||
val dialogBuilder = AlertDialog.Builder(activity)
|
||||
dialogBuilder.setView(dialogView.root)
|
||||
|
||||
@@ -82,7 +81,10 @@ class AudioContentOrderConfirmDialog(
|
||||
dialogView.tvPoint.visibility = View.GONE
|
||||
dialogView.tvPlus.visibility = View.GONE
|
||||
dialogView.ivCan.visibility = View.GONE
|
||||
dialogView.tvCan.text = "${(price * 110).moneyFormat()}원"
|
||||
dialogView.tvCan.text = context.getString(
|
||||
R.string.audio_content_order_price_won_format,
|
||||
(price * 110).moneyFormat()
|
||||
)
|
||||
} else {
|
||||
if (usablePoint > 0) {
|
||||
dialogView.ivPoint.visibility = View.VISIBLE
|
||||
@@ -111,19 +113,19 @@ class AudioContentOrderConfirmDialog(
|
||||
}
|
||||
}
|
||||
|
||||
if (SharedPreferenceManager.userId == 17958L) {
|
||||
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||
"콘텐츠를 대여하시겠습니까?"
|
||||
} else {
|
||||
"콘텐츠를 소장하시겠습니까?"
|
||||
}
|
||||
} else {
|
||||
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||
"콘텐츠를 대여하시겠습니까?\n아래 금액이 차감됩니다."
|
||||
} else {
|
||||
"콘텐츠를 소장하시겠습니까?\n아래 금액이 차감됩니다."
|
||||
}
|
||||
val noticeResId = when {
|
||||
SharedPreferenceManager.userId == 17958L && orderType == OrderType.RENTAL ->
|
||||
R.string.audio_content_order_confirm_notice_rental_simple
|
||||
|
||||
SharedPreferenceManager.userId == 17958L && orderType == OrderType.KEEP ->
|
||||
R.string.audio_content_order_confirm_notice_keep_simple
|
||||
|
||||
orderType == OrderType.RENTAL ->
|
||||
R.string.audio_content_order_confirm_notice_rental
|
||||
|
||||
else -> R.string.audio_content_order_confirm_notice_keep
|
||||
}
|
||||
dialogView.tvNotice.text = dialogView.root.context.getString(noticeResId)
|
||||
|
||||
dialogView.tvCancel.setOnClickListener {
|
||||
alertDialog.dismiss()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.order
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentOrderBinding
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
@@ -28,23 +28,31 @@ class AudioContentOrderFragment(
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val context = requireContext()
|
||||
if (SharedPreferenceManager.userId == 17958L) {
|
||||
binding.tvKeepDate.text = "(이용기간 1년)"
|
||||
binding.tvKeepDate.text =
|
||||
context.getString(R.string.audio_content_order_keep_period_special)
|
||||
binding.ivKeepCan.visibility = View.GONE
|
||||
binding.ivRentalCan.visibility = View.GONE
|
||||
} else {
|
||||
binding.tvKeepDate.text = "(서비스 종료시까지)"
|
||||
binding.tvKeepDate.text =
|
||||
context.getString(R.string.audio_content_order_keep_period_default)
|
||||
binding.ivKeepCan.visibility = View.VISIBLE
|
||||
binding.ivRentalCan.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (SharedPreferenceManager.userId == 17958L) {
|
||||
binding.tvKeep.text = "${(price * 110).moneyFormat()}원"
|
||||
binding.tvRental.text = "${(ceil(price * 0.7).toInt() * 110).moneyFormat()}원"
|
||||
binding.tvKeep.text = context.getString(
|
||||
R.string.audio_content_order_price_won_format,
|
||||
(price * 110).moneyFormat()
|
||||
)
|
||||
binding.tvRental.text = context.getString(
|
||||
R.string.audio_content_order_price_won_format,
|
||||
(ceil(price * 0.7).toInt() * 110).moneyFormat()
|
||||
)
|
||||
} else {
|
||||
binding.tvKeep.text = price.moneyFormat()
|
||||
binding.tvRental.text = ceil(price * 0.7).toInt().moneyFormat()
|
||||
|
||||
@@ -33,7 +33,7 @@ class AudioContentOrderListActivity : BaseActivity<ActivityAudioContentOrderList
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
binding.toolbar.tvBack.text = "콘텐츠 보관함"
|
||||
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_order_title)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ class AudioContentOrderListFragment : BaseFragment<FragmentAudioContentOrderList
|
||||
}
|
||||
|
||||
viewModel.totalCount.observe(viewLifecycleOwner) {
|
||||
binding.tvTotalCount.text = "$it"
|
||||
binding.tvTotalCount.text = it.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class AudioContentOrderListViewModel(
|
||||
@@ -34,6 +36,7 @@ class AudioContentOrderListViewModel(
|
||||
private val size = 10
|
||||
|
||||
fun getAudioContentOrderList(onFailure: (() -> Unit)? = null) {
|
||||
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
if (_isLoading.value == false) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
@@ -59,9 +62,7 @@ class AudioContentOrderListViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownError)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
@@ -73,7 +74,7 @@ class AudioContentOrderListViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownError)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ class AudioContentPlayerFragment(
|
||||
if (mediaController == null) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
"플레이어를 실행하지 못했습니다.\n다시 시도해 주세요.",
|
||||
getString(R.string.audio_content_player_error_launch_failed),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
dismiss()
|
||||
|
||||
@@ -7,9 +7,9 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemPlaylistListBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AudioContentPlaylistListAdapter(
|
||||
private val onClickItem: (Long) -> Unit
|
||||
@@ -20,7 +20,6 @@ class AudioContentPlaylistListAdapter(
|
||||
inner class ViewHolder(
|
||||
private val binding: ItemPlaylistListBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(item: GetPlaylistsItem) {
|
||||
binding.ivCover.load(item.coverImageUrl) {
|
||||
crossfade(true)
|
||||
@@ -29,7 +28,10 @@ class AudioContentPlaylistListAdapter(
|
||||
}
|
||||
|
||||
binding.tvTitle.text = item.title
|
||||
binding.tvContentCount.text = "총 ${item.contentCount}개"
|
||||
binding.tvContentCount.text = binding.root.context.getString(
|
||||
R.string.audio_content_playlist_content_count,
|
||||
item.contentCount
|
||||
)
|
||||
|
||||
if (item.desc.isNotBlank()) {
|
||||
binding.tvDesc.text = item.desc
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.playlist
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.create.AudioContentPlaylistCreateActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
@@ -43,6 +45,7 @@ class AudioContentPlaylistListFragment : BaseFragment<FragmentAudioContentPlayli
|
||||
viewModel.getPlaylistList()
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
private fun setupView() {
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
adapter = AudioContentPlaylistListAdapter { playlistId ->
|
||||
@@ -107,7 +110,6 @@ class AudioContentPlaylistListFragment : BaseFragment<FragmentAudioContentPlayli
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindData() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
@@ -122,7 +124,8 @@ class AudioContentPlaylistListFragment : BaseFragment<FragmentAudioContentPlayli
|
||||
}
|
||||
|
||||
viewModel.totalCountLiveData.observe(viewLifecycleOwner) {
|
||||
binding.tvTotalCount.text = "${it}개"
|
||||
binding.tvTotalCount.text =
|
||||
getString(R.string.audio_content_playlist_total_count, it)
|
||||
}
|
||||
|
||||
viewModel.playlistLiveData.observe(viewLifecycleOwner) {
|
||||
|
||||
@@ -5,8 +5,10 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class AudioContentPlaylistListViewModel(
|
||||
private val repository: AudioContentPlaylistRepository
|
||||
@@ -44,7 +46,8 @@ class AudioContentPlaylistListViewModel(
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -52,7 +55,10 @@ class AudioContentPlaylistListViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.playlist.create
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Service
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
@@ -11,10 +10,12 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.create.add_content.PlaylistAddContentDialogFragment
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentPlaylistCreateBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
@@ -39,7 +40,8 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
|
||||
title = item.title,
|
||||
category = item.themeStr,
|
||||
coverUrl = item.coverImageUrl,
|
||||
duration = item.duration ?: "00:00:00",
|
||||
duration = item.duration ?: SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.screen_audio_content_upload_preview_start_time_default),
|
||||
creatorNickname = item.creatorNickname,
|
||||
creatorProfileUrl = ""
|
||||
)
|
||||
@@ -70,7 +72,8 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
binding.tvBack.text = "새 재생목록 만들기"
|
||||
binding.tvBack.text = getString(R.string.audio_content_playlist_create_title)
|
||||
binding.tvSave.text = getString(R.string.audio_content_playlist_create_save)
|
||||
binding.tvBack.setOnClickListener { finish() }
|
||||
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
@@ -153,8 +156,8 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it.length > 30) {
|
||||
val truncated = it.take(30)
|
||||
if (it.length > PLAYLIST_TITLE_MAX_LENGTH) {
|
||||
val truncated = it.take(PLAYLIST_TITLE_MAX_LENGTH)
|
||||
binding.etTitle.setText(truncated)
|
||||
binding.etTitle.setSelection(truncated.length)
|
||||
setTitle(truncated)
|
||||
@@ -171,8 +174,8 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it.length > 40) {
|
||||
val truncated = it.take(40)
|
||||
if (it.length > PLAYLIST_DESC_MAX_LENGTH) {
|
||||
val truncated = it.take(PLAYLIST_DESC_MAX_LENGTH)
|
||||
binding.etDesc.setText(truncated)
|
||||
binding.etDesc.setSelection(truncated.length)
|
||||
setDesc(truncated)
|
||||
@@ -183,15 +186,26 @@ class AudioContentPlaylistCreateActivity : BaseActivity<ActivityAudioContentPlay
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setTitle(title: String) {
|
||||
binding.tvTitleLength.text = "${title.length}/30"
|
||||
binding.tvTitleLength.text = getString(
|
||||
R.string.audio_content_playlist_create_length_format,
|
||||
title.length,
|
||||
PLAYLIST_TITLE_MAX_LENGTH
|
||||
)
|
||||
viewModel.title = title
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setDesc(desc: String) {
|
||||
binding.tvDescLength.text = "${desc.length}/40"
|
||||
binding.tvDescLength.text = getString(
|
||||
R.string.audio_content_playlist_create_length_format,
|
||||
desc.length,
|
||||
PLAYLIST_DESC_MAX_LENGTH
|
||||
)
|
||||
viewModel.desc = desc
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val PLAYLIST_TITLE_MAX_LENGTH = 30
|
||||
private const val PLAYLIST_DESC_MAX_LENGTH = 40
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.AudioContentPlaylistRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class AudioContentPlaylistCreateViewModel(
|
||||
private val repository: AudioContentPlaylistRepository
|
||||
@@ -41,6 +43,8 @@ class AudioContentPlaylistCreateViewModel(
|
||||
|
||||
fun savePlaylist(onSuccess: () -> Unit) {
|
||||
if (validate()) {
|
||||
val unknownError =
|
||||
SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
_isLoading.value = true
|
||||
val contentIdAndOrderList = contentList.mapIndexed { index, item ->
|
||||
PlaylistContentIdAndOrder(item.id, index + 1)
|
||||
@@ -66,7 +70,7 @@ class AudioContentPlaylistCreateViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownError
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -75,7 +79,7 @@ class AudioContentPlaylistCreateViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownError
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -84,16 +88,27 @@ class AudioContentPlaylistCreateViewModel(
|
||||
}
|
||||
|
||||
private fun validate(): Boolean {
|
||||
if (title.isBlank() || title.length < 3) {
|
||||
_toastLiveData.value = "제목을 3자 이상 입력하세요"
|
||||
if (title.isBlank() || title.length < MIN_TITLE_LENGTH) {
|
||||
_toastLiveData.value = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_playlist_create_title_min_length_error,
|
||||
MIN_TITLE_LENGTH
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (contentList.isEmpty()) {
|
||||
_toastLiveData.value = "콘텐츠를 1개 이상 추가하세요"
|
||||
_toastLiveData.value = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_playlist_create_content_min_count_error,
|
||||
MIN_CONTENT_COUNT
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val MIN_TITLE_LENGTH = 3
|
||||
private const val MIN_CONTENT_COUNT = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
|
||||
@@ -148,7 +149,7 @@ class PlaylistAddContentDialogFragment(
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show()
|
||||
@@ -175,7 +176,10 @@ class PlaylistAddContentDialogFragment(
|
||||
}
|
||||
|
||||
viewModel.totalCount.observe(viewLifecycleOwner) {
|
||||
binding.tvContentCount.text = "${it}개"
|
||||
binding.tvContentCount.text = getString(
|
||||
R.string.audio_content_playlist_total_count,
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,8 +173,9 @@ class AudioContentPlaylistDetailActivity : BaseActivity<ActivityAudioContentPlay
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (playlistId <= 0) {
|
||||
showToast("잘못된 요청입니다.")
|
||||
showToast(getString(R.string.screen_audio_content_error_invalid_request))
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
bindData()
|
||||
@@ -283,16 +284,19 @@ class AudioContentPlaylistDetailActivity : BaseActivity<ActivityAudioContentPlay
|
||||
SodaDialog(
|
||||
activity = this@AudioContentPlaylistDetailActivity,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "재생 목록 삭제",
|
||||
desc = "'${binding.tvTitle.text}'을 삭제하시겠습니까?",
|
||||
confirmButtonTitle = "삭제",
|
||||
title = getString(R.string.audio_content_playlist_detail_delete_title),
|
||||
desc = getString(
|
||||
R.string.audio_content_playlist_detail_delete_message,
|
||||
binding.tvTitle.text
|
||||
),
|
||||
confirmButtonTitle = getString(R.string.screen_audio_content_detail_delete),
|
||||
confirmButtonClick = {
|
||||
viewModel.deletePlaylist(playlistId = playlistId) {
|
||||
setResult(RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
},
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonTitle = getString(R.string.cancel),
|
||||
cancelButtonClick = {}
|
||||
).show(screenWidth)
|
||||
}
|
||||
@@ -319,8 +323,14 @@ class AudioContentPlaylistDetailActivity : BaseActivity<ActivityAudioContentPlay
|
||||
viewModel.detailResponseLiveData.observe(this) {
|
||||
binding.tvDesc.text = it.desc
|
||||
binding.tvTitle.text = it.title
|
||||
binding.tvContentCount.text = " ${it.contentCount}개"
|
||||
binding.tvCreateDate.text = "만든 날짜 ${it.createdDate} "
|
||||
binding.tvContentCount.text = getString(
|
||||
R.string.audio_content_playlist_total_count,
|
||||
it.contentCount
|
||||
)
|
||||
binding.tvCreateDate.text = getString(
|
||||
R.string.audio_content_playlist_detail_created_date,
|
||||
it.createdDate
|
||||
)
|
||||
adapter.updateItems(it.contentList)
|
||||
this.contentList.clear()
|
||||
this.contentList.addAll(it.contentList)
|
||||
|
||||
@@ -7,6 +7,8 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.AudioContentPlaylistRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class AudioContentPlaylistDetailViewModel(
|
||||
@@ -24,6 +26,14 @@ class AudioContentPlaylistDetailViewModel(
|
||||
val detailResponseLiveData: LiveData<GetPlaylistDetailResponse>
|
||||
get() = _detailResponseLiveData
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
private val deleteSuccessMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_playlist_detail_delete_success
|
||||
)
|
||||
|
||||
fun getPlaylistDetail(playlistId: Long) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
@@ -41,9 +51,7 @@ class AudioContentPlaylistDetailViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
}
|
||||
_isLoading.value = false
|
||||
@@ -51,7 +59,7 @@ class AudioContentPlaylistDetailViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -69,15 +77,13 @@ class AudioContentPlaylistDetailViewModel(
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success) {
|
||||
_toastLiveData.value = "삭제되었습니다."
|
||||
_toastLiveData.value = deleteSuccessMessage
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
}
|
||||
_isLoading.value = false
|
||||
@@ -85,7 +91,7 @@ class AudioContentPlaylistDetailViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -13,11 +13,13 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.create.add_content.PlaylistAddContentDialogFragment
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentPlaylistModifyBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
@@ -45,7 +47,8 @@ class AudioContentPlaylistModifyActivity : BaseActivity<ActivityAudioContentPlay
|
||||
title = item.title,
|
||||
category = item.themeStr,
|
||||
coverUrl = item.coverImageUrl,
|
||||
duration = item.duration ?: "00:00:00",
|
||||
duration = item.duration ?: SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.screen_audio_content_upload_preview_start_time_default),
|
||||
creatorNickname = item.creatorNickname,
|
||||
creatorProfileUrl = ""
|
||||
)
|
||||
@@ -70,8 +73,9 @@ class AudioContentPlaylistModifyActivity : BaseActivity<ActivityAudioContentPlay
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (playlistId <= 0) {
|
||||
showToast("잘못된 요청입니다.")
|
||||
showToast(getString(R.string.screen_audio_content_error_invalid_request))
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
imm = getSystemService(
|
||||
@@ -83,7 +87,6 @@ class AudioContentPlaylistModifyActivity : BaseActivity<ActivityAudioContentPlay
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
binding.tvBack.text = "재생목록 수정"
|
||||
binding.tvBack.setOnClickListener { finish() }
|
||||
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
@@ -207,13 +210,21 @@ class AudioContentPlaylistModifyActivity : BaseActivity<ActivityAudioContentPlay
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setTitle(title: String) {
|
||||
binding.tvTitleLength.text = "${title.length}/30"
|
||||
binding.tvTitleLength.text = getString(
|
||||
R.string.audio_content_playlist_create_length_format,
|
||||
title.length,
|
||||
30
|
||||
)
|
||||
viewModel.title = title
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setDesc(desc: String) {
|
||||
binding.tvDescLength.text = "${desc.length}/40"
|
||||
binding.tvDescLength.text = getString(
|
||||
R.string.audio_content_playlist_create_length_format,
|
||||
desc.length,
|
||||
40
|
||||
)
|
||||
viewModel.desc = desc
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,9 @@ import kr.co.vividnext.sodalive.audio_content.playlist.create.PlaylistContentIdA
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistContent
|
||||
import kr.co.vividnext.sodalive.audio_content.playlist.detail.GetPlaylistDetailResponse
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AudioContentPlaylistModifyViewModel(
|
||||
private val repository: AudioContentPlaylistRepository
|
||||
@@ -37,6 +39,9 @@ class AudioContentPlaylistModifyViewModel(
|
||||
var desc: String = ""
|
||||
private var playlistId: Long = 0
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
fun addContent(item: AudioContentPlaylistContent) {
|
||||
contentList.add(item)
|
||||
_contentListLiveData.value = contentList
|
||||
@@ -85,7 +90,7 @@ class AudioContentPlaylistModifyViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownErrorMessage
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -94,7 +99,7 @@ class AudioContentPlaylistModifyViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownErrorMessage
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -104,12 +109,18 @@ class AudioContentPlaylistModifyViewModel(
|
||||
|
||||
private fun validate(): Boolean {
|
||||
if (title.isBlank() || title.length < 3) {
|
||||
_toastLiveData.value = "제목을 3자 이상 입력하세요"
|
||||
_toastLiveData.value = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_playlist_create_title_min_length_error,
|
||||
3
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (contentList.isEmpty()) {
|
||||
_toastLiveData.value = "콘텐츠를 1개 이상 추가하세요"
|
||||
_toastLiveData.value = SodaLiveApplicationHolder.get().getString(
|
||||
R.string.audio_content_playlist_create_content_min_count_error,
|
||||
1
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -136,9 +147,7 @@ class AudioContentPlaylistModifyViewModel(
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
}
|
||||
_isLoading.value = false
|
||||
@@ -146,7 +155,7 @@ class AudioContentPlaylistModifyViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -38,7 +38,10 @@ class SeriesListAdapter(
|
||||
}
|
||||
|
||||
binding.tvTitle.text = item.title
|
||||
binding.tvSeriesContentCount.text = "총 ${item.numberOfContent}화"
|
||||
binding.tvSeriesContentCount.text = binding.root.context.getString(
|
||||
R.string.screen_home_series_episode_count,
|
||||
item.numberOfContent
|
||||
)
|
||||
binding.tvPublishedDaysOfWeek.text = item.publishedDaysOfWeek
|
||||
|
||||
binding.tvNew.visibility = if (item.isNew) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.widget.Toast
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
@@ -57,11 +58,11 @@ class SeriesListAllActivity : BaseActivity<ActivitySeriesListAllBinding>(
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.toolbar.tvBack.text =
|
||||
if (intent.getBooleanExtra(Constants.EXTRA_IS_COMPLETED, false)) {
|
||||
"완결 시리즈"
|
||||
getString(R.string.screen_series_main_completed_title)
|
||||
} else if (intent.getBooleanExtra(Constants.EXTRA_IS_ORIGINAL, false)) {
|
||||
"오직 보이스온에서만"
|
||||
getString(R.string.voiceon_original_only)
|
||||
} else {
|
||||
"시리즈 전체보기"
|
||||
getString(R.string.screen_series_main_title)
|
||||
}
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ import com.google.gson.annotations.SerializedName
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseViewModel() {
|
||||
|
||||
@@ -34,6 +36,8 @@ class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseVie
|
||||
var isLast = false
|
||||
var page = 1
|
||||
private val size = 20
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
fun getSeriesList() {
|
||||
if (!_isLoading.value!! && !isLast) {
|
||||
@@ -62,12 +66,7 @@ class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseVie
|
||||
isLast = true
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
|
||||
}
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
@@ -75,7 +74,7 @@ class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseVie
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ class SeriesContentAdapter(
|
||||
} else if (item.isRented) {
|
||||
binding.tvRented.visibility = View.VISIBLE
|
||||
} else if (item.price > 0) {
|
||||
binding.tvPrice.text = "${item.price}"
|
||||
binding.tvPrice.text = item.price.toString()
|
||||
binding.tvPrice.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.tvPriceFree.visibility = View.VISIBLE
|
||||
|
||||
@@ -30,7 +30,11 @@ class SeriesContentAllActivity : BaseActivity<ActivitySeriesContentAllBinding>(
|
||||
|
||||
val seriesId = intent.getLongExtra(Constants.EXTRA_SERIES_ID, 0)
|
||||
if (seriesId <= 0) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.screen_audio_content_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -45,9 +49,12 @@ class SeriesContentAllActivity : BaseActivity<ActivitySeriesContentAllBinding>(
|
||||
|
||||
val seriesTitle = intent.getStringExtra(Constants.EXTRA_SERIES_TITLE) ?: ""
|
||||
binding.toolbar.tvBack.text = if (seriesTitle.isNotBlank()) {
|
||||
"$seriesTitle - 전체회차 듣기"
|
||||
getString(
|
||||
R.string.screen_series_content_all_title_format,
|
||||
seriesTitle
|
||||
)
|
||||
} else {
|
||||
" 전체회차 듣기"
|
||||
getString(R.string.screen_series_content_all_title_default)
|
||||
}
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesContentListItem
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class SeriesContentAllViewModel(private val repository: SeriesRepository) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
@@ -33,6 +35,8 @@ class SeriesContentAllViewModel(private val repository: SeriesRepository) : Base
|
||||
var page = 1
|
||||
private var pageSize = 10
|
||||
private var isLast = false
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
fun getSeriesContentList() {
|
||||
if (!_isLoading.value!! && !isLast) {
|
||||
@@ -59,18 +63,14 @@ class SeriesContentAllViewModel(private val repository: SeriesRepository) : Base
|
||||
isLast = true
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ data class GetSeriesDetailResponse(
|
||||
@SerializedName("writer") val writer: String?,
|
||||
@SerializedName("studio") val studio: String?,
|
||||
@SerializedName("publishedDate") val publishedDate: String,
|
||||
@SerializedName("publishedDateUtc") val publishedDateUtc: String,
|
||||
@SerializedName("creator") val creator: GetSeriesDetailCreator,
|
||||
@SerializedName("rentalMinPrice") var rentalMinPrice: Int,
|
||||
@SerializedName("rentalMaxPrice") var rentalMaxPrice: Int,
|
||||
@@ -26,7 +27,9 @@ data class GetSeriesDetailResponse(
|
||||
@SerializedName("keywordList") var keywordList: List<String>,
|
||||
@SerializedName("publishedDaysOfWeek") var publishedDaysOfWeek: String,
|
||||
@SerializedName("contentList") val contentList: List<GetSeriesContentListItem>,
|
||||
@SerializedName("contentCount") val contentCount: Int
|
||||
@SerializedName("contentCount") val contentCount: Int,
|
||||
@SerializedName("translated") val translated: TranslatedSeries?,
|
||||
@SerializedName("translatedGenre") val translatedGenre: String?
|
||||
) : Parcelable {
|
||||
@Parcelize
|
||||
@Keep
|
||||
@@ -38,3 +41,11 @@ data class GetSeriesDetailResponse(
|
||||
@SerializedName("isNotify") var isNotify: Boolean
|
||||
) : Parcelable
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
@Keep
|
||||
data class TranslatedSeries(
|
||||
@SerializedName("title") val title: String,
|
||||
@SerializedName("introduction") val introduction: String,
|
||||
@SerializedName("keywords") val keywords: List<String>
|
||||
) : Parcelable
|
||||
|
||||
@@ -38,7 +38,11 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
|
||||
|
||||
val seriesId = intent.getLongExtra(Constants.EXTRA_SERIES_ID, 0)
|
||||
if (seriesId <= 0) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
getString(R.string.screen_audio_content_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -57,8 +61,14 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
|
||||
|
||||
private fun setupTab() {
|
||||
val tabs = binding.tabs
|
||||
tabs.addTab(tabs.newTab().setText("홈").setTag("home"))
|
||||
tabs.addTab(tabs.newTab().setText("작품소개").setTag("introduction"))
|
||||
tabs.addTab(
|
||||
tabs.newTab().setText(R.string.screen_series_detail_tab_home).setTag("home")
|
||||
)
|
||||
tabs.addTab(
|
||||
tabs.newTab()
|
||||
.setText(R.string.screen_series_detail_tab_introduction)
|
||||
.setTag("introduction")
|
||||
)
|
||||
|
||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
@@ -108,10 +118,13 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
|
||||
}
|
||||
|
||||
viewModel.seriesDetailLiveData.observe(this) {
|
||||
// GetSeriesDetailResponse에 추가한대로 번역 데이터가 있으면 번역데이터 표시
|
||||
// 없으면 지금과 동일하게 원본 데이터 표시
|
||||
setSeriesBg(it.coverImage)
|
||||
setSeriesInfo(it)
|
||||
setSeriesCreator(it.creator)
|
||||
setSeriesKeywordChipList(it.keywordList)
|
||||
// 번역 키워드가 있으면 번역 키워드 표시, 없으면 기존 키워드 표시
|
||||
setSeriesKeywordChipList(it.translated?.keywords ?: it.keywordList)
|
||||
|
||||
changeFragment("home")
|
||||
}
|
||||
@@ -137,7 +150,7 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
|
||||
|
||||
chip.setPadding(0, 0, 0, 0)
|
||||
chip.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_d2d2d2))
|
||||
chip.typeface = ResourcesCompat.getFont(applicationContext, R.font.gmarket_sans_medium)
|
||||
chip.typeface = ResourcesCompat.getFont(applicationContext, R.font.medium)
|
||||
binding.chipGroup.addView(chip)
|
||||
}
|
||||
}
|
||||
@@ -150,9 +163,23 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
|
||||
transformations(RoundedCornersTransformation(5f.dpToPx()))
|
||||
}
|
||||
|
||||
binding.tvTitle.text = seriesDetail.title
|
||||
binding.tvGenre.text = seriesDetail.genre
|
||||
binding.tvPublishedDaysOfWeek.text = "${seriesDetail.publishedDaysOfWeek} 연재"
|
||||
// 번역 데이터 사용 우선, 없으면 원본 사용
|
||||
val displayTitle = seriesDetail.translated?.title?.takeIf { it.isNotBlank() }
|
||||
?: seriesDetail.title
|
||||
val displayGenre = seriesDetail.translatedGenre?.takeIf { it.isNotBlank() }
|
||||
?: seriesDetail.genre
|
||||
|
||||
binding.tvTitle.text = displayTitle
|
||||
binding.tvGenre.text = displayGenre
|
||||
val publishedDays = if (seriesDetail.publishedDaysOfWeek == getString(R.string.day_random)) {
|
||||
getString(R.string.day_random)
|
||||
} else {
|
||||
seriesDetail.publishedDaysOfWeek
|
||||
}
|
||||
binding.tvPublishedDaysOfWeek.text = getString(
|
||||
R.string.screen_series_detail_published_days_format,
|
||||
publishedDays
|
||||
)
|
||||
|
||||
if (seriesDetail.isAdult) {
|
||||
binding.tvAge19.visibility = View.VISIBLE
|
||||
|
||||
@@ -5,8 +5,11 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAllActivity
|
||||
@@ -44,9 +47,12 @@ class SeriesDetailHomeFragment : BaseFragment<FragmentSeriesDetailHomeBinding>(
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@OptIn(UnstableApi::class)
|
||||
private fun setContent() {
|
||||
binding.tvTotalCount.text = "(${seriesDetailResponse!!.contentCount})"
|
||||
binding.tvTotalCount.text = getString(
|
||||
R.string.screen_series_detail_content_count_format,
|
||||
seriesDetailResponse!!.contentCount
|
||||
)
|
||||
binding.llContentAll.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(requireActivity(), SeriesContentAllActivity::class.java).apply {
|
||||
|
||||
@@ -13,6 +13,9 @@ import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentSeriesDetailIntroductionBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
class SeriesDetailIntroductionFragment : BaseFragment<FragmentSeriesDetailIntroductionBinding>(
|
||||
FragmentSeriesDetailIntroductionBinding::inflate
|
||||
@@ -38,8 +41,15 @@ class SeriesDetailIntroductionFragment : BaseFragment<FragmentSeriesDetailIntrod
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (seriesDetailResponse != null) {
|
||||
setSeriesKeywordChipList(seriesDetailResponse!!.keywordList)
|
||||
setSeriesIntroduction(seriesDetailResponse!!.introduction)
|
||||
// 번역 데이터가 있으면 번역 데이터 우선 적용
|
||||
setSeriesKeywordChipList(
|
||||
seriesDetailResponse!!.translated?.keywords
|
||||
?: seriesDetailResponse!!.keywordList
|
||||
)
|
||||
setSeriesIntroduction(
|
||||
seriesDetailResponse!!.translated?.introduction
|
||||
?: seriesDetailResponse!!.introduction
|
||||
)
|
||||
setSeriesPrice()
|
||||
setSeriesInfo()
|
||||
}
|
||||
@@ -53,41 +63,63 @@ class SeriesDetailIntroductionFragment : BaseFragment<FragmentSeriesDetailIntrod
|
||||
|
||||
binding.tvRentalPrice.text = if (rentalMinPrice == rentalMaxPrice) {
|
||||
if (rentalMaxPrice == 0) {
|
||||
"무료(5일)"
|
||||
getString(R.string.screen_series_detail_price_rental_free)
|
||||
} else {
|
||||
"$rentalMaxPrice(5일)"
|
||||
getString(R.string.screen_series_detail_price_rental_single, rentalMaxPrice)
|
||||
}
|
||||
} else {
|
||||
"${if (rentalMinPrice == 0) "무료" else rentalMinPrice} ~ ${rentalMaxPrice}캔 (5일)"
|
||||
val minText = if (rentalMinPrice == 0) {
|
||||
getString(R.string.audio_content_price_free)
|
||||
} else {
|
||||
rentalMinPrice.toString()
|
||||
}
|
||||
getString(
|
||||
R.string.screen_series_detail_price_rental_range,
|
||||
minText,
|
||||
rentalMaxPrice
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvPrice.text = if (minPrice == maxPrice) {
|
||||
if (maxPrice == 0) {
|
||||
"무료"
|
||||
getString(R.string.audio_content_price_free)
|
||||
} else {
|
||||
"$maxPrice"
|
||||
getString(R.string.screen_series_detail_price_keep_single, maxPrice)
|
||||
}
|
||||
} else {
|
||||
"${if (minPrice == 0) "무료" else minPrice} ~ ${maxPrice}캔"
|
||||
val minText = if (minPrice == 0) {
|
||||
getString(R.string.audio_content_price_free)
|
||||
} else {
|
||||
minPrice.toString()
|
||||
}
|
||||
getString(R.string.screen_series_detail_price_keep_range, minText, maxPrice)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setSeriesInfo() {
|
||||
binding.tvGenre.text = seriesDetailResponse!!.genre
|
||||
// 장르는 번역 데이터가 있으면 번역 장르 사용
|
||||
binding.tvGenre.text =
|
||||
seriesDetailResponse!!.translatedGenre ?: seriesDetailResponse!!.genre
|
||||
binding.tvIsAdult.text = if (seriesDetailResponse!!.isAdult) {
|
||||
"19세 이상"
|
||||
getString(R.string.screen_series_detail_age_19)
|
||||
} else {
|
||||
"전체연령가"
|
||||
getString(R.string.screen_series_detail_age_all)
|
||||
}
|
||||
|
||||
binding.tvPublishedDate.text = seriesDetailResponse!!.publishedDate
|
||||
binding.tvPublishedDaysOfWeek.text =
|
||||
if (seriesDetailResponse!!.publishedDaysOfWeek == "랜덤") {
|
||||
seriesDetailResponse!!.publishedDaysOfWeek
|
||||
// 공개일은 publishedDateUtc(UTC)를 단말 타임존으로 변환하여 표시
|
||||
binding.tvPublishedDate.text =
|
||||
formatPublishedDateUtc(seriesDetailResponse!!.publishedDateUtc)
|
||||
val publishedDays =
|
||||
if (seriesDetailResponse!!.publishedDaysOfWeek == getString(R.string.day_random)) {
|
||||
getString(R.string.day_random)
|
||||
} else {
|
||||
seriesDetailResponse!!.publishedDaysOfWeek
|
||||
}
|
||||
binding.tvPublishedDaysOfWeek.text = getString(
|
||||
R.string.screen_series_detail_published_days_format,
|
||||
publishedDays
|
||||
)
|
||||
|
||||
if (seriesDetailResponse!!.writer != null) {
|
||||
binding.tvWriter.visibility = View.VISIBLE
|
||||
@@ -110,6 +142,26 @@ class SeriesDetailIntroductionFragment : BaseFragment<FragmentSeriesDetailIntrod
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatPublishedDateUtc(utcString: String): String {
|
||||
return try {
|
||||
val utcFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()).apply {
|
||||
timeZone = TimeZone.getTimeZone("UTC")
|
||||
}
|
||||
val date = utcFormat.parse(utcString)
|
||||
if (date != null) {
|
||||
val localFormat = SimpleDateFormat("yyyy.MM.dd", Locale.getDefault()).apply {
|
||||
timeZone = TimeZone.getDefault()
|
||||
}
|
||||
localFormat.format(date)
|
||||
} else {
|
||||
// 파싱 실패 시 서버에서 제공한 기존 publishedDate로 폴백
|
||||
seriesDetailResponse?.publishedDate ?: utcString
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
seriesDetailResponse?.publishedDate ?: utcString
|
||||
}
|
||||
}
|
||||
|
||||
private fun setSeriesIntroduction(introduction: String) {
|
||||
binding.tvIntroduce.text = introduction
|
||||
}
|
||||
@@ -134,7 +186,7 @@ class SeriesDetailIntroductionFragment : BaseFragment<FragmentSeriesDetailIntrod
|
||||
chip.setEnsureMinTouchTargetSize(false)
|
||||
chip.setPadding(0, 0, 0, 0)
|
||||
chip.setTextColor(ContextCompat.getColor(requireContext(), R.color.color_d2d2d2))
|
||||
chip.typeface = ResourcesCompat.getFont(requireContext(), R.font.gmarket_sans_medium)
|
||||
chip.typeface = ResourcesCompat.getFont(requireContext(), R.font.medium)
|
||||
binding.chipGroup.addView(chip)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.user.UserRepository
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class SeriesDetailViewModel(
|
||||
private val repository: SeriesRepository,
|
||||
@@ -29,6 +31,8 @@ class SeriesDetailViewModel(
|
||||
var seriesId = 0L
|
||||
|
||||
lateinit var seriesDetailResponse: GetSeriesDetailResponse
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
fun getSeriesDetail() {
|
||||
_isLoading.value = true
|
||||
@@ -46,18 +50,14 @@ class SeriesDetailViewModel(
|
||||
seriesDetailResponse = it.data
|
||||
_seriesDetailLiveData.value = seriesDetailResponse
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -84,20 +84,14 @@ class SeriesDetailViewModel(
|
||||
if (it.success && it.data != null) {
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
_toastLiveData.postValue(it.message ?: unknownErrorMessage)
|
||||
}
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -14,16 +14,22 @@ class SeriesMainActivity : BaseActivity<ActivitySeriesMainBinding>(
|
||||
private var currentTab = 0
|
||||
|
||||
override fun setupView() {
|
||||
binding.toolbar.tvBack.text = "시리즈 전체보기"
|
||||
binding.toolbar.tvBack.text = getString(R.string.screen_series_main_title)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
setupTabs()
|
||||
}
|
||||
|
||||
private fun setupTabs() {
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("홈"))
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("요일별"))
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("장르별"))
|
||||
binding.tabLayout.addTab(
|
||||
binding.tabLayout.newTab().setText(R.string.screen_series_main_tab_home)
|
||||
)
|
||||
binding.tabLayout.addTab(
|
||||
binding.tabLayout.newTab().setText(R.string.screen_series_main_tab_day_of_week)
|
||||
)
|
||||
binding.tabLayout.addTab(
|
||||
binding.tabLayout.newTab().setText(R.string.screen_series_main_tab_genre)
|
||||
)
|
||||
|
||||
// 탭 선택 리스너 설정
|
||||
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
|
||||
@@ -4,10 +4,12 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class SeriesMainByGenreViewModel(
|
||||
private val repository: SeriesMainRepository
|
||||
@@ -36,6 +38,9 @@ class SeriesMainByGenreViewModel(
|
||||
val selectedGenreId: Long?
|
||||
get() = _selectedGenreId
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
fun loadGenres() {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
@@ -59,12 +64,12 @@ class SeriesMainByGenreViewModel(
|
||||
_genreListLiveData.value = emptyList()
|
||||
}
|
||||
} else {
|
||||
_toastLiveData.value = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownErrorMessage
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -108,12 +113,12 @@ class SeriesMainByGenreViewModel(
|
||||
isLast = true
|
||||
}
|
||||
} else {
|
||||
_toastLiveData.value = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownErrorMessage
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.widget.Toast
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
@@ -61,7 +60,7 @@ class SeriesMainDayOfWeekFragment : BaseFragment<FragmentSeriesMainDayOfWeekBind
|
||||
}
|
||||
|
||||
private fun setupDayOfWeekDay() {
|
||||
val dayOfWeekAdapter = DayOfWeekAdapter(screenWidth = screenWidth) {
|
||||
val dayOfWeekAdapter = DayOfWeekAdapter(requireContext()) {
|
||||
adapter.clear()
|
||||
viewModel.dayOfWeek = it
|
||||
}
|
||||
@@ -73,7 +72,7 @@ class SeriesMainDayOfWeekFragment : BaseFragment<FragmentSeriesMainDayOfWeekBind
|
||||
false
|
||||
) {
|
||||
override fun canScrollVertically() = false
|
||||
override fun canScrollHorizontally() = false
|
||||
override fun canScrollHorizontally() = true
|
||||
}
|
||||
rvDayOfWeek.layoutManager = layoutManager
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.home.SeriesPublishedDaysOfWeek
|
||||
|
||||
class SeriesMainDayOfWeekViewModel(
|
||||
@@ -30,6 +32,9 @@ class SeriesMainDayOfWeekViewModel(
|
||||
private var isLast = false
|
||||
private val pageSize = 20
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
var dayOfWeek = SeriesPublishedDaysOfWeek.RANDOM
|
||||
set(newValue) {
|
||||
if (field != newValue) {
|
||||
@@ -67,17 +72,13 @@ class SeriesMainDayOfWeekViewModel(
|
||||
isLast = true
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownErrorMessage
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -5,10 +5,12 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.main.SeriesMainRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
|
||||
class SeriesMainHomeViewModel(
|
||||
private val repository: SeriesMainRepository
|
||||
@@ -35,6 +37,9 @@ class SeriesMainHomeViewModel(
|
||||
val recommendSeriesLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||
get() = _recommendSeriesLiveData
|
||||
|
||||
private val unknownErrorMessage: String
|
||||
get() = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
|
||||
|
||||
fun fetchData() {
|
||||
_isLoading.value = true
|
||||
|
||||
@@ -52,19 +57,13 @@ class SeriesMainHomeViewModel(
|
||||
_completedSeriesLiveData.value = data.completedSeriesList
|
||||
_recommendSeriesLiveData.value = data.recommendSeriesList
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
_toastLiveData.postValue(it.message ?: unknownErrorMessage)
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(unknownErrorMessage)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -83,17 +82,13 @@ class SeriesMainHomeViewModel(
|
||||
if (it.success && it.data != null) {
|
||||
_recommendSeriesLiveData.value = it.data
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
}
|
||||
_toastLiveData.value = it.message ?: unknownErrorMessage
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = unknownErrorMessage
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.audio_content.upload
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Intent
|
||||
@@ -32,6 +31,7 @@ import kr.co.vividnext.sodalive.common.ImagePickerCropper
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.RealPathUtil
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentUploadBinding
|
||||
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
||||
import kr.co.vividnext.sodalive.dialog.SodaLiveTimePickerDialog
|
||||
@@ -84,16 +84,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
getString(R.string.audio_content_upload_error_invalid_file),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else {
|
||||
binding.tvSelectContent.text = "파일 선택"
|
||||
binding.tvSelectContent.text =
|
||||
getString(R.string.screen_audio_content_upload_select_file)
|
||||
viewModel.contentUri = null
|
||||
Toast.makeText(
|
||||
this,
|
||||
"파일 선택을 실패했습니다.\n다시 시도해 주세요.",
|
||||
getString(R.string.audio_content_upload_error_select_file),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
@@ -177,11 +178,11 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
)
|
||||
|
||||
binding.tvServiceDate.text = if (SharedPreferenceManager.userId == 17958L) {
|
||||
"※ 이용기간 : 대여(5일) | 소장(이용 기간 1년)"
|
||||
getString(R.string.screen_audio_content_upload_service_period_one_year)
|
||||
} else {
|
||||
"※ 이용기간 : 대여(5일) | 소장(서비스 종료시까지)"
|
||||
getString(R.string.screen_audio_content_upload_service_period_until_end)
|
||||
}
|
||||
binding.toolbar.tvBack.text = "콘텐츠 등록"
|
||||
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_upload_title)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
binding.llTheme.setOnClickListener {
|
||||
if (themeFragment.isAdded) return@setOnClickListener
|
||||
@@ -200,7 +201,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
selectAudioActivityResultLauncher.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
"Select Audio"
|
||||
getString(R.string.audio_content_upload_select_audio_title)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -235,11 +236,9 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
LiveDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "콘텐츠 업로드",
|
||||
desc = "등록한 콘텐츠가 업로드 중입니다.\n" +
|
||||
"콘텐츠 등록이 완료되면 알림을 보내드립니다.\n" +
|
||||
"이 페이지를 나가도 콘텐츠는 자동으로 등록됩니다.",
|
||||
confirmButtonTitle = "확인",
|
||||
title = getString(R.string.audio_content_upload_dialog_title),
|
||||
desc = getString(R.string.audio_content_upload_dialog_desc),
|
||||
confirmButtonTitle = getString(R.string.confirm),
|
||||
confirmButtonClick = { finish() },
|
||||
).show(screenWidth)
|
||||
}
|
||||
@@ -309,6 +308,13 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
|
||||
timePicker.show()
|
||||
}
|
||||
|
||||
viewModel.setReservationDate(
|
||||
getString(R.string.screen_audio_content_upload_reservation_date_placeholder)
|
||||
)
|
||||
viewModel.setReservationTime(
|
||||
getString(R.string.screen_audio_content_upload_reservation_time_placeholder)
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkPermissions() {
|
||||
@@ -332,8 +338,12 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
.check()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindData() {
|
||||
binding.tvNumberOfCharacters.text = getString(
|
||||
R.string.screen_audio_content_upload_char_count_format,
|
||||
binding.etDetail.text?.length ?: 0
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etTitle.textChanges().skip(1)
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -348,7 +358,10 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
binding.tvNumberOfCharacters.text = "${it.length}자"
|
||||
binding.tvNumberOfCharacters.text = getString(
|
||||
R.string.screen_audio_content_upload_char_count_format,
|
||||
it.length
|
||||
)
|
||||
viewModel.detail = it.toString()
|
||||
}
|
||||
)
|
||||
@@ -424,13 +437,21 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
}
|
||||
)
|
||||
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||
viewModel.toastLiveData.observe(this) { toastMessage ->
|
||||
toastMessage?.let {
|
||||
val message = it.message ?: it.resId?.let(::getString)
|
||||
message?.let { text ->
|
||||
Toast.makeText(applicationContext, text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth, "콘텐츠를 업로드 하는 중입니다.")
|
||||
loadingDialog.show(
|
||||
screenWidth,
|
||||
getString(R.string.screen_audio_content_upload_loading_message)
|
||||
)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
@@ -647,7 +668,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
|
||||
private fun checkPriceFree() {
|
||||
viewModel.price = 0
|
||||
binding.etSetPrice.setText("0")
|
||||
binding.etSetPrice.setText(SodaLiveApplicationHolder.get().getString(R.string.common_zero))
|
||||
binding.llSetPrice.visibility = View.GONE
|
||||
binding.llConfigPurchase.visibility = View.GONE
|
||||
binding.tvTitleConfigKeep.visibility = View.GONE
|
||||
@@ -876,7 +897,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
|
||||
private fun checkBoth() {
|
||||
uncheckPurchaseOption()
|
||||
binding.tvPriceTitle.text = "소장 가격"
|
||||
binding.tvPriceTitle.text =
|
||||
getString(R.string.screen_audio_content_upload_price_title_keep)
|
||||
binding.ivBoth.visibility = View.VISIBLE
|
||||
binding.tvBoth.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
@@ -889,7 +911,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
|
||||
private fun checkBuyOnly() {
|
||||
uncheckPurchaseOption()
|
||||
binding.tvPriceTitle.text = "소장 가격"
|
||||
binding.tvPriceTitle.text =
|
||||
getString(R.string.screen_audio_content_upload_price_title_keep)
|
||||
binding.ivBuyOnly.visibility = View.VISIBLE
|
||||
binding.tvBuyOnly.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
@@ -902,7 +925,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
|
||||
private fun checkRentOnly() {
|
||||
uncheckPurchaseOption()
|
||||
binding.tvPriceTitle.text = "대여 가격"
|
||||
binding.tvPriceTitle.text =
|
||||
getString(R.string.screen_audio_content_upload_price_title_rent)
|
||||
binding.ivRentOnly.visibility = View.VISIBLE
|
||||
binding.tvRentOnly.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
|
||||
@@ -11,7 +11,9 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.PurchaseOption
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
@@ -27,8 +29,8 @@ class AudioContentUploadViewModel(
|
||||
private val repository: AudioContentRepository
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<ToastMessage?>()
|
||||
val toastLiveData: LiveData<ToastMessage?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
@@ -71,11 +73,11 @@ class AudioContentUploadViewModel(
|
||||
val isActiveReservationLiveData: LiveData<Boolean>
|
||||
get() = _isActiveReservationLiveData
|
||||
|
||||
private val _reservationDateLiveData = MutableLiveData("날짜를 선택해주세요")
|
||||
private val _reservationDateLiveData = MutableLiveData("")
|
||||
val reservationDateLiveData: LiveData<String>
|
||||
get() = _reservationDateLiveData
|
||||
|
||||
private val _reservationTimeLiveData = MutableLiveData("시간을 설정해주세요")
|
||||
private val _reservationTimeLiveData = MutableLiveData("")
|
||||
val reservationTimeLiveData: LiveData<String>
|
||||
get() = _reservationTimeLiveData
|
||||
|
||||
@@ -262,12 +264,16 @@ class AudioContentUploadViewModel(
|
||||
}
|
||||
|
||||
if (coverImage == null) {
|
||||
_toastLiveData.postValue("커버이미지를 선택해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_cover_required)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (contentFile == null) {
|
||||
_toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_content_required)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -286,10 +292,12 @@ class AudioContentUploadViewModel(
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(message = it.message)
|
||||
)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -299,7 +307,7 @@ class AudioContentUploadViewModel(
|
||||
_isLoading.postValue(false)
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -309,48 +317,64 @@ class AudioContentUploadViewModel(
|
||||
|
||||
private fun validateData(): Boolean {
|
||||
if (title.isBlank()) {
|
||||
_toastLiveData.postValue("제목을 입력해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_title_required)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (detail.isBlank() || detail.length < 5) {
|
||||
_toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_detail_min_length)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (theme == null) {
|
||||
_toastLiveData.postValue("테마를 선택해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_theme_required)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (coverImageFile == null) {
|
||||
_toastLiveData.postValue("커버이미지를 선택해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_cover_required)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (previewStartTime != null && previewEndTime != null) {
|
||||
val startTimeArray = previewStartTime!!.split(":")
|
||||
if (startTimeArray.size != 3) {
|
||||
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
for (time in startTimeArray) {
|
||||
if (time.length != 2) {
|
||||
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
val endTimeArray = previewEndTime!!.split(":")
|
||||
if (endTimeArray.size != 3) {
|
||||
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
for (time in endTimeArray) {
|
||||
if (time.length != 2) {
|
||||
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_preview_format)
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -359,7 +383,7 @@ class AudioContentUploadViewModel(
|
||||
|
||||
if (timeDifference < 15000) {
|
||||
_toastLiveData.postValue(
|
||||
"미리 듣기의 최소 시간은 15초 입니다."
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_preview_minimum)
|
||||
)
|
||||
|
||||
return false
|
||||
@@ -367,7 +391,9 @@ class AudioContentUploadViewModel(
|
||||
} else {
|
||||
if (previewStartTime != null || previewEndTime != null) {
|
||||
_toastLiveData.postValue(
|
||||
"미리 듣기 시작 시간과 종료 시간 둘 다 입력을 하거나 둘 다 입력 하지 않아야 합니다."
|
||||
ToastMessage(
|
||||
resId = R.string.audio_content_upload_error_preview_both_required
|
||||
)
|
||||
)
|
||||
|
||||
return false
|
||||
@@ -375,12 +401,16 @@ class AudioContentUploadViewModel(
|
||||
}
|
||||
|
||||
if (contentUri == null) {
|
||||
_toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_content_required)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isPriceFreeLiveData.value!! && price < 5) {
|
||||
_toastLiveData.postValue("콘텐츠의 최소금액은 5캔 입니다.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_minimum_price)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -388,7 +418,9 @@ class AudioContentUploadViewModel(
|
||||
_isActiveReservationLiveData.value!! &&
|
||||
(releaseDate.isBlank() || releaseTime.isBlank())
|
||||
) {
|
||||
_toastLiveData.postValue("예약날짜와 시간을 선택해주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.audio_content_upload_error_reservation_required)
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,13 @@ class AudioContentThemeFragment(
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
it?.let { toastMessage ->
|
||||
val message = toastMessage.message
|
||||
?: toastMessage.resId?.let(::getString)
|
||||
message?.let { text ->
|
||||
Toast.makeText(requireActivity(), text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.themeLiveData.observe(viewLifecycleOwner) {
|
||||
|
||||
@@ -7,11 +7,13 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
|
||||
class AudioContentThemeViewModel(private val repository: AudioContentRepository) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<ToastMessage?>()
|
||||
val toastLiveData: LiveData<ToastMessage?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _themeLiveData = MutableLiveData<List<GetAudioContentThemeResponse>>()
|
||||
@@ -29,17 +31,19 @@ class AudioContentThemeViewModel(private val repository: AudioContentRepository)
|
||||
_themeLiveData.postValue(it.data!!)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
_toastLiveData.postValue(ToastMessage(message = it.message))
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -124,8 +124,13 @@ class AuditionFragment : BaseFragment<FragmentAuditionBinding>(
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) { toastMessage ->
|
||||
toastMessage?.let {
|
||||
val message = it.message ?: it.resId?.let(::getString)
|
||||
message?.let { text ->
|
||||
Toast.makeText(requireActivity(), text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.audition
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -47,18 +46,18 @@ class AuditionListAdapter(
|
||||
inner class InProgressHeaderViewHolder(
|
||||
private val binding: ItemAuditionListInProgressHeaderBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(totalCount: Int) {
|
||||
binding.tvTotalCount.text = "총 ${totalCount}개"
|
||||
binding.tvTotalCount.text =
|
||||
binding.root.context.getString(R.string.screen_audition_total_count, totalCount)
|
||||
}
|
||||
}
|
||||
|
||||
inner class CompletedHeaderViewHolder(
|
||||
private val binding: ItemAuditionListCompletedHeaderBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(totalCount: Int) {
|
||||
binding.tvTotalCount.text = "총 ${totalCount}개"
|
||||
binding.tvTotalCount.text =
|
||||
binding.root.context.getString(R.string.screen_audition_total_count, totalCount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
|
||||
import kr.co.vividnext.sodalive.user.UserRepository
|
||||
|
||||
@@ -14,8 +16,8 @@ class AuditionViewModel(
|
||||
private val repository: AuditionRepository,
|
||||
private val userRepository: UserRepository
|
||||
) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<ToastMessage?>()
|
||||
val toastLiveData: LiveData<ToastMessage?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
@@ -53,10 +55,10 @@ class AuditionViewModel(
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
_toastLiveData.postValue(ToastMessage(message = it.message))
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -64,7 +66,9 @@ class AuditionViewModel(
|
||||
{
|
||||
_isLoading.postValue(false)
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.media3.common.util.UnstableApi
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
|
||||
import kr.co.vividnext.sodalive.audio_content.player.AudioContentPlayerService
|
||||
import java.io.IOException
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
class AuditionApplicantMediaPlayerManager(
|
||||
@@ -101,7 +102,11 @@ class AuditionApplicantMediaPlayerManager(
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(context, "콘텐츠를 재생하지 못했습니다.\n다시 시도해 주세요", Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.screen_audition_play_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
showLoadingDialog(false)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentAuditionApplyDialogBinding
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AuditionApplyDialogFragment(
|
||||
private val fileName: String,
|
||||
@@ -59,13 +60,13 @@ class AuditionApplyDialogFragment(
|
||||
if (phoneNumber.isBlank() || phoneNumber.length != 11) {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"잘못된 연락처 입니다.\n다시 입력해 주세요.",
|
||||
getString(R.string.dialog_audition_apply_error_invalid_phone),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
} else if (!binding.tvAgree.isSelected) {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"연락처 수집 및 활용에 동의하셔야 오디션 지원이 가능합니다.",
|
||||
getString(R.string.dialog_audition_apply_error_need_agreement),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
} else {
|
||||
|
||||
@@ -7,8 +7,6 @@ import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.MultiTransformation
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
@@ -19,6 +17,7 @@ import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailActivity
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAuditionDetailBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
@@ -40,7 +39,7 @@ class AuditionDetailActivity : BaseActivity<ActivityAuditionDetailBinding>(
|
||||
if (auditionId <= 0) {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
"잘못된 요청입니다.\n다시 시도해 주세요.",
|
||||
getString(R.string.screen_audition_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
@@ -60,7 +59,7 @@ class AuditionDetailActivity : BaseActivity<ActivityAuditionDetailBinding>(
|
||||
isOpenInformation = !isOpenInformation
|
||||
if (isOpenInformation) {
|
||||
binding.tvInformation.maxLines = Int.MAX_VALUE
|
||||
binding.tvOpen.text = "접기"
|
||||
binding.tvOpen.text = getString(R.string.screen_audition_detail_collapse)
|
||||
binding.tvOpen.setCompoundDrawablesWithIntrinsicBounds(
|
||||
R.drawable.ic_live_detail_top,
|
||||
0,
|
||||
@@ -69,7 +68,7 @@ class AuditionDetailActivity : BaseActivity<ActivityAuditionDetailBinding>(
|
||||
)
|
||||
} else {
|
||||
binding.tvInformation.maxLines = 3
|
||||
binding.tvOpen.text = "펼치기"
|
||||
binding.tvOpen.text = getString(R.string.screen_audition_detail_expand)
|
||||
binding.tvOpen.setCompoundDrawablesWithIntrinsicBounds(
|
||||
R.drawable.ic_live_detail_bottom,
|
||||
0,
|
||||
@@ -125,8 +124,13 @@ class AuditionDetailActivity : BaseActivity<ActivityAuditionDetailBinding>(
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||
viewModel.toastLiveData.observe(this) { toastMessage ->
|
||||
toastMessage?.let {
|
||||
val message = it.message ?: it.resId?.let(::getString)
|
||||
message?.let { text ->
|
||||
Toast.makeText(applicationContext, text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
|
||||
@@ -60,11 +60,11 @@ class AuditionDetailRoleAdapter(
|
||||
|
||||
if (item.isComplete) {
|
||||
binding.blackCover.visibility = View.VISIBLE
|
||||
binding.tvStatus.text = "모집완료"
|
||||
binding.tvStatus.text = context.getString(R.string.screen_audition_status_closed)
|
||||
binding.tvStatus.setBackgroundResource(R.drawable.bg_round_corner_13_3_909090)
|
||||
} else {
|
||||
binding.blackCover.visibility = View.GONE
|
||||
binding.tvStatus.text = "모집중"
|
||||
binding.tvStatus.text = context.getString(R.string.screen_audition_status_open)
|
||||
binding.tvStatus.setBackgroundResource(R.drawable.bg_round_corner_13_3_3bb9f1)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,15 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audition.AuditionRepository
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
class AuditionDetailViewModel(
|
||||
private val repository: AuditionRepository
|
||||
) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<ToastMessage?>()
|
||||
val toastLiveData: LiveData<ToastMessage?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
@@ -39,10 +41,10 @@ class AuditionDetailViewModel(
|
||||
_auditionDetailLiveData.value = it.data
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
_toastLiveData.postValue(ToastMessage(message = it.message))
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,7 +58,9 @@ class AuditionDetailViewModel(
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.audition.role
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
@@ -28,6 +29,7 @@ import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.RealPathUtil
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityAuditionRoleDetailBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.RecordingVoiceFragment
|
||||
@@ -66,14 +68,14 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 녹음 파일 입니다.\n다시 선택해 주세요.",
|
||||
getString(R.string.screen_audition_invalid_audio_file),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 녹음 파일 입니다.\n다시 선택해 주세요.",
|
||||
getString(R.string.screen_audition_invalid_audio_file),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
@@ -87,7 +89,7 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
if (auditionRoleId <= 0) {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
"잘못된 요청입니다.\n다시 시도해 주세요.",
|
||||
getString(R.string.screen_audition_error_invalid_request),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
@@ -137,7 +139,7 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
isOpenInformation = !isOpenInformation
|
||||
if (isOpenInformation) {
|
||||
binding.tvInformation.maxLines = Int.MAX_VALUE
|
||||
binding.tvOpen.text = "접기"
|
||||
binding.tvOpen.text = getString(R.string.screen_audition_detail_collapse)
|
||||
binding.tvOpen.setCompoundDrawablesWithIntrinsicBounds(
|
||||
R.drawable.ic_live_detail_top,
|
||||
0,
|
||||
@@ -146,7 +148,7 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
)
|
||||
} else {
|
||||
binding.tvInformation.maxLines = 3
|
||||
binding.tvOpen.text = "펼치기"
|
||||
binding.tvOpen.text = getString(R.string.screen_audition_detail_expand)
|
||||
binding.tvOpen.setCompoundDrawablesWithIntrinsicBounds(
|
||||
R.drawable.ic_live_detail_bottom,
|
||||
0,
|
||||
@@ -162,9 +164,9 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
SodaDialog(
|
||||
activity = this@AuditionRoleDetailActivity,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "재지원 안내",
|
||||
desc = "재지원 시 이전 지원 내역은 삭제되며 받은 투표수는 무효 처리됩니다.",
|
||||
confirmButtonTitle = "확인",
|
||||
title = getString(R.string.dialog_audition_reapply_title),
|
||||
desc = getString(R.string.dialog_audition_reapply_desc),
|
||||
confirmButtonTitle = getString(R.string.confirm),
|
||||
confirmButtonClick = { showApplicationMethodDialog() }
|
||||
).show(screenWidth)
|
||||
} else {
|
||||
@@ -174,9 +176,9 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
SodaDialog(
|
||||
activity = this@AuditionRoleDetailActivity,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "- 본인인증 -",
|
||||
desc = "마이페이지에서 '본인인증'을 하고 다시 오디션에 지원해 주세요.",
|
||||
confirmButtonTitle = "확인",
|
||||
title = getString(R.string.dialog_audition_auth_title),
|
||||
desc = getString(R.string.dialog_audition_auth_desc),
|
||||
confirmButtonTitle = getString(R.string.confirm),
|
||||
confirmButtonClick = {}
|
||||
).show(screenWidth)
|
||||
}
|
||||
@@ -211,9 +213,9 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
SodaDialog(
|
||||
activity = this@AuditionRoleDetailActivity,
|
||||
layoutInflater = layoutInflater,
|
||||
"[오디션 응원]",
|
||||
"오디션을 응원하셨습니다\n(무료응원 : 1계정당 1일 1회)\n1캔으로 추가 응원을 해보세요.",
|
||||
confirmButtonTitle = "확인",
|
||||
getString(R.string.dialog_audition_vote_title),
|
||||
getString(R.string.dialog_audition_vote_desc),
|
||||
confirmButtonTitle = getString(R.string.confirm),
|
||||
confirmButtonClick = {
|
||||
isShowNotifyVote = false
|
||||
},
|
||||
@@ -225,9 +227,9 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
SodaDialog(
|
||||
activity = this@AuditionRoleDetailActivity,
|
||||
layoutInflater = layoutInflater,
|
||||
"[오늘 응원 제한]",
|
||||
"오늘 응원은 여기까지!\n하루 최대 10회까지 이용이 가능합니다.\n내일 다시 이용해주세요.",
|
||||
confirmButtonTitle = "확인",
|
||||
getString(R.string.dialog_audition_vote_limit_title),
|
||||
getString(R.string.dialog_audition_vote_limit_desc),
|
||||
confirmButtonTitle = getString(R.string.confirm),
|
||||
confirmButtonClick = {},
|
||||
descGravity = Gravity.CENTER
|
||||
).show(screenWidth)
|
||||
@@ -307,7 +309,7 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
selectAudioActivityResultLauncher.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
"Select Audio"
|
||||
getString(R.string.screen_audition_select_audio)
|
||||
)
|
||||
)
|
||||
},
|
||||
@@ -339,9 +341,15 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
auditionApplyDialogFragment.show(supportFragmentManager, auditionApplyDialogFragment.tag)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||
it?.let { toastMessage ->
|
||||
val message = toastMessage.message ?: toastMessage.resId?.let(::getString)
|
||||
message?.let { text ->
|
||||
Toast.makeText(applicationContext, text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
@@ -381,10 +389,10 @@ class AuditionRoleDetailActivity : BaseActivity<ActivityAuditionRoleDetailBindin
|
||||
|
||||
if (roleDetail.isAlreadyApplicant) {
|
||||
reApplication = true
|
||||
binding.tvApplicant.text = "오디션 재지원"
|
||||
binding.tvApplicant.text = getString(R.string.screen_audition_apply_again)
|
||||
} else {
|
||||
reApplication = false
|
||||
binding.tvApplicant.text = "오디션 지원"
|
||||
binding.tvApplicant.text = getString(R.string.screen_audition_apply)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ import kr.co.vividnext.sodalive.audition.applicant.ApplyAuditionRoleRequest
|
||||
import kr.co.vividnext.sodalive.audition.applicant.GetAuditionRoleApplicantItem
|
||||
import kr.co.vividnext.sodalive.audition.vote.VoteAuditionApplicantRequest
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
@@ -24,8 +26,8 @@ import java.io.File
|
||||
import java.util.TimeZone
|
||||
|
||||
class AuditionRoleDetailViewModel(private val repository: AuditionRepository) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<ToastMessage?>()
|
||||
val toastLiveData: LiveData<ToastMessage?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _isLoading = MutableLiveData(false)
|
||||
@@ -90,9 +92,10 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
_auditionRoleDetailLiveData.value = roleDetailResponse.data!!
|
||||
} else {
|
||||
if (roleDetailResponse.message != null) {
|
||||
_toastLiveData.value = roleDetailResponse.message
|
||||
_toastLiveData.value = ToastMessage(message = roleDetailResponse.message)
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value =
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
@@ -113,9 +116,10 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
}
|
||||
} else {
|
||||
if (applicantListResponse.message != null) {
|
||||
_toastLiveData.value = applicantListResponse.message
|
||||
_toastLiveData.value = ToastMessage(message = applicantListResponse.message)
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value =
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
@@ -128,7 +132,9 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
@@ -166,9 +172,10 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.value = it.message
|
||||
_toastLiveData.value = ToastMessage(message = it.message)
|
||||
} else {
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value =
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +184,9 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -186,7 +195,8 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
|
||||
fun applyAudition(auditionRoleId: Long, phoneNumber: String, onSuccess: () -> Unit) {
|
||||
if (audioFile == null) {
|
||||
_toastLiveData.value = "잘못된 녹음 파일 입니다.\n다시 선택해 주세요."
|
||||
_toastLiveData.value =
|
||||
ToastMessage(resId = R.string.screen_audition_invalid_audio_file)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -236,10 +246,10 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
_toastLiveData.postValue(ToastMessage(message = it.message))
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -248,7 +258,7 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -304,11 +314,11 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
) {
|
||||
onFailure()
|
||||
} else {
|
||||
_toastLiveData.value = it.message
|
||||
_toastLiveData.value = ToastMessage(message = it.message)
|
||||
}
|
||||
} else {
|
||||
_toastLiveData.value =
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +327,8 @@ class AuditionRoleDetailViewModel(private val repository: AuditionRepository) :
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value =
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,6 +17,9 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||
import kr.co.vividnext.sodalive.settings.language.LocaleHelper
|
||||
import kotlin.math.max
|
||||
|
||||
abstract class BaseActivity<T : ViewBinding>(
|
||||
@@ -43,6 +46,12 @@ abstract class BaseActivity<T : ViewBinding>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
// 앱 설정 언어가 있으면 해당 Locale을 적용한 Context로 래핑한다.
|
||||
val wrapped = LocaleHelper.wrap(newBase)
|
||||
super.attachBaseContext(wrapped)
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -103,7 +112,8 @@ abstract class BaseActivity<T : ViewBinding>(
|
||||
layoutInflater = layoutInflater,
|
||||
title = "포인트 지급",
|
||||
desc = message,
|
||||
confirmButtonTitle = "확인",
|
||||
confirmButtonTitle = SodaLiveApplicationHolder.get()
|
||||
.getString(R.string.screen_live_tag_confirm),
|
||||
confirmButtonClick = {}
|
||||
).show(screenWidth)
|
||||
}
|
||||
|
||||
@@ -52,9 +52,15 @@ class ChatFragment : BaseFragment<FragmentChatBinding>(FragmentChatBinding::infl
|
||||
|
||||
private fun setupTabs() {
|
||||
// 탭 추가
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("캐릭터"))
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("작품별"))
|
||||
binding.tabLayout.addTab(binding.tabLayout.newTab().setText("톡"))
|
||||
binding.tabLayout.addTab(
|
||||
binding.tabLayout.newTab().setText(R.string.screen_chat_tab_character)
|
||||
)
|
||||
binding.tabLayout.addTab(
|
||||
binding.tabLayout.newTab().setText(R.string.screen_chat_tab_original)
|
||||
)
|
||||
binding.tabLayout.addTab(
|
||||
binding.tabLayout.newTab().setText(R.string.screen_chat_tab_talk)
|
||||
)
|
||||
|
||||
// 탭 선택 리스너 설정
|
||||
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
|
||||
@@ -6,12 +6,12 @@ import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterImageList
|
||||
import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterImagePurchaseRequest
|
||||
import kr.co.vividnext.sodalive.chat.character.detail.gallery.CharacterImagePurchaseResponse
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface CharacterApi {
|
||||
@GET("/api/chat/character/main")
|
||||
|
||||
@@ -379,12 +379,11 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
SodaDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "본인인증",
|
||||
desc = "보이스온의 오픈월드 캐릭터톡은\n청소년 보호를 위해 본인인증한\n성인만 이용이 가능합니다.\n" +
|
||||
"캐릭터톡 서비스를 이용하시려면\n본인인증을 하고 이용해주세요.",
|
||||
confirmButtonTitle = "본인인증 하러가기",
|
||||
title = getString(R.string.auth_title),
|
||||
desc = getString(R.string.auth_desc),
|
||||
confirmButtonTitle = getString(R.string.auth_go),
|
||||
confirmButtonClick = { startAuthFlow() },
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonTitle = getString(R.string.cancel),
|
||||
cancelButtonClick = {},
|
||||
descGravity = Gravity.CENTER
|
||||
).show(screenWidth)
|
||||
@@ -430,7 +429,10 @@ class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
val text = it?.message ?: it?.resId?.let { resId -> getString(resId) }
|
||||
if (!text.isNullOrBlank()) {
|
||||
Toast.makeText(requireActivity(), text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.chat.character
|
||||
|
||||
class CharacterTabRepository(private val api: CharacterApi) {
|
||||
fun getCharacterMain(
|
||||
token: String
|
||||
) = api.getCharacterMain(authHeader = token)
|
||||
fun getCharacterMain(token: String) = api.getCharacterMain(authHeader = token)
|
||||
|
||||
fun refreshRecommendCharacters(
|
||||
token: String
|
||||
|
||||
@@ -5,9 +5,11 @@ 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.R
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||
|
||||
class CharacterTabViewModel(
|
||||
private val repository: CharacterTabRepository
|
||||
@@ -16,8 +18,8 @@ class CharacterTabViewModel(
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<ToastMessage?>()
|
||||
val toastLiveData: LiveData<ToastMessage?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _bannerListLiveData = MutableLiveData<List<CharacterBannerResponse>>()
|
||||
@@ -48,7 +50,9 @@ class CharacterTabViewModel(
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.getCharacterMain(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
repository.getCharacterMain(
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
@@ -61,15 +65,18 @@ class CharacterTabViewModel(
|
||||
_newCharacters.value = data.newCharacters
|
||||
_recommendCharacters.value = data.recommendCharacters
|
||||
} else {
|
||||
_toastLiveData.value =
|
||||
it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = it.message?.let { message ->
|
||||
ToastMessage(message = message)
|
||||
} ?: ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -78,7 +85,9 @@ class CharacterTabViewModel(
|
||||
fun refreshRecommendCharacters() {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository.refreshRecommendCharacters(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
repository.refreshRecommendCharacters(
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
@@ -86,15 +95,18 @@ class CharacterTabViewModel(
|
||||
if (response.success && response.data != null) {
|
||||
_recommendCharacters.value = response.data
|
||||
} else {
|
||||
_toastLiveData.value = response.message
|
||||
?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.value = response.message?.let { message ->
|
||||
ToastMessage(message = message)
|
||||
} ?: ToastMessage(resId = R.string.common_error_unknown)
|
||||
}
|
||||
_isLoading.value = false
|
||||
},
|
||||
{ throwable ->
|
||||
_isLoading.value = false
|
||||
throwable.message?.let { msg -> Logger.e(msg) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(
|
||||
ToastMessage(resId = R.string.common_error_unknown)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.UiText
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentListBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
@@ -173,8 +174,7 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) { msg ->
|
||||
|
||||
msg?.let { showToast(it) }
|
||||
msg?.let { showToast(it.asString(requireContext())) }
|
||||
}
|
||||
|
||||
viewModel.totalCommentCount.observe(viewLifecycleOwner) { count ->
|
||||
|
||||
@@ -6,14 +6,16 @@ import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.UiText
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class CharacterCommentListViewModel(
|
||||
private val repository: CharacterCommentRepository
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
private val _toastLiveData = MutableLiveData<UiText?>()
|
||||
val toastLiveData: LiveData<UiText?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _isLoading = MutableLiveData(false)
|
||||
@@ -80,14 +82,16 @@ class CharacterCommentListViewModel(
|
||||
// 응답 아이템 전달 (비어있어도 전달) — UI는 addAll 처리
|
||||
_commentList.postValue(items)
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
onFailure?.invoke()
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character comments load failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
onFailure?.invoke()
|
||||
})
|
||||
)
|
||||
@@ -95,7 +99,7 @@ class CharacterCommentListViewModel(
|
||||
|
||||
fun createComment(characterId: Long, comment: String) {
|
||||
if (comment.isBlank()) {
|
||||
_toastLiveData.postValue("내용을 입력하세요")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.character_comment_error_empty))
|
||||
return
|
||||
}
|
||||
if (_isLoading.value == true) return
|
||||
@@ -119,13 +123,15 @@ class CharacterCommentListViewModel(
|
||||
cursor = null
|
||||
getCommentList(characterId)
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character comment create failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -151,20 +157,24 @@ class CharacterCommentListViewModel(
|
||||
cursor = null
|
||||
getCommentList(characterId)
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character comment delete failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fun reportComment(characterId: Long, commentId: Long, reason: String) {
|
||||
if (reason.isBlank()) {
|
||||
_toastLiveData.postValue("신고 사유를 입력하세요")
|
||||
_toastLiveData.postValue(
|
||||
UiText.StringResource(R.string.character_comment_error_report_reason)
|
||||
)
|
||||
return
|
||||
}
|
||||
if (_isLoading.value == true) return
|
||||
@@ -182,15 +192,19 @@ class CharacterCommentListViewModel(
|
||||
.subscribe({ resp ->
|
||||
_isLoading.value = false
|
||||
if (resp.success) {
|
||||
_toastLiveData.postValue("신고가 접수되었습니다.")
|
||||
_toastLiveData.postValue(
|
||||
UiText.StringResource(R.string.character_comment_report_submitted)
|
||||
)
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character comment report failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ class CharacterReplyHeaderVH(
|
||||
) : CharacterReplyVH(binding) {
|
||||
override fun bind(item: Any) {
|
||||
val data = item as CharacterCommentResponse
|
||||
val context = binding.root.context
|
||||
if (data.memberProfileImage.isNotBlank()) {
|
||||
binding.ivCommentProfile.load(data.memberProfileImage) {
|
||||
crossfade(true)
|
||||
@@ -71,7 +72,7 @@ class CharacterReplyHeaderVH(
|
||||
binding.ivCommentProfile.setImageResource(R.drawable.ic_placeholder_profile)
|
||||
}
|
||||
binding.tvCommentNickname.text = data.memberNickname
|
||||
binding.tvCommentDate.text = timeAgo(data.createdAt)
|
||||
binding.tvCommentDate.text = formatCommentTime(context, data.createdAt)
|
||||
binding.tvComment.text = data.comment
|
||||
binding.tvWriteReply.visibility = View.GONE
|
||||
binding.ivMenu.visibility = View.GONE
|
||||
@@ -86,6 +87,7 @@ class CharacterReplyItemVH(
|
||||
|
||||
override fun bind(item: Any) {
|
||||
val data = item as CharacterReplyResponse
|
||||
val context = binding.root.context
|
||||
if (data.memberProfileImage.isNotBlank()) {
|
||||
binding.ivCommentProfile.load(data.memberProfileImage) {
|
||||
crossfade(true)
|
||||
@@ -98,7 +100,7 @@ class CharacterReplyItemVH(
|
||||
}
|
||||
|
||||
binding.tvCommentNickname.text = data.memberNickname
|
||||
binding.tvCommentDate.text = timeAgo(data.createdAt)
|
||||
binding.tvCommentDate.text = formatCommentTime(context, data.createdAt)
|
||||
binding.tvComment.text = data.comment
|
||||
|
||||
val isOwner = data.memberId == currentUserId
|
||||
@@ -109,17 +111,3 @@ class CharacterReplyItemVH(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun timeAgo(createdAtMillis: Long): String {
|
||||
val now = System.currentTimeMillis()
|
||||
val diff = (now - createdAtMillis).coerceAtLeast(0)
|
||||
val minutes = diff / 60_000
|
||||
if (minutes < 1) return "방금전"
|
||||
if (minutes < 60) return "${minutes}분전"
|
||||
val hours = minutes / 60
|
||||
if (hours < 24) return "${hours}시간전"
|
||||
val days = hours / 24
|
||||
if (days < 365) return "${days}일전"
|
||||
val years = days / 365
|
||||
return "${years}년전"
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.UiText
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentReplyBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
@@ -179,7 +180,7 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
||||
if (loading) loadingDialog.show(screenWidth) else loadingDialog.dismiss()
|
||||
}
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) { msg ->
|
||||
msg?.let { showToast(it) }
|
||||
msg?.let { showToast(it.asString(requireContext())) }
|
||||
}
|
||||
viewModel.replies.observe(viewLifecycleOwner) { list ->
|
||||
// 헤더(원본 댓글)는 index 0에 유지, 나머지를 교체
|
||||
|
||||
@@ -6,14 +6,16 @@ import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.common.UiText
|
||||
|
||||
class CharacterCommentReplyViewModel(
|
||||
private val repository: CharacterCommentRepository
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?> get() = _toastLiveData
|
||||
private val _toastLiveData = MutableLiveData<UiText?>()
|
||||
val toastLiveData: LiveData<UiText?> get() = _toastLiveData
|
||||
|
||||
private val _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean> get() = _isLoading
|
||||
@@ -65,20 +67,22 @@ class CharacterCommentReplyViewModel(
|
||||
cursor = resp.data.cursor
|
||||
page += 1
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character replies load failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fun createReply(characterId: Long, comment: String) {
|
||||
if (comment.isBlank()) {
|
||||
_toastLiveData.postValue("내용을 입력하세요")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.character_comment_error_empty))
|
||||
return
|
||||
}
|
||||
val originalId = _original.value?.commentId ?: return
|
||||
@@ -110,13 +114,15 @@ class CharacterCommentReplyViewModel(
|
||||
val current = _replies.value ?: emptyList()
|
||||
_replies.postValue(current + listOf(me))
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character reply create failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -139,20 +145,24 @@ class CharacterCommentReplyViewModel(
|
||||
val current = _replies.value ?: emptyList()
|
||||
_replies.postValue(current.filterNot { it.replyId == replyId })
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character reply delete failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fun reportReply(characterId: Long, replyId: Long, reason: String) {
|
||||
if (reason.isBlank()) {
|
||||
_toastLiveData.postValue("신고 사유를 입력하세요")
|
||||
_toastLiveData.postValue(
|
||||
UiText.StringResource(R.string.character_comment_error_report_reason)
|
||||
)
|
||||
return
|
||||
}
|
||||
if (_isLoading.value == true) return
|
||||
@@ -170,15 +180,19 @@ class CharacterCommentReplyViewModel(
|
||||
.subscribe({ resp ->
|
||||
_isLoading.value = false
|
||||
if (resp.success) {
|
||||
_toastLiveData.postValue("신고가 접수되었습니다.")
|
||||
_toastLiveData.postValue(
|
||||
UiText.StringResource(R.string.character_comment_report_submitted)
|
||||
)
|
||||
} else {
|
||||
val message = resp.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
val message = resp.message?.takeIf { it.isNotBlank() }
|
||||
?.let { UiText.DynamicString(it) }
|
||||
?: UiText.StringResource(R.string.common_error_unknown)
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
}, { e ->
|
||||
_isLoading.value = false
|
||||
Logger.e(e, "Character reply report failed")
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_toastLiveData.postValue(UiText.StringResource(R.string.common_error_unknown))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,12 +27,14 @@ class CharacterCommentReportBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
var onSubmit: ((String) -> Unit)? = null
|
||||
|
||||
private var reasons: ArrayList<String>? = null
|
||||
private var reasons: ArrayList<String> = ArrayList()
|
||||
private var selectedIndex: Int = -1
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
reasons = arguments?.getStringArrayList(ARG_REASONS) ?: DEFAULT_REASONS
|
||||
val defaultReasons = resources.getStringArray(R.array.character_comment_report_reasons)
|
||||
.toCollection(ArrayList())
|
||||
reasons = arguments?.getStringArrayList(ARG_REASONS) ?: defaultReasons
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -49,7 +51,7 @@ class CharacterCommentReportBottomSheet : BottomSheetDialogFragment() {
|
||||
tvTitle.text = getString(R.string.report_title)
|
||||
setReportEnabled(btnReport, false)
|
||||
|
||||
val items = reasons ?: DEFAULT_REASONS
|
||||
val items = reasons
|
||||
val textColor = ContextCompat.getColor(requireContext(), R.color.white)
|
||||
|
||||
// RadioButton 동적 생성 및 단일 선택 처리
|
||||
@@ -64,8 +66,9 @@ class CharacterCommentReportBottomSheet : BottomSheetDialogFragment() {
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
|
||||
// 폰트: pretendard_regular
|
||||
try {
|
||||
typeface = ResourcesCompat.getFont(context, R.font.pretendard_regular)
|
||||
} catch (_: Exception) { /* 폰트 미존재 대비 안전 처리 */ }
|
||||
typeface = ResourcesCompat.getFont(context, R.font.regular)
|
||||
} catch (_: Exception) { /* 폰트 미존재 대비 안전 처리 */
|
||||
}
|
||||
// 항목 간 간격: 기존 paddingVertical 12dp의 1.3배 -> 15.6dp
|
||||
val vPadPx = (14f * resources.displayMetrics.density).toInt()
|
||||
setPadding(paddingLeft, vPadPx, paddingRight, vPadPx)
|
||||
@@ -106,16 +109,6 @@ class CharacterCommentReportBottomSheet : BottomSheetDialogFragment() {
|
||||
companion object {
|
||||
private const val ARG_REASONS = "arg_reasons"
|
||||
|
||||
private val DEFAULT_REASONS = arrayListOf(
|
||||
"원치 않는 상업성 콘텐츠 또는 스팸",
|
||||
"아동 학대",
|
||||
"증오시 표현 또는 노골적인 폭력",
|
||||
"테러 조장",
|
||||
"희롱 또는 괴롭힘",
|
||||
"자살 또는 자해",
|
||||
"잘못된 정보"
|
||||
)
|
||||
|
||||
fun newInstance(reasons: ArrayList<String>? = null): CharacterCommentReportBottomSheet {
|
||||
return CharacterCommentReportBottomSheet().apply {
|
||||
arguments = bundleOf(ARG_REASONS to reasons)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package kr.co.vividnext.sodalive.chat.character.comment
|
||||
|
||||
import android.content.Context
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
fun formatCommentTime(context: Context, createdAtMillis: Long): String {
|
||||
val now = System.currentTimeMillis()
|
||||
val diff = (now - createdAtMillis).coerceAtLeast(0)
|
||||
val minutes = diff / 60_000
|
||||
return when {
|
||||
minutes < 1 -> context.getString(R.string.character_comment_time_just_now)
|
||||
minutes < 60 -> context.getString(R.string.character_comment_time_minutes, minutes)
|
||||
minutes < 1_440 -> {
|
||||
val hours = minutes / 60
|
||||
context.getString(R.string.character_comment_time_hours, hours)
|
||||
}
|
||||
minutes < 525_600 -> {
|
||||
val days = minutes / 1_440
|
||||
context.getString(R.string.character_comment_time_days, days)
|
||||
}
|
||||
else -> {
|
||||
val years = minutes / 525_600
|
||||
context.getString(R.string.character_comment_time_years, years)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user