Compare commits

..

20 Commits

Author SHA1 Message Date
klaus a4ff89cec0 사용하지 않는 아이콘 제거 2024-10-15 23:54:52 +09:00
klaus b489f46910 푸시 알림 아이콘 - 앱 로고 아이콘으로 변경 2024-10-15 23:53:31 +09:00
klaus 4a167a00bd 권한 수정 2024-10-15 19:02:10 +09:00
klaus 2aca7620e7 권한 수정 2024-10-14 17:51:43 +09:00
klaus 1f7f3bfdb1 큐레이션 콘텐츠
- 남성향이면 여성 크리에이터, 여성향이면 남성 크리에이터 작품만 조회되도록 수정
2024-10-14 02:21:39 +09:00
klaus 90ff8ceb72 콘텐츠 메인 - 추천시리즈, 모닝콜, 숏플, 라이브 다시보기
- 남성향이면 여성 크리에이터, 여성향이면 남성 크리에이터 작품만 조회되도록 수정
2024-10-14 01:34:35 +09:00
klaus e8b69cc6b9 가이드 이미지 변경 2024-10-13 22:04:35 +09:00
klaus 9143e74a72 소다로 살다 -> 보이스 모닝콜 등록 변경 2024-10-13 21:55:51 +09:00
klaus 7bb6e2ae45 스플래시 이미지
- 글자 크기 변경
2024-10-13 21:21:02 +09:00
klaus 6f4f500aec 소다라이브 -> 보이스온 2024-10-12 01:17:48 +09:00
klaus d328bdb4d1 스플래시 변경 2024-10-12 01:03:26 +09:00
klaus 7cb3d19e85 콘텐츠 전체 보기
- 콘텐츠 제목 영역과 가격 표시 영역이 겹치지 않도록 수정
2024-10-11 19:40:25 +09:00
klaus 7c320b7f23 콘텐츠, 라이브 메인
- 보이스 모닝콜 메뉴 추가
- 라이브 다시듣기 메뉴 라이브 메인으로 이동
2024-10-11 14:11:56 +09:00
klaus f2cca1e14b 설정
- 19금 콘텐츠 보기 설정 UI depth 추가
- 콘텐츠 보기 설정으로 제목 변경
2024-10-10 15:42:19 +09:00
klaus f3553c3c59 라이브, 콘텐츠 메인 - 새로운 콘텐츠, 큐레이션
- 민감한 콘텐츠(19금) 설정 추가
2024-10-10 13:36:33 +09:00
klaus 5daddc5fef 설정
- 19금 콘텐츠 보기 설정 UI 추가
2024-10-10 13:10:40 +09:00
klaus 8cee9fb019 라이브 메뉴 설정 페이지 추가 2024-10-08 16:13:30 +09:00
klaus 38e4122570 크리에이터 채널
- 메뉴 설정 버튼 추가
2024-10-07 23:41:59 +09:00
klaus 3c178dbb96 룰렛 설정 완료 메시지
- 채널에서 새 룰렛을 저장할 때 성공메시지 수정
2024-10-04 13:58:40 +09:00
klaus 4537a95d2d 불필요한 파일 삭제 2024-10-03 00:50:50 +09:00
89 changed files with 1102 additions and 764 deletions

View File

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-09-30T12:57:26.128603Z">
<DropdownSelection timestamp="2024-10-14T08:13:14.161127Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/klaus/.android/avd/Pixel_8_Pro_API_34.avd" />
<DeviceId pluginId="PhysicalDevice" identifier="serial=2cec640c34017ece" />
</handle>
</Target>
</DropdownSelection>

View File

@ -25,6 +25,17 @@
<option name="screenX" value="1080" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="Lenovo" />
<option name="codename" value="TB370FU" />
<option name="id" value="TB370FU" />
<option name="manufacturer" value="Lenovo" />
<option name="name" value="Tab P12" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1840" />
<option name="screenY" value="2944" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="samsung" />

View File

@ -35,8 +35,8 @@ android {
applicationId "kr.co.vividnext.sodalive"
minSdk 23
targetSdk 34
versionCode 109
versionName "1.19.2"
versionCode 117
versionName "1.21.2"
}
buildTypes {

View File

@ -12,11 +12,8 @@
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission
android:name="android.permission.BLUETOOTH"
@ -123,6 +120,7 @@
<activity android:name=".settings.event.EventActivity" />
<activity android:name=".settings.event.EventDetailActivity" />
<activity android:name=".settings.notification.NotificationSettingsActivity" />
<activity android:name=".settings.ContentSettingsActivity" />
<activity android:name=".live.reservation_status.LiveReservationStatusActivity" />
<activity android:name=".live.reservation_status.LiveReservationCancelActivity" />
<activity android:name=".audio_content.AudioContentActivity" />
@ -143,6 +141,7 @@
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
<activity android:name=".audio_content.all.by_theme.AudioContentAllByThemeActivity" />
<activity android:name=".live.roulette.config.RouletteConfigActivity" />
<activity android:name=".live.room.menu.MenuConfigActivity" />
<activity android:name=".audio_content.series.SeriesListAllActivity" />
<activity android:name=".audio_content.series.detail.SeriesDetailActivity" />
<activity android:name=".audio_content.series.content.SeriesContentAllActivity" />

View File

@ -21,6 +21,7 @@ import kr.co.vividnext.sodalive.audio_content.order.OrderRequest
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.explorer.profile.GetAudioContentListResponse
import kr.co.vividnext.sodalive.settings.ContentType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.Body
@ -53,6 +54,8 @@ interface AudioContentApi {
@GET("/audio-content/theme/{id}/content")
fun getAudioContentByTheme(
@Path("id") id: Long,
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("contentType") contentType: ContentType,
@Query("page") page: Int,
@Query("size") size: Int,
@Query("sort-type") sort: AudioContentViewModel.Sort,
@ -141,12 +144,16 @@ interface AudioContentApi {
@GET("/audio-content/main/new")
fun getNewContentOfTheme(
@Query("theme") theme: String,
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("contentType") contentType: ContentType,
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetAudioContentMainItem>>>
@GET("/audio-content/main/new/all")
fun getNewContentAllOfTheme(
@Query("theme") theme: String,
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("contentType") contentType: ContentType,
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
@ -167,6 +174,8 @@ interface AudioContentApi {
@GET("/audio-content/curation/{id}")
fun getAudioContentListByCurationId(
@Path("id") id: Long,
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("contentType") contentType: ContentType,
@Query("page") page: Int,
@Query("size") size: Int,
@Query("sort-type") sort: AudioContentViewModel.Sort,
@ -193,6 +202,8 @@ interface AudioContentApi {
@GET("/audio-content/main/curation-list")
fun getCurationList(
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("contentType") contentType: ContentType,
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String

View File

@ -481,7 +481,7 @@ class AudioContentPlayService :
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val notificationBuilder = NotificationCompat
.Builder(this@AudioContentPlayService, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(resource)
.setContentTitle(title ?: "오디오 콘텐츠")
.setContentText(nickname ?: "")

View File

@ -5,6 +5,8 @@ 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.settings.ContentType
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
import kr.co.vividnext.sodalive.user.UserApi
import okhttp3.MultipartBody
@ -24,6 +26,8 @@ class AudioContentRepository(
token: String
) = api.getAudioContentListByCurationId(
id = curationId,
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
page = page - 1,
size = size,
sort = sort,
@ -135,6 +139,8 @@ class AudioContentRepository(
fun getNewContentOfTheme(theme: String, token: String) = api.getNewContentOfTheme(
theme = theme,
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
authHeader = token
)
@ -145,6 +151,8 @@ class AudioContentRepository(
token: String
) = api.getNewContentAllOfTheme(
theme = theme,
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
page = page - 1,
size = size,
authHeader = token
@ -181,6 +189,8 @@ class AudioContentRepository(
)
fun getCurationList(page: Int, size: Int, token: String) = api.getCurationList(
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
page = page - 1,
size = size,
authHeader = token
@ -215,6 +225,8 @@ class AudioContentRepository(
token: String
) = api.getAudioContentByTheme(
id = themeId,
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
page = page - 1,
size = size,
sort = sort,

View File

@ -387,7 +387,7 @@ class AudioContentDetailViewModel(
}
socialMetaTagParameters {
title = contentTitle
description = "지금 소다라이브에서 이 콘텐츠 감상하기"
description = "지금 보이스온에서 이 콘텐츠 감상하기"
imageUrl = contentImage.toUri()
}
}.addOnSuccessListener {

View File

@ -115,10 +115,10 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
)
}
binding.llReviewLive.setOnClickListener {
binding.llMorningCall.setOnClickListener {
startActivity(
Intent(requireContext(), AudioContentAllByThemeActivity::class.java).apply {
putExtra(Constants.EXTRA_THEME_ID, 7L)
putExtra(Constants.EXTRA_THEME_ID, 12L)
}
)
}

View File

@ -112,7 +112,7 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
private fun checkPermissions() {
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
listOf(Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
listOf(Manifest.permission.READ_MEDIA_AUDIO)
} else {
listOf(Manifest.permission.READ_EXTERNAL_STORAGE)
}

View File

@ -4,6 +4,7 @@ import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesContentListResponse
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesDetailResponse
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.settings.ContentType
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Path
@ -36,6 +37,8 @@ interface SeriesApi {
@GET("/audio-content/series/recommend")
fun getRecommendSeriesList(
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("contentType") contentType: ContentType,
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetSeriesListResponse.SeriesListItem>>>
}

View File

@ -1,5 +1,8 @@
package kr.co.vividnext.sodalive.audio_content.series
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.settings.ContentType
class SeriesRepository(private val api: SeriesApi) {
fun getSeriesList(
creatorId: Long,
@ -34,5 +37,9 @@ class SeriesRepository(private val api: SeriesApi) {
authHeader = token
)
fun getRecommendSeriesList(token: String) = api.getRecommendSeriesList(authHeader = token)
fun getRecommendSeriesList(token: String) = api.getRecommendSeriesList(
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
authHeader = token
)
}

View File

@ -297,7 +297,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
private fun checkPermissions() {
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
listOf(Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
listOf(Manifest.permission.READ_MEDIA_AUDIO)
} else {
listOf(Manifest.permission.READ_EXTERNAL_STORAGE)
}

View File

@ -11,7 +11,9 @@ object Constants {
const val PREF_NO_CHAT_ROOM = "pref_no_chat"
const val PREF_PUSH_TOKEN = "pref_push_token"
const val PREF_PROFILE_IMAGE = "pref_profile_image"
const val PREF_CONTENT_PREFERENCE = "pref_content_preference"
const val PREF_IS_CONTENT_PLAY_LOOP = "pref_is_content_play_loop"
const val PREF_IS_ADULT_CONTENT_VISIBLE = "pref_is_adult_content_visible"
const val PREF_IS_FOLLOWED_CREATOR_LIVE = "pref_is_followed_creator_live"
const val PREF_NOT_SHOWING_EVENT_POPUP_ID = "pref_not_showing_event_popup_id"
const val PREF_IS_VIEWED_ON_BOARDING_TUTORIAL = "pref_is_viewed_on_boarding_tutorial"

View File

@ -95,6 +95,18 @@ object SharedPreferenceManager {
sharedPreferences[Constants.PREF_IS_ADULT] = value
}
var isAdultContentVisible: Boolean
get() = sharedPreferences[Constants.PREF_IS_ADULT_CONTENT_VISIBLE, true]
set(value) {
sharedPreferences[Constants.PREF_IS_ADULT_CONTENT_VISIBLE] = value
}
var contentPreference: Int
get() = sharedPreferences[Constants.PREF_CONTENT_PREFERENCE, 0]
set(value) {
sharedPreferences[Constants.PREF_CONTENT_PREFERENCE] = value
}
var pushToken: String
get() = sharedPreferences[Constants.PREF_PUSH_TOKEN, ""]
set(value) {

View File

@ -76,7 +76,7 @@ class SodaLiveService : Service() {
)
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
.setSmallIcon(R.drawable.ic_notification)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentText(content)
.setOngoing(true)

View File

@ -59,6 +59,8 @@ import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailViewModel
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
import kr.co.vividnext.sodalive.live.room.menu.MenuApi
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigRepository
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigViewModel
import kr.co.vividnext.sodalive.live.room.tag.LiveTagRepository
import kr.co.vividnext.sodalive.live.room.tag.LiveTagViewModel
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditViewModel
@ -102,6 +104,7 @@ import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterViewModel
import kr.co.vividnext.sodalive.network.TokenAuthenticator
import kr.co.vividnext.sodalive.report.ReportApi
import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.settings.ContentSettingsViewModel
import kr.co.vividnext.sodalive.settings.SettingsViewModel
import kr.co.vividnext.sodalive.settings.event.EventApi
import kr.co.vividnext.sodalive.settings.event.EventRepository
@ -219,6 +222,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { NoticeViewModel(get()) }
viewModel { EventViewModel(get()) }
viewModel { NotificationSettingsViewModel(get()) }
viewModel { ContentSettingsViewModel() }
viewModel { SettingsViewModel(get()) }
viewModel { SeriesDetailViewModel(get(), get()) }
viewModel { SeriesListAllViewModel(get()) }
@ -260,6 +264,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { AlarmListViewModel(get()) }
viewModel { BlockMemberViewModel(get()) }
viewModel { UserViewModel(get(), get()) }
viewModel { MenuConfigViewModel(get()) }
}
private val repositoryModule = module {
@ -287,6 +292,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
factory { RouletteRepository(get()) }
factory { CreatorCommunityRepository(get()) }
factory { AlarmListRepository(get()) }
factory { MenuConfigRepository(get()) }
}
private val moduleList = listOf(

View File

@ -52,6 +52,7 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.loadUrl
import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigActivity
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
@ -800,6 +801,12 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
}
)
}
binding.layoutUserProfileLive.tvSettingMenu.setOnClickListener {
startActivity(
Intent(applicationContext, MenuConfigActivity::class.java)
)
}
} else {
binding.layoutUserProfileLive.llRouletteMenu.visibility = View.GONE

View File

@ -318,7 +318,7 @@ class UserProfileViewModel(
}.addOnSuccessListener {
val uri = it.shortLink
if (uri != null) {
onSuccess("소다라이브 ${creatorNickname}님의 채널입니다.\n$uri")
onSuccess("보이스온 ${creatorNickname}님의 채널입니다.\n$uri")
}
}.addOnFailureListener {
_toastLiveData.postValue("공유링크를 생성하지 못했습니다.\n다시 시도해 주세요.")

View File

@ -128,7 +128,7 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
private fun checkPermissions() {
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
listOf(Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
listOf(Manifest.permission.READ_MEDIA_AUDIO)
} else {
listOf(Manifest.permission.READ_EXTERNAL_STORAGE)
}

View File

@ -134,7 +134,7 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
private fun checkPermissions() {
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
listOf(Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
listOf(Manifest.permission.READ_MEDIA_AUDIO)
} else {
listOf(Manifest.permission.READ_EXTERNAL_STORAGE)
}

View File

@ -80,7 +80,7 @@ class SodaFirebaseMessagingService : FirebaseMessagingService() {
)
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
.setSmallIcon(R.drawable.ic_notification)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(messageData["title"])
.setContentText(messageData["message"])
.setSound(defaultSoundUri)

View File

@ -26,6 +26,7 @@ import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
import kr.co.vividnext.sodalive.live.room.tag.GetLiveTagResponse
import kr.co.vividnext.sodalive.settings.ContentType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.Body
@ -50,6 +51,7 @@ interface LiveApi {
@Query("timezone") timezone: String,
@Query("dateString") dateString: String?,
@Query("status") status: LiveRoomStatus,
@Query("isAdultContentVisible") isAdultContentVisible: Boolean,
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String

View File

@ -21,6 +21,7 @@ import com.zhpan.indicator.enums.IndicatorSlideMode
import com.zhpan.indicator.enums.IndicatorStyle
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
import kr.co.vividnext.sodalive.audio_content.all.by_theme.AudioContentAllByThemeActivity
import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
@ -99,6 +100,14 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
setupEvent()
setupCommunityPost()
binding.llReviewLive.setOnClickListener {
startActivity(
Intent(requireContext(), AudioContentAllByThemeActivity::class.java).apply {
putExtra(Constants.EXTRA_THEME_ID, 7L)
}
)
}
message = "라이브를 불러오고 있습니다."
viewModel.getSummary()
}

View File

@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.live
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationRequest
import kr.co.vividnext.sodalive.live.reservation_status.CancelLiveReservationRequest
import kr.co.vividnext.sodalive.live.room.CancelLiveRequest
@ -39,6 +40,7 @@ class LiveRepository(
timezone = TimeZone.getDefault().id,
dateString = dateString,
status = status,
isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
page = page - 1,
size = size,
authHeader = token

View File

@ -310,12 +310,12 @@ class LiveRoomViewModel(
if (uri != null) {
val message = if (isPrivateRoom) {
"${SharedPreferenceManager.nickname}님이 귀하를 " +
"소다라이브의 비공개라이브에 초대하였습니다.\n" +
"보이스온의 비공개라이브에 초대하였습니다.\n" +
"※ 라이브 참여: $uri\n" +
"(입장 비밀번호 : $password)"
} else {
"${SharedPreferenceManager.nickname}님이 귀하를 " +
"소다라이브의 공개라이브에 초대하였습니다.\n" +
"보이스온의 공개라이브에 초대하였습니다.\n" +
"※ 라이브 참여: $uri"
}

View File

@ -83,12 +83,12 @@ class LiveRoomDetailViewModel(private val repository: LiveRepository) : BaseView
if (uri != null) {
val message = if (isPrivateRoom) {
"${SharedPreferenceManager.nickname}님이 귀하를 " +
"소다라이브의 비공개라이브에 초대하였습니다.\n" +
"보이스온의 비공개라이브에 초대하였습니다.\n" +
"※ 라이브 참여: $uri\n" +
"(입장 비밀번호 : $password)"
} else {
"${SharedPreferenceManager.nickname}님이 귀하를 " +
"소다라이브의 공개라이브에 초대하였습니다.\n" +
"보이스온의 공개라이브에 초대하였습니다.\n" +
"※ 라이브 참여: $uri"
}

View File

@ -6,6 +6,6 @@ import com.google.gson.annotations.SerializedName
@Keep
data class GetMenuPresetResponse(
@SerializedName("id") val id: Long,
@SerializedName("menu") val menu: String,
@SerializedName("menu") var menu: String,
@SerializedName("isActive") val isActive: Boolean
)

View File

@ -2,8 +2,10 @@ package kr.co.vividnext.sodalive.live.room.menu
import io.reactivex.rxjava3.core.Single
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.Query
interface MenuApi {
@ -12,4 +14,10 @@ interface MenuApi {
@Query("creatorId") creatorId: Long,
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetMenuPresetResponse>>>
@POST("/live/room/menu")
fun saveMenu(
@Body request: UpdateLiveMenuRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
}

View File

@ -0,0 +1,186 @@
package kr.co.vividnext.sodalive.live.room.menu
import android.app.Service
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
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.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityMenuConfigBinding
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
import org.koin.android.ext.android.inject
import java.util.concurrent.TimeUnit
class MenuConfigActivity : BaseActivity<ActivityMenuConfigBinding>(
ActivityMenuConfigBinding::inflate
) {
private val viewModel: MenuConfigViewModel by inject()
private lateinit var imm: InputMethodManager
private lateinit var loadingDialog: LoadingDialog
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindData()
viewModel.getAllMenuPreset()
}
override fun setupView() {
binding.toolbar.tvBack.text = "메뉴 설정"
binding.toolbar.tvBack.setOnClickListener { finish() }
loadingDialog = LoadingDialog(this, layoutInflater)
imm = getSystemService(
Service.INPUT_METHOD_SERVICE
) as InputMethodManager
binding.tvSave.setOnClickListener {
handler.postDelayed({
imm.hideSoftInputFromWindow(currentFocus?.windowToken, 0)
}, 100)
// 저장 액션
viewModel.saveMenu()
}
binding.llSelectMenu1.setOnClickListener {
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_1)
}
binding.llSelectMenu2.setOnClickListener {
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_2)
}
binding.llSelectMenu3.setOnClickListener {
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
}
}
private fun bindData() {
viewModel.toastLiveData.observe(this) { it?.let { showToast(it) } }
viewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth)
} else {
loadingDialog.dismiss()
}
}
viewModel.selectedMenuLiveData.observe(this) {
deselectAllMenuPreset()
when (it) {
LiveRoomCreateViewModel.SelectedMenu.MENU_2 -> selectMenuPresetButton(
binding.ivSelectMenu2,
binding.llSelectMenu2,
binding.tvSelectMenu2
)
LiveRoomCreateViewModel.SelectedMenu.MENU_3 -> selectMenuPresetButton(
binding.ivSelectMenu3,
binding.llSelectMenu3,
binding.tvSelectMenu3
)
else -> selectMenuPresetButton(
binding.ivSelectMenu1,
binding.llSelectMenu1,
binding.tvSelectMenu1
)
}
}
viewModel.selectedMenuTextLiveData.observe(this) {
binding.etMenu.setText(it)
}
compositeDisposable.add(
binding.etMenu.textChanges().skip(1)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe {
viewModel.menuText = it.toString()
}
)
}
private fun deselectAllMenuPreset() {
binding.ivSelectMenu1.visibility = View.GONE
binding.ivSelectMenu2.visibility = View.GONE
binding.ivSelectMenu3.visibility = View.GONE
binding.llSelectMenu1.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectMenu1.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_3bb9f1
)
)
if (viewModel.countMenu() > 0) {
binding.llSelectMenu2.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectMenu2.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_3bb9f1
)
)
} else {
binding.llSelectMenu2.setBackgroundResource(R.drawable.bg_round_corner_6_7_777777)
binding.tvSelectMenu2.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_555555
)
)
}
if (viewModel.countMenu() > 1) {
binding.llSelectMenu3.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectMenu3.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_3bb9f1
)
)
} else {
binding.llSelectMenu3.setBackgroundResource(R.drawable.bg_round_corner_6_7_777777)
binding.tvSelectMenu3.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_555555
)
)
}
}
private fun selectMenuPresetButton(
ivSelectMenuPreset: ImageView,
llSelectMenuPreset: LinearLayout,
tvSelectMenuPreset: TextView
) {
ivSelectMenuPreset.visibility = View.VISIBLE
llSelectMenuPreset.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
tvSelectMenuPreset.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
}
}

View File

@ -0,0 +1,17 @@
package kr.co.vividnext.sodalive.live.room.menu
class MenuConfigRepository(private val api: MenuApi) {
fun getAllMenu(creatorId: Long, token: String) = api.getAllMenu(
creatorId = creatorId,
authHeader = token
)
fun saveMenu(menuId: Long, menu: String, token: String) = api.saveMenu(
request = UpdateLiveMenuRequest(
id = menuId,
menu = menu,
isActive = false
),
authHeader = token
)
}

View File

@ -0,0 +1,147 @@
package kr.co.vividnext.sodalive.live.room.menu
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.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
class MenuConfigViewModel(private val repository: MenuConfigRepository) : BaseViewModel() {
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private val _selectedMenuLiveData = MutableLiveData<LiveRoomCreateViewModel.SelectedMenu>()
val selectedMenuLiveData: LiveData<LiveRoomCreateViewModel.SelectedMenu>
get() = _selectedMenuLiveData
private val _selectedMenuTextLiveData = MutableLiveData("")
val selectedMenuTextLiveData: LiveData<String>
get() = _selectedMenuTextLiveData
private var menuId = 0L
private val menuList = mutableListOf<GetMenuPresetResponse>()
var menuText: String = ""
fun getAllMenuPreset(selectedMenu: LiveRoomCreateViewModel.SelectedMenu = LiveRoomCreateViewModel.SelectedMenu.MENU_1) {
_isLoading.value = true
compositeDisposable.add(
repository.getAllMenu(
creatorId = SharedPreferenceManager.userId,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success) {
val data = it.data ?: listOf()
menuList.clear()
menuList.addAll(data)
selectMenuPreset(selectedMenu)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun selectMenuPreset(selectedMenuPreset: LiveRoomCreateViewModel.SelectedMenu) {
if (
menuList.isEmpty() &&
(
selectedMenuPreset == LiveRoomCreateViewModel.SelectedMenu.MENU_2 ||
selectedMenuPreset == LiveRoomCreateViewModel.SelectedMenu.MENU_3
)
) {
_toastLiveData.value = "메뉴 1을 먼저 설정하세요"
return
}
if (menuList.size == 1 && selectedMenuPreset == LiveRoomCreateViewModel.SelectedMenu.MENU_3) {
_toastLiveData.value = "메뉴 1과 메뉴 2를 먼저 설정하세요"
return
}
if (_selectedMenuLiveData.value != selectedMenuPreset) {
_selectedMenuLiveData.value = selectedMenuPreset
if (menuList.size > selectedMenuPreset.ordinal) {
val menuPreset = menuList[selectedMenuPreset.ordinal]
menuText = menuPreset.menu
menuId = menuPreset.id
_selectedMenuTextLiveData.value = menuPreset.menu
} else {
menuText = ""
menuId = 0
_selectedMenuTextLiveData.value = ""
}
}
}
fun saveMenu() {
if (menuText == _selectedMenuTextLiveData.value) {
_toastLiveData.postValue("저장되었습니다.")
return
}
_isLoading.value = true
compositeDisposable.add(
repository.saveMenu(
menuId = menuId,
menu = menuText,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success) {
_toastLiveData.postValue("저장되었습니다.")
getAllMenuPreset(selectedMenu = _selectedMenuLiveData.value!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun countMenu() = menuList.size
}

View File

@ -0,0 +1,14 @@
package kr.co.vividnext.sodalive.live.room.menu
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
@Keep
data class UpdateLiveMenuRequest(
@SerializedName("id")
val id: Long,
@SerializedName("menu")
val menu: String,
@SerializedName("isActive")
val isActive: Boolean = false
)

View File

@ -59,7 +59,7 @@ class RouletteConfigActivity : BaseActivity<ActivityRouletteConfigBinding>(
}
override fun setupView() {
binding.tvBack.text = "룰렛설정"
binding.tvBack.text = "룰렛 설정"
binding.tvBack.setOnClickListener { finish() }
loadingDialog = LoadingDialog(this, layoutInflater)

View File

@ -1,333 +0,0 @@
package kr.co.vividnext.sodalive.live.roulette.config
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Service
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.InputFilter
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
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.base.BaseFragment
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.FragmentRouletteSettingsBinding
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
import org.koin.android.ext.android.inject
import java.util.Locale
import java.util.concurrent.TimeUnit
class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
FragmentRouletteSettingsBinding::inflate
) {
private val viewModel: RouletteSettingsViewModel by inject()
private lateinit var imm: InputMethodManager
private lateinit var loadingDialog: LoadingDialog
private val handler = Handler(Looper.getMainLooper())
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupView()
bindData()
viewModel.getAllRoulette()
}
private fun setupView() {
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
imm = requireActivity().getSystemService(
Service.INPUT_METHOD_SERVICE
) as InputMethodManager
binding.etSetPrice.filters = arrayOf(InputFilter { source, start, end, _, _, _ ->
// Only allow numeric input
for (i in start until end) {
if (!Character.isDigit(source[i])) {
return@InputFilter ""
}
}
null
})
binding.ivRouletteIsActive.setOnClickListener { viewModel.toggleIsActive() }
binding.ivAddOption.setOnClickListener { addOption() }
binding.tvPreview.setOnClickListener {
handler.postDelayed({
imm.hideSoftInputFromWindow(view?.windowToken, 0)
}, 100)
viewModel.onClickPreview()
}
binding.tvSave.setOnClickListener { _ ->
handler.postDelayed({
imm.hideSoftInputFromWindow(view?.windowToken, 0)
}, 100)
viewModel.createOrUpdateRoulette {
val resultIntent = Intent().apply { putExtra(Constants.EXTRA_RESULT_ROULETTE, it) }
requireActivity().setResult(Activity.RESULT_OK, resultIntent)
requireActivity().finish()
}
}
binding.llSelectRoulette1.setOnClickListener {
viewModel.selectRoulette(
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_1
)
}
binding.llSelectRoulette2.setOnClickListener {
viewModel.selectRoulette(
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2
)
}
binding.llSelectRoulette3.setOnClickListener {
viewModel.selectRoulette(
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_3
)
}
}
@SuppressLint("SetTextI18n")
private fun bindData() {
viewModel.selectedRouletteLiveData.observe(viewLifecycleOwner) {
deselectAllRoulette()
when (it) {
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2 -> selectRouletteButton(
binding.ivSelectRoulette2,
binding.llSelectRoulette2,
binding.tvSelectRoulette2
)
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_3 -> selectRouletteButton(
binding.ivSelectRoulette3,
binding.llSelectRoulette3,
binding.tvSelectRoulette3
)
else -> selectRouletteButton(
binding.ivSelectRoulette1,
binding.llSelectRoulette1,
binding.tvSelectRoulette1
)
}
}
viewModel.isActiveLiveData.observe(viewLifecycleOwner) {
binding.ivRouletteIsActive.setImageResource(
if (it) R.drawable.btn_toggle_on_big else R.drawable.btn_toggle_off_big
)
}
viewModel.optionsLiveData.observe(viewLifecycleOwner) { updateOptionUi(it) }
viewModel.toastLiveData.observe(viewLifecycleOwner) { it?.let { showToast(it) } }
viewModel.canLiveData.observe(viewLifecycleOwner) {
if (it > 0) {
binding.etSetPrice.setText("$it")
} else {
binding.etSetPrice.setText("")
}
}
viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) {
loadingDialog.show(screenWidth)
} else {
loadingDialog.dismiss()
}
}
viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) {
RoulettePreviewDialog(
activity = requireActivity(),
previewList = listOf(it),
title = "룰렛 미리보기",
layoutInflater = layoutInflater
).show()
}
viewModel.totalPercentageLiveData.observe(viewLifecycleOwner) {
binding.tvTotalPercentage.text = "( ${
String.format(
Locale.KOREAN,
"%.2f%%",
it
)
} )"
}
compositeDisposable.add(
binding.etSetPrice.textChanges().skip(1)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe {
if (it.trim().isNotEmpty()) {
viewModel.can = it.toString().toInt()
}
}
)
}
private fun addOption() {
val newOption = RouletteOption("", "")
viewModel.addOption(newOption)
}
private fun updateOptionUi(options: List<RouletteOption>) {
binding.llRouletteOptionContainer.removeAllViews()
options.forEachIndexed { index, option ->
binding.llRouletteOptionContainer.addView(createOptionView(index, option))
}
}
@SuppressLint("SetTextI18n")
private fun createOptionView(index: Int, option: RouletteOption): View {
val optionView = LayoutInflater
.from(context)
.inflate(
R.layout.layout_roulette_option,
binding.llRouletteOptionContainer,
false
)
val etOption = optionView.findViewById<EditText>(R.id.et_option)
val tvOptionTitle = optionView.findViewById<TextView>(R.id.tv_option_title)
val etPercentage = optionView.findViewById<EditText>(R.id.et_option_percentage)
val tvDelete = optionView.findViewById<TextView>(R.id.tv_delete)
etOption.setText(option.title)
tvOptionTitle.text = "옵션 ${index + 1}"
try {
if (option.percentage.toFloat() > 0f) {
etPercentage.setText(option.percentage)
} else {
etPercentage.setText("")
}
} catch (e: Exception) {
etPercentage.setText("")
}
if (index == 0 || index == 1) {
tvDelete.visibility = View.GONE
} else {
tvDelete.visibility = View.VISIBLE
tvDelete.setOnClickListener { viewModel.deleteOption(index) }
}
compositeDisposable.add(
etOption.textChanges().skip(1)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe {
viewModel.inputOption(index, it.toString())
}
)
compositeDisposable.add(
etPercentage.textChanges().skip(1)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe {
viewModel.inputOptionPercentage(index, it.toString())
}
)
return optionView
}
private fun deselectAllRoulette() {
binding.ivSelectRoulette1.visibility = View.GONE
binding.ivSelectRoulette2.visibility = View.GONE
binding.ivSelectRoulette3.visibility = View.GONE
binding.llSelectRoulette1.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectRoulette1.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.color_3bb9f1
)
)
if (viewModel.rouletteList.size > 0) {
binding.llSelectRoulette2.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectRoulette2.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.color_ffcb14
)
)
} else {
binding.llSelectRoulette2.setBackgroundResource(R.drawable.bg_round_corner_6_7_777777)
binding.tvSelectRoulette2.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.color_ff14d9
)
)
}
if (viewModel.rouletteList.size > 1) {
binding.llSelectRoulette3.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
binding.tvSelectRoulette3.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.color_3bb9f1
)
)
} else {
binding.llSelectRoulette3.setBackgroundResource(R.drawable.bg_round_corner_6_7_777777)
binding.tvSelectRoulette3.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.color_555555
)
)
}
}
private fun selectRouletteButton(
ivSelectRoulette: ImageView,
llSelectRoulette: LinearLayout,
tvSelectRoulette: TextView
) {
ivSelectRoulette.visibility = View.VISIBLE
llSelectRoulette.setBackgroundResource(
when (viewModel.selectedRouletteLiveData.value) {
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2 -> R.drawable.bg_round_corner_6_7_ffcb14
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_3 -> R.drawable.bg_round_corner_6_7_ff14d9
else -> R.drawable.bg_round_corner_6_7_3bb9f1
}
)
tvSelectRoulette.setTextColor(
ContextCompat.getColor(
requireContext(),
when (viewModel.selectedRouletteLiveData.value) {
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2 -> R.color.black
else -> R.color.color_eeeeee
}
)
)
}
}

View File

@ -246,8 +246,15 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
SelectedRoulette.ROULETTE_3 -> "룰렛 3"
}
val successMessage = "$selectedRouletteTitle " +
if (isActive || availableActive) "로 설정하였습니다." else "을 설정했습니다."
val successMessage = if (availableActive) {
if (isActive) {
"${selectedRouletteTitle}로 설정하였습니다."
} else {
"${selectedRouletteTitle}을 설정했습니다."
}
} else {
"${selectedRouletteTitle}을 생성했습니다."
}
compositeDisposable.add(
repository.createRoulette(

View File

@ -109,7 +109,7 @@ class AlarmListActivity : BaseActivity<ActivityAlarmListBinding>(
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.tvBack.text = "소다로 살다 (알람 등록)"
binding.tvBack.text = "보이스 모닝콜 등록"
binding.tvBack.setOnClickListener { finish() }
binding.ivPlus.setOnClickListener {
startActivity(

View File

@ -0,0 +1,111 @@
package kr.co.vividnext.sodalive.settings
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivityContentSettingsBinding
import kr.co.vividnext.sodalive.splash.SplashActivity
import org.koin.android.ext.android.inject
class ContentSettingsActivity : BaseActivity<ActivityContentSettingsBinding>(
ActivityContentSettingsBinding::inflate
) {
private val viewModel: ContentSettingsViewModel by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindData()
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
handleFinish()
}
})
}
override fun setupView() {
binding.toolbar.tvBack.text = "콘텐츠 보기 설정"
binding.toolbar.tvBack.setOnClickListener { handleFinish() }
// 본인 인증 체크
if (SharedPreferenceManager.isAuth) {
binding.llAdultContentVisible.visibility = View.VISIBLE
// 19금 콘텐츠 보기 체크
if (SharedPreferenceManager.isAdultContentVisible) {
binding.llAdultContentPreference.visibility = View.VISIBLE
} else {
binding.llAdultContentPreference.visibility = View.GONE
}
// 19금 콘텐츠 보기 스위치 액션
binding.ivAdultContentVisible.setOnClickListener {
viewModel.toggleAdultContentVisible()
}
binding.tvContentAll.setOnClickListener {
viewModel.setAdultContentPreference(ContentType.ALL)
}
binding.tvContentMale.setOnClickListener {
viewModel.setAdultContentPreference(ContentType.MALE)
}
binding.tvContentFemale.setOnClickListener {
viewModel.setAdultContentPreference(ContentType.FEMALE)
}
} else {
binding.llAdultContentVisible.visibility = View.GONE
}
}
private fun bindData() {
viewModel.isAdultContentVisible.observe(this) {
if (it) {
binding.ivAdultContentVisible.setImageResource(R.drawable.btn_toggle_on_big)
binding.llAdultContentPreference.visibility = View.VISIBLE
} else {
binding.ivAdultContentVisible.setImageResource(R.drawable.btn_toggle_off_big)
binding.llAdultContentPreference.visibility = View.GONE
}
}
viewModel.adultContentPreference.observe(this) {
binding.tvContentAll.isSelected = false
binding.tvContentMale.isSelected = false
binding.tvContentFemale.isSelected = false
when (it) {
ContentType.ALL -> binding.tvContentAll.isSelected = true
ContentType.MALE -> binding.tvContentMale.isSelected = true
ContentType.FEMALE -> binding.tvContentFemale.isSelected = true
else -> {}
}
}
}
private fun handleFinish() {
if (viewModel.isChangedAdultContentVisible) {
startActivity(
Intent(
this@ContentSettingsActivity,
SplashActivity::class.java
).apply {
addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_ACTIVITY_NEW_TASK
)
}
)
finish()
} else {
finish()
}
}
}

View File

@ -0,0 +1,39 @@
package kr.co.vividnext.sodalive.settings
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
class ContentSettingsViewModel : BaseViewModel() {
private var _isAdultContentVisible = MutableLiveData(
SharedPreferenceManager.isAdultContentVisible
)
val isAdultContentVisible: LiveData<Boolean>
get() = _isAdultContentVisible
private var _adultContentPreference = MutableLiveData(
ContentType.values()[SharedPreferenceManager.contentPreference]
)
val adultContentPreference: LiveData<ContentType>
get() = _adultContentPreference
var isChangedAdultContentVisible = false
fun toggleAdultContentVisible() {
val adultContentVisible = SharedPreferenceManager.isAdultContentVisible
_isAdultContentVisible.value = !adultContentVisible
SharedPreferenceManager.isAdultContentVisible = !adultContentVisible
isChangedAdultContentVisible = true
if (adultContentVisible) {
SharedPreferenceManager.contentPreference = ContentType.ALL.ordinal
}
}
fun setAdultContentPreference(adultContentPreference: ContentType) {
_adultContentPreference.value = adultContentPreference
SharedPreferenceManager.contentPreference = adultContentPreference.ordinal
isChangedAdultContentVisible = true
}
}

View File

@ -0,0 +1,12 @@
package kr.co.vividnext.sodalive.settings
enum class ContentType {
// 전체
ALL,
// 남성향
MALE,
// 여성향
FEMALE
}

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Paint
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
@ -95,6 +96,20 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(ActivitySettingsB
)
}
if (SharedPreferenceManager.isAuth) {
binding.rlContentSettings.visibility = View.VISIBLE
binding.rlContentSettings.setOnClickListener {
startActivity(
Intent(
applicationContext,
ContentSettingsActivity::class.java
)
)
}
} else {
binding.rlContentSettings.visibility = View.GONE
}
binding.rlTerms.setOnClickListener {
val intent = Intent(applicationContext, TermsActivity::class.java)
intent.putExtra(Constants.EXTRA_TERMS, Constants.EXTRA_TERMS)

View File

@ -2,12 +2,10 @@ package kr.co.vividnext.sodalive.splash
import android.annotation.SuppressLint
import android.content.Intent
import android.media.MediaPlayer
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.SurfaceHolder
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.os.bundleOf
@ -18,7 +16,6 @@ import com.google.firebase.remoteconfig.ktx.get
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import kr.co.vividnext.sodalive.BuildConfig
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants
@ -37,7 +34,8 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setLayoutParams(binding.ivText, start = 0, end = 112, top = 282, bottom = 0)
setLayoutParams(binding.ivText, start = 0, end = 0, top = 300, bottom = 0)
setLayoutParams(binding.ivText2, start = 0, end = 0, top = 0, bottom = 180)
setupRemoteConfig()
fetchAndroidLatestVersion()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 668 B

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/loading_1" android:duration="500" />
<item android:drawable="@drawable/loading_2" android:duration="500" />
<item android:drawable="@drawable/loading_3" android:duration="500" />
<item android:drawable="@drawable/loading_4" android:duration="500" />
<item android:drawable="@drawable/loading_5" android:duration="500" />
</animation-list>

View File

@ -28,7 +28,7 @@
android:textSize="18.3sp"
app:drawableStartCompat="@drawable/ic_back"
tools:ignore="RelativeOverlap"
tools:text="소다라이브" />
tools:text="보이스온" />
<ImageView
android:id="@+id/iv_plus"

View File

@ -192,7 +192,7 @@
android:layout_marginHorizontal="26.7dp"
android:layout_marginTop="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="- 충전된 캔의 유효기간은 충전 후 5년 입니다.\n- 결제 취소는 결제 후 7일 이내에만 할 수 있습니다.\n 단, 캔의 일부를 사용하면 결제 취소할 수 없습니다.\n- 광고성 이벤트 등 회사가 무료로 지급한 \n포인트는 환불되지 않습니다.\n- 자세한 내용은 소다라이브 이용약관에서 확인할 수 있습니다."
android:text="- 충전된 캔의 유효기간은 충전 후 5년 입니다.\n- 결제 취소는 결제 후 7일 이내에만 할 수 있습니다.\n 단, 캔의 일부를 사용하면 결제 취소할 수 없습니다.\n- 광고성 이벤트 등 회사가 무료로 지급한 \n포인트는 환불되지 않습니다.\n- 자세한 내용은 보이스온 이용약관에서 확인할 수 있습니다."
android:textColor="@color/color_777777"
android:textSize="12sp" />
</LinearLayout>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:id="@+id/ll_adult_content_visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:orientation="vertical"
android:visibility="gone">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="16.7dp"
android:paddingStart="16.7dp"
android:paddingEnd="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_bold"
android:text="민감한 콘텐츠 보기"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<ImageView
android:id="@+id/iv_adult_content_visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/btn_toggle_on_big" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_adult_content_preference"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:background="@color/color_88909090" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingHorizontal="16.7dp"
android:paddingVertical="13.3dp">
<TextView
android:id="@+id/tv_content_all"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawablePadding="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center_vertical"
android:text="전체"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_radio_button_select" />
<TextView
android:id="@+id/tv_content_male"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_weight="1"
android:button="@null"
android:drawablePadding="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center_vertical"
android:text="남성향"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_radio_button_select" />
<TextView
android:id="@+id/tv_content_female"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawablePadding="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center_vertical"
android:text="여성향"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_radio_button_select" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -29,7 +29,7 @@
android:layout_height="36.7dp"
android:layout_centerVertical="true"
android:contentDescription="@null"
tools:src="@drawable/ic_notification" />
tools:src="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="0dp"

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_select_menu_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_13181b"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_menu_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_menu_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="메뉴 1"
android:textColor="@color/color_3bb9f1"
android:textSize="14.7sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_select_menu_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_777777"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_menu_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_menu_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="메뉴 2"
android:textColor="@color/color_555555"
android:textSize="14.7sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_select_menu_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_777777"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_menu_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_menu_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="메뉴 3"
android:textColor="@color/color_555555"
android:textSize="14.7sp" />
</LinearLayout>
</LinearLayout>
<EditText
android:id="@+id/et_menu"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="top"
android:hint="메뉴판을 작성해주세요."
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:overScrollMode="always"
android:padding="20dp"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_10_3bb9f1"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="메뉴 저장"
android:textColor="@color/white"
android:textSize="18.3sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -26,7 +26,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp"
tools:text="소다라이브 App 오픈 관련 공지사항입니다." />
tools:text="보이스온 App 오픈 관련 공지사항입니다." />
<TextView
android:id="@+id/tv_date"

View File

@ -30,7 +30,7 @@
android:textSize="18.3sp"
app:drawableStartCompat="@drawable/ic_back"
tools:ignore="RelativeOverlap"
tools:text="소다라이브" />
tools:text="보이스온" />
</RelativeLayout>
<ScrollView

View File

@ -31,7 +31,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="소다라이브 고객센터"
android:text="보이스온 고객센터"
android:textColor="@color/color_eeeeee"
android:textSize="20sp" />

View File

@ -121,11 +121,40 @@
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_content_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:paddingVertical="16.7dp"
android:paddingStart="16.7dp"
android:paddingEnd="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_bold"
android:text="콘텐츠 보기 설정"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/ic_forward" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="26.7dp"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:orientation="vertical">
@ -219,9 +248,7 @@
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/ic_forward" />
</RelativeLayout>
</LinearLayout>
<RelativeLayout

View File

@ -20,7 +20,20 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/splash_text"
android:src="@drawable/splash_text1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
/>
<ImageView
android:id="@+id/iv_text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/splash_text2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -21,6 +21,6 @@
android:textSize="18.3sp"
app:drawableStartCompat="@drawable/ic_back"
tools:ignore="RelativeOverlap"
tools:text="소다라이브" />
tools:text="보이스온" />
</RelativeLayout>

View File

@ -122,10 +122,32 @@
android:orientation="horizontal"
android:paddingHorizontal="13.3dp">
<LinearLayout
android:id="@+id/ll_morning_call"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/img_bg_morning_call"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="2.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="보이스 모닝콜"
android:gravity="center"
android:textColor="@color/color_0057ff"
android:textSize="16.7sp"
app:drawableStartCompat="@drawable/ic_alarm_clock_blue" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_short_play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:background="@drawable/img_bg_short_play"
android:gravity="center"
@ -141,27 +163,6 @@
android:textSize="16.7sp"
app:drawableStartCompat="@drawable/ic_short_play" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_review_live"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:background="@drawable/img_bg_review_live"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="2.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="라이브 다시듣기"
android:textColor="@color/color_0057ff"
android:textSize="16.7sp"
app:drawableStartCompat="@drawable/ic_thumb_play_blue" />
</LinearLayout>
</LinearLayout>
<LinearLayout

View File

@ -22,6 +22,28 @@
android:layout_marginTop="13.3dp"
android:layout_marginBottom="40dp" />
<LinearLayout
android:id="@+id/ll_review_live"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginBottom="40dp"
android:background="@drawable/img_bg_review_live"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="2.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:text="라이브 다시듣기"
android:textColor="@color/color_672bff"
android:textSize="16.7sp"
app:drawableStartCompat="@drawable/ic_thumb_play_purple" />
</LinearLayout>
<include
android:id="@+id/layout_recommend_channel"
layout="@layout/layout_live_recommend_channel"

View File

@ -270,7 +270,7 @@
android:layout_marginEnd="5.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:text="소다로 살다 (알람 등록)"
android:text="보이스 모닝콜 등록"
android:textColor="@color/color_eeeeee"
android:textSize="16sp" />
@ -432,7 +432,7 @@
android:drawablePadding="13.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:text="소다라이브 고객센터"
android:text="보이스온 고객센터"
android:textColor="@color/color_eeeeee"
android:textSize="15.3sp"
app:drawableStartCompat="@drawable/ic_headphones" />

View File

@ -1,295 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="@color/black">
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/ll_actions"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="13.3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_select_roulette_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_13181b"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_roulette_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_roulette_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="룰렛 1"
android:textColor="@color/color_3bb9f1"
android:textSize="14.7sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_select_roulette_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_777777"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_roulette_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check_black"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_roulette_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="룰렛 2"
android:textColor="@color/color_555555"
android:textSize="14.7sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_select_roulette_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_777777"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_select_roulette_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_select_roulette_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="룰렛 3"
android:textColor="@color/color_555555"
android:textSize="14.7sp" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_bold"
android:text="룰렛을 활성화 하시겠습니까?"
android:textColor="@color/color_eeeeee"
android:textSize="16sp" />
<ImageView
android:id="@+id/iv_roulette_is_active"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:contentDescription="@null"
tools:src="@drawable/btn_toggle_off_big" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp"
android:layout_marginBottom="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="룰렛 금액 설정"
android:textColor="@color/color_eeeeee"
android:textSize="16sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/et_set_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:layout_toStartOf="@+id/tv_price_unit"
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_medium"
android:hint="룰렛 금액을 입력해 주세요.(최소 5캔)"
android:importantForAutofill="no"
android:inputType="numberSigned"
android:paddingHorizontal="13.3dp"
android:paddingVertical="16.7dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_price_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_bold"
android:text="캔"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="룰렛 옵션 설정"
android:textColor="@color/color_eeeeee"
android:textSize="16sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_medium"
android:text="※ 룰렛 옵션은 최소 2개,\n최대 10개까지 설정할 수 있습니다."
android:textColor="@color/color_ff5c49"
android:textSize="13.3sp" />
<ImageView
android:id="@+id/iv_add_option"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/btn_add" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="옵션 확률 합계"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp"
tools:ignore="RelativeOverlap" />
<TextView
android:id="@+id/tv_total_percentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp"
tools:text="( 100.00% )" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_roulette_option_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/ll_actions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_top_round_corner_16_7_222222"
android:orientation="horizontal"
android:padding="13.3dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/tv_preview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_transparent_3bb9f1"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="미리보기"
android:textColor="@color/color_3bb9f1"
android:textSize="18.3sp" />
<TextView
android:id="@+id/tv_save"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_3bb9f1"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="설정완료"
android:textColor="@color/white"
android:textSize="18.3sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -20,7 +20,7 @@
android:layout_marginHorizontal="10dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toStartOf="@+id/tv_price"
app:layout_constraintEnd_toStartOf="@+id/fl_audio_content_end"
app:layout_constraintStart_toEndOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="@+id/iv_cover">
@ -151,21 +151,26 @@
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/fl_audio_content_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5.3dp"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_cover">
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="5.3dp"
android:layout_gravity="center"
android:drawablePadding="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:textColor="@color/color_909090"
android:textSize="12sp"
app:drawableStartCompat="@drawable/ic_can"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_cover"
tools:text="300" />
<TextView
@ -179,11 +184,7 @@
android:text="소장중"
android:textColor="@color/color_111111"
android:textSize="13.3sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_cover"
tools:ignore="RelativeOverlap" />
android:visibility="gone" />
<TextView
android:id="@+id/tv_rented"
@ -196,11 +197,7 @@
android:text="대여중"
android:textColor="@color/white"
android:textSize="13.3sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_cover"
tools:ignore="RelativeOverlap" />
android:visibility="gone" />
<TextView
android:id="@+id/tv_sold_out"
@ -213,10 +210,8 @@
android:text="Sold Out"
android:textColor="@color/color_d2d2d2"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_cover" />
android:visibility="gone" />
</FrameLayout>
<View
android:layout_width="match_parent"

View File

@ -19,7 +19,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp"
tools:text="소다라이브 App 오픈 관련 공지사항입니다." />
tools:text="보이스온 App 오픈 관련 공지사항입니다." />
<TextView
android:id="@+id/tv_date"

View File

@ -37,6 +37,20 @@
android:text="룰렛 설정"
android:textColor="@color/white"
android:textSize="14.7sp" />
<TextView
android:id="@+id/tv_setting_menu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_4_7_3bb9f1"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="17dp"
android:layout_marginStart="8dp"
android:text="메뉴 설정"
android:textColor="@color/white"
android:textSize="14.7sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView

View File

@ -124,4 +124,5 @@
<color name="color_f1291c">#F1291C</color>
<color name="color_ff14d9">#FF14D9</color>
<color name="color_333bb9f1">#333BB9F1</color>
<color name="color_672bff">#672BFF</color>
</resources>

View File

@ -1,5 +1,5 @@
<resources>
<string name="app_name">소다라이브</string>
<string name="app_name">보이스온</string>
<string name="picker_gallery">갤러리</string>
<string name="picker_camera">카메라</string>
<string name="picker_select">선택</string>