Compare commits

...

12 Commits

Author SHA1 Message Date
klaus 66a83a118f 콘텐츠 메인
- 배너 indicator 색상 변경
2024-09-24 14:08:30 +09:00
klaus 3494ff0491 콘텐츠 상세
- 시간표시 슬라이더 색상변경
2024-09-24 14:01:50 +09:00
klaus d51fc88813 콘텐츠 업로드
- 미리듣기 최소 시간 15초로 변경
2024-09-24 13:47:14 +09:00
klaus 1930014498 라이브 비밀후원
- 방장인 경우 비밀후원도 후원 총액에 반영되도록 수정
2024-09-24 12:14:47 +09:00
klaus 4189ee4e54 라이브
- 큰 음소거 이미지 변경
2024-09-20 16:12:13 +09:00
klaus a191e295da 라이브
- 최대 스피커 수 방장 포함 6명으로 변경
2024-09-20 16:10:48 +09:00
klaus 0709c68653 크리에이터 채널
- 공유버튼 변경
2024-09-20 15:34:00 +09:00
klaus 084c306159 시리즈 상세 - 크리에이터 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-20 12:11:33 +09:00
klaus 2ed77a3332 콘텐츠 상세 - 크리에이터 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-20 11:44:13 +09:00
klaus 5b2c5a6e2f 팔로잉/팔로워 리스트 - 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-20 01:57:27 +09:00
klaus 5063ce815d 크리에이터 채널 - 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-13 16:11:39 +09:00
klaus 78323103fd 라이브 정보 수정
- 연령 제한 설정 추가
2024-09-11 23:26:45 +09:00
48 changed files with 585 additions and 231 deletions

View File

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-08-26T10:43:24.248064Z">
<DropdownSelection timestamp="2024-09-23T12:14:10.678819Z">
<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

@ -35,8 +35,8 @@ android {
applicationId "kr.co.vividnext.sodalive"
minSdk 23
targetSdk 34
versionCode 104
versionName "1.17.0"
versionCode 108
versionName "1.19.1"
}
buildTypes {

View File

@ -42,6 +42,7 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.Utils
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
@ -843,21 +844,50 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
if (creator.creatorId != SharedPreferenceManager.userId) {
binding.ivFollow.visibility = View.VISIBLE
if (creator.isFollowing) {
binding.ivFollow.setImageResource(R.drawable.btn_following_big)
binding.ivFollow.setOnClickListener {
viewModel.unRegisterNotification(
contentId = audioContentId,
creatorId = creator.creatorId
if (creator.isFollow) {
binding.ivFollow.setImageResource(
if (creator.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_following_no_alarm_big
}
)
binding.ivFollow.setOnClickListener {
val notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(
contentId = audioContentId,
creatorId = creator.creatorId,
follow = true,
notify = true
)
},
onClickNotifyNone = {
viewModel.follow(
contentId = audioContentId,
creatorId = creator.creatorId,
follow = true,
notify = false
)
},
onClickUnFollow = {
viewModel.follow(
contentId = audioContentId,
creatorId = creator.creatorId,
follow = false,
notify = false
)
}
)
if (notifyFragment.isAdded) return@setOnClickListener
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
}
} else {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
binding.ivFollow.setOnClickListener {
viewModel.registerNotification(
contentId = audioContentId,
creatorId = creator.creatorId
)
viewModel.follow(contentId = audioContentId, creatorId = creator.creatorId)
}
}
} else {

View File

@ -25,9 +25,11 @@ import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.user.UserRepository
class AudioContentDetailViewModel(
private val repository: AudioContentRepository,
private val userRepository: UserRepository,
private val authRepository: AuthRepository,
private val reportRepository: ReportRepository,
private val commentRepository: AudioContentCommentRepository
@ -102,6 +104,41 @@ class AudioContentDetailViewModel(
)
}
fun follow(contentId: Long, creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId = creatorId,
follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
getAudioContentDetail(contentId)
} 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 registerNotification(contentId: Long, creatorId: Long) {
isLoading.value = true
compositeDisposable.add(

View File

@ -53,5 +53,7 @@ data class AudioContentCreator(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImageUrl") val profileImageUrl: String,
@SerializedName("isFollowing") val isFollowing: Boolean
@SerializedName("isFollowing") val isFollowing: Boolean,
@SerializedName("isFollow") var isFollow: Boolean,
@SerializedName("isNotify") var isNotify: Boolean
)

View File

@ -277,7 +277,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
.setIndicatorVisibility(View.GONE)
.setIndicatorSliderColor(
ContextCompat.getColor(requireContext(), R.color.color_909090),
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
)
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
.setIndicatorHeight(4f.dpToPx().toInt())

View File

@ -34,6 +34,7 @@ data class GetSeriesDetailResponse(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImage") val profileImage: String,
@SerializedName("isFollow") var isFollow: Boolean
@SerializedName("isFollow") var isFollow: Boolean,
@SerializedName("isNotify") var isNotify: Boolean
) : Parcelable
}

View File

@ -20,6 +20,7 @@ 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.databinding.ActivitySeriesDetailBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
@ -170,29 +171,68 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
if (SharedPreferenceManager.userId != creator.creatorId) {
binding.ivFollow.visibility = View.VISIBLE
binding.ivFollow.setImageResource(
if (creator.isFollow) {
binding.ivFollow.setImageResource(
if (creator.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_follow_big
R.drawable.btn_following_no_alarm_big
}
)
} else {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
} else {
binding.ivFollow.visibility = View.GONE
}
binding.ivFollow.setOnClickListener {
if (creator.isFollow) {
viewModel.unFollow(creator.creatorId) {
creator.isFollow = false
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
} else {
viewModel.follow(creator.creatorId) {
val notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(
creatorId = creator.creatorId,
follow = true,
notify = true
) {
creator.isFollow = true
creator.isNotify = true
binding.ivFollow.setImageResource(R.drawable.btn_following_big)
}
},
onClickNotifyNone = {
viewModel.follow(
creatorId = creator.creatorId,
follow = true,
notify = false
) {
creator.isFollow = true
creator.isNotify = false
binding.ivFollow.setImageResource(R.drawable.btn_following_no_alarm_big)
}
},
onClickUnFollow = {
viewModel.follow(
creatorId = creator.creatorId,
follow = false,
notify = false
) {
creator.isFollow = false
creator.isNotify = false
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
}
)
if (notifyFragment.isAdded) return@setOnClickListener
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} else {
viewModel.follow(creatorId = creator.creatorId) {
creator.isFollow = true
creator.isNotify = true
binding.ivFollow.setImageResource(R.drawable.btn_following_big)
}
}
}
}

View File

@ -63,45 +63,19 @@ class SeriesDetailViewModel(
)
}
fun follow(creatorId: Long, onSuccess: () -> Unit) {
fun follow(
creatorId: Long,
follow: Boolean = true,
notify: Boolean = true,
onSuccess: () -> Unit
) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
onSuccess()
} 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 unFollow(creatorId: Long, onSuccess: () -> Unit) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
creatorId = creatorId,
follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -346,9 +346,9 @@ class AudioContentUploadViewModel(
val timeDifference = timeDifference(previewStartTime!!, previewEndTime!!)
if (timeDifference < 30000) {
if (timeDifference < 15000) {
_toastLiveData.postValue(
"미리 듣기의 최소 시간은 30초 입니다."
"미리 듣기의 최소 시간은 15초 입니다."
)
return false

View File

@ -237,10 +237,10 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { AudioContentUploadViewModel(get()) }
viewModel { AudioContentModifyViewModel(get()) }
viewModel { AudioContentThemeViewModel(get()) }
viewModel { AudioContentDetailViewModel(get(), get(), get(), get()) }
viewModel { AudioContentDetailViewModel(get(), get(), get(), get(), get()) }
viewModel { AudioContentCommentListViewModel(get()) }
viewModel { AudioContentCommentReplyViewModel(get()) }
viewModel { FollowingCreatorViewModel(get()) }
viewModel { FollowingCreatorViewModel(get(), get()) }
viewModel { ServiceCenterViewModel(get()) }
viewModel { ProfileUpdateViewModel(get()) }
viewModel { NicknameUpdateViewModel(get()) }
@ -280,7 +280,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
factory { AudioContentRepository(get(), get(), get()) }
factory { AudioContentCommentRepository(get()) }
factory { PlaybackTrackingRepository(get()) }
factory { FollowingCreatorRepository(get(), get()) }
factory { FollowingCreatorRepository(get()) }
factory { FaqRepository(get()) }
factory { MemberTagRepository(get()) }
factory { UserProfileFantalkAllViewModel(get(), get()) }

View File

@ -0,0 +1,42 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.R
class CreatorFollowNotifyFragment(
private val onClickNotifyAll: () -> Unit,
private val onClickNotifyNone: () -> Unit,
private val onClickUnFollow: () -> Unit,
) : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = inflater.inflate(
R.layout.fragment_creator_follow_notify,
container,
false
)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<LinearLayout>(R.id.ll_notify_all).setOnClickListener {
onClickNotifyAll()
dialog?.dismiss()
}
view.findViewById<LinearLayout>(R.id.ll_notify_none).setOnClickListener {
onClickNotifyNone()
dialog?.dismiss()
}
view.findViewById<LinearLayout>(R.id.ll_unfollow).setOnClickListener {
onClickUnFollow()
dialog?.dismiss()
}
}
}

View File

@ -41,6 +41,8 @@ data class CreatorResponse(
@SerializedName("websiteUrl") val websiteUrl: String? = null,
@SerializedName("blogUrl") val blogUrl: String? = null,
@SerializedName("isAvailableChat") val isAvailableChat: Boolean = true,
@SerializedName("isFollow") val isFollow: Boolean,
@SerializedName("isNotify") val isNotify: Boolean,
@SerializedName("isNotification") val isNotification: Boolean,
@SerializedName("notificationRecipientCount") val notificationRecipientCount: Int
)

View File

@ -83,6 +83,8 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
private val handler = Handler(Looper.getMainLooper())
private var userId: Long = 0
private var notifyFragment: CreatorFollowNotifyFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
super.onCreate(savedInstanceState)
@ -703,10 +705,32 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
}
}
if (creator.isNotification) {
layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_following_big)
if (creator.isFollow) {
layoutUserProfile.ivNotification.setImageResource(
if (creator.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_following_no_alarm_big
}
)
layoutUserProfile.ivNotification.setOnClickListener {
viewModel.unFollow(creator.creatorId)
if (notifyFragment == null) {
notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(creator.creatorId, follow = true, notify = true)
},
onClickNotifyNone = {
viewModel.follow(creator.creatorId, follow = true, notify = false)
},
onClickUnFollow = {
viewModel.follow(creator.creatorId, follow = false, notify = false)
}
)
}
if (notifyFragment!!.isAdded) return@setOnClickListener
notifyFragment!!.show(supportFragmentManager, notifyFragment!!.tag)
}
} else {
layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_follow_big)

View File

@ -16,7 +16,6 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType
@ -147,12 +146,14 @@ class UserProfileViewModel(
)
}
fun follow(creatorId: Long) {
fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
follow = follow,
notify = notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -14,5 +14,6 @@ data class GetFollowerListResponseItem(
@SerializedName("userId") val userId: Long,
@SerializedName("profileImage") val profileImage: String,
@SerializedName("nickname") val nickname: String,
@SerializedName("isFollow") val isFollow: Boolean?
@SerializedName("isFollow") val isFollow: Boolean?,
@SerializedName("isNotify") val isNotify: Boolean?
)

View File

@ -10,6 +10,7 @@ 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.databinding.ActivityUserFollowerListBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
import org.koin.android.ext.android.inject
@ -50,8 +51,26 @@ class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = UserFollowerListAdapter(
onClickRegisterNotification = { viewModel.registerNotification(it) },
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) }
onClickFollow = { creatorId, isFollow ->
if (isFollow) {
val notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(creatorId, follow = true, notify = true)
},
onClickNotifyNone = {
viewModel.follow(creatorId, follow = true, notify = false)
},
onClickUnFollow = {
viewModel.follow(creatorId, follow = false, notify = false)
}
)
if (notifyFragment.isAdded) return@UserFollowerListAdapter
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} else {
viewModel.follow(creatorId)
}
}
)
binding.rvFollowerList.layoutManager = LinearLayoutManager(
@ -94,6 +113,7 @@ class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
private fun bindData() {
viewModel.userId = userId
viewModel.followerListItemsLiveData.observe(this) {
if (viewModel.page == 2) adapter.clear()
adapter.addAll(it)
}

View File

@ -11,8 +11,7 @@ import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
class UserFollowerListAdapter(
private val onClickRegisterNotification: (Long) -> Unit,
private val onClickUnRegisterNotification: (Long) -> Unit,
private val onClickFollow: (Long, Boolean) -> Unit
) : RecyclerView.Adapter<UserFollowerListAdapter.ViewHolder>() {
private val items = mutableListOf<GetFollowerListResponseItem>()
@ -28,23 +27,25 @@ class UserFollowerListAdapter(
crossfade(true)
}
if (item.isFollow != null) {
binding.ivNotification.visibility = View.VISIBLE
if (item.isFollow != null && item.isNotify != null) {
if (item.isFollow) {
binding.ivNotification.setImageResource(R.drawable.btn_following_big)
binding.ivNotification.setOnClickListener {
onClickUnRegisterNotification(item.userId)
clear()
binding.ivFollow.setImageResource(
if (item.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_following_no_alarm_big
}
)
} else {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
binding.ivFollow.visibility = View.VISIBLE
binding.ivFollow.setOnClickListener {
onClickFollow(item.userId, item.isFollow)
}
} else {
binding.ivNotification.setImageResource(R.drawable.btn_follow_big)
binding.ivNotification.setOnClickListener {
onClickRegisterNotification(item.userId)
clear()
}
}
} else {
binding.ivNotification.visibility = View.GONE
binding.ivFollow.visibility = View.GONE
}
}
}

View File

@ -34,7 +34,7 @@ class UserFollowerListViewModel(
var userId: Long = 0
var page = 1
private var isLast = false
private val pageSize = 10
private var pageSize = 10
fun getFollowerList() {
if (!isLast && !_isLoading.value!!) {
@ -52,6 +52,7 @@ class UserFollowerListViewModel(
.subscribe(
{
_isLoading.value = false
pageSize = 10
if (it.success && it.data != null) {
val data = it.data
_totalCountLiveData.value = data.totalCount
@ -84,12 +85,14 @@ class UserFollowerListViewModel(
}
}
fun registerNotification(creatorId: Long) {
fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
creatorId = creatorId,
follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -97,43 +100,9 @@ class UserFollowerListViewModel(
{
_isLoading.value = false
if (it.success && it.data != null) {
page = 1
isLast = false
getFollowerList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun unRegisterNotification(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
pageSize *= page
page = 1
isLast = false
getFollowerList()
} else {
if (it.message != null) {

View File

@ -12,6 +12,7 @@ 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.databinding.ActivityFollowingCreatorBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
@ -23,6 +24,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: FollowingCreatorAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -43,8 +45,26 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
}
)
},
onClickRegisterNotification = { viewModel.registerNotification(it) },
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) }
onClickFollow = { creatorId, isFollow ->
if (isFollow) {
val notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(creatorId, follow = true, notify = true)
},
onClickNotifyNone = {
viewModel.follow(creatorId, follow = true, notify = false)
},
onClickUnFollow = {
viewModel.follow(creatorId, follow = false, notify = false)
}
)
if (notifyFragment.isAdded) return@FollowingCreatorAdapter
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} else {
viewModel.follow(creatorId)
}
},
)
binding.rvFollowingCreator.layoutManager = LinearLayoutManager(
@ -99,6 +119,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
}
viewModel.creatorListLiveData.observe(this) {
if (viewModel.page == 2) adapter.clear()
adapter.addAll(it)
}

View File

@ -12,8 +12,7 @@ import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
class FollowingCreatorAdapter(
private val onClickItem: (Long) -> Unit,
private val onClickRegisterNotification: (Long) -> Unit,
private val onClickUnRegisterNotification: (Long) -> Unit,
private val onClickFollow: (Long, Boolean) -> Unit
) : RecyclerView.Adapter<FollowingCreatorAdapter.ViewHolder>() {
private val items = mutableListOf<GetCreatorFollowingAllListItem>()
@ -30,29 +29,22 @@ class FollowingCreatorAdapter(
crossfade(true)
}
binding.ivNotification.visibility = View.VISIBLE
binding.ivFollow.visibility = View.VISIBLE
if (item.isFollow) {
binding.ivNotification.setImageResource(R.drawable.btn_following_big)
binding.ivNotification.setOnClickListener {
val index = items.indexOf(item)
val copyItem = item.copy(isFollow = false)
items.add(index, copyItem)
items.removeAt(index + 1)
notifyDataSetChanged()
onClickUnRegisterNotification(item.creatorId)
}
binding.ivFollow.setImageResource(
if (item.isNotify) {
R.drawable.btn_following_big
} else {
binding.ivNotification.setImageResource(R.drawable.btn_follow_big)
binding.ivNotification.setOnClickListener {
val index = items.indexOf(item)
val copyItem = item.copy(isFollow = true)
items.add(index, copyItem)
items.removeAt(index + 1)
notifyDataSetChanged()
onClickRegisterNotification(item.creatorId)
R.drawable.btn_following_no_alarm_big
}
)
} else {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
binding.ivFollow.setOnClickListener {
onClickFollow(item.creatorId, item.isFollow)
}
binding.root.setOnClickListener { onClickItem(item.creatorId) }
}
}

View File

@ -4,29 +4,10 @@ import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
import kr.co.vividnext.sodalive.user.UserApi
class FollowingCreatorRepository(
private val api: LiveRecommendApi,
private val userApi: UserApi
) {
class FollowingCreatorRepository(private val api: LiveRecommendApi) {
fun getFollowedCreatorAllList(
page: Int,
size: Int,
token: String
) = api.getCreatorFollowingAllList(page = page - 1, size = size, authHeader = token)
fun registerNotification(
creatorId: Long,
token: String
) = userApi.creatorFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
authHeader = token
)
fun unRegisterNotification(
creatorId: Long,
token: String
) = userApi.creatorUnFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
authHeader = token
)
}

View File

@ -7,9 +7,11 @@ 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.user.UserRepository
class FollowingCreatorViewModel(
private val repository: FollowingCreatorRepository
private val repository: FollowingCreatorRepository,
private val userRepository: UserRepository
) : BaseViewModel() {
private val _creatorListLiveData = MutableLiveData<List<GetCreatorFollowingAllListItem>>()
@ -30,7 +32,7 @@ class FollowingCreatorViewModel(
var page = 1
var isLast = false
private val pageSize = 10
private var pageSize = 10
fun getFollowedCreatorAllList() {
if (!isLast && !_isLoading.value!!) {
@ -47,6 +49,7 @@ class FollowingCreatorViewModel(
.subscribe(
{
_isLoading.value = false
pageSize = 10
if (it.success && it.data != null) {
val data = it.data
if (data.items.isEmpty()) {
@ -78,29 +81,41 @@ class FollowingCreatorViewModel(
}
}
fun registerNotification(creatorId: Long) {
_creatorListTotalCountLiveData.value = _creatorListTotalCountLiveData.value!! + 1
fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
_isLoading.value = true
compositeDisposable.add(
repository.registerNotification(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
userRepository.creatorFollow(
creatorId = creatorId,
follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {})
)
}
fun unRegisterNotification(creatorId: Long) {
_creatorListTotalCountLiveData.value = _creatorListTotalCountLiveData.value!! - 1
compositeDisposable.add(
repository.unRegisterNotification(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {})
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
isLast = false
pageSize *= page
page = 1
getFollowedCreatorAllList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}

View File

@ -14,5 +14,6 @@ data class GetCreatorFollowingAllListItem(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImageUrl") val profileImageUrl: String,
@SerializedName("isFollow") val isFollow: Boolean
@SerializedName("isFollow") var isFollow: Boolean,
@SerializedName("isNotify") var isNotify: Boolean
)

View File

@ -46,6 +46,7 @@ import io.agora.rtm.RtmMessageType
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.agora.Agora
import kr.co.vividnext.sodalive.base.BaseActivity
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.RealPathUtil
@ -320,7 +321,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
)
},
onClickInviteSpeaker = { memberId ->
if (speakerListAdapter.itemCount <= 4) {
if (speakerListAdapter.itemCount <= 5) {
inviteSpeaker(memberId)
} else {
showToast("스피커 정원이 초과했습니다.")
@ -403,7 +404,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
)
},
onClickInviteSpeaker = {
if (speakerListAdapter.itemCount <= 4) {
if (speakerListAdapter.itemCount <= 5) {
inviteSpeaker(it)
} else {
showToast("스피커 정원이 초과했습니다.")
@ -689,6 +690,20 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
it?.let { showToast(it) }
}
viewModel.changeIsAdultLiveData.observe(this) {
if (it && !SharedPreferenceManager.isAuth) {
agora.muteAllRemoteAudioStreams(true)
binding.rvChat.visibility = View.INVISIBLE
SodaDialog(this@LiveRoomActivity,
layoutInflater,
"알림",
"지금 참여하던 라이브는 '19세 이상' 연령제한이 설정되어 정보통신망 이용촉진 및 정보 보호 등에 관한 법률 및 청소년 보호법의 규정에 의해 만 19세 미만의 청소년은 이용할 수 없습니다.\n마이페이지에서 본인인증 후 다시 이용하시기 바랍니다.",
"확인",
{ finish() }
).show(screenWidth)
}
}
donationMessageViewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth)
@ -758,10 +773,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
if (response.creatorId == SharedPreferenceManager.userId) {
binding.ivEdit.setOnClickListener {
viewModel.getAllMenuPreset {
roomInfoEditDialog.setRoomInfo(response.title, response.notice)
roomInfoEditDialog.setRoomInfo(
response.title,
response.notice,
response.isAdult
)
roomInfoEditDialog.setCoverImageUrl(response.coverImageUrl)
roomInfoEditDialog.setMenuPreset(it)
roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageUri, isActivateMenu, menuId, menu ->
roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageUri, isActivateMenu, menuId, menu, isAdult ->
viewModel.editLiveRoomInfo(
response.roomId,
newTitle,
@ -770,6 +789,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
isActivateMenu,
menuId,
menu,
isAdult,
onSuccess = {
Toast.makeText(
applicationContext,
@ -1109,8 +1129,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.left = 4f.dpToPx().toInt()
outRect.right = 4f.dpToPx().toInt()
outRect.left = 2f.dpToPx().toInt()
outRect.right = 2f.dpToPx().toInt()
}
})
rvSpeakers.adapter = speakerListAdapter
@ -1639,10 +1659,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
Logger.e("onAudioVolumeIndication - $speakers")
val activeSpeakerIds = speakers
.asSequence()
.filter { it.volume > 0 }
.map { it.uid }
.toList()
Logger.e("onAudioVolumeIndication - $activeSpeakerIds")
handler.post {
@ -1862,6 +1880,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
)
)
invalidateChat()
viewModel.addDonationCan(message.can)
if (message.signature != null) {
addSignature(message.signature)

View File

@ -72,6 +72,10 @@ class LiveRoomViewModel(
val coverImageUrlLiveData: LiveData<String>
get() = _coverImageUrlLiveData
private val _changeIsAdultLiveData = MutableLiveData(false)
val changeIsAdultLiveData: LiveData<Boolean>
get() = _changeIsAdultLiveData
lateinit var roomInfoResponse: GetRoomInfoResponse
fun isRoomInfoInitialized() = this::roomInfoResponse.isInitialized
@ -212,6 +216,10 @@ class LiveRoomViewModel(
getTotalDonationCan(roomId = roomId)
if (it.data.isAdult && !SharedPreferenceManager.isAuth) {
_changeIsAdultLiveData.value = true
}
if (userId > 0 && it.data.creatorId == SharedPreferenceManager.userId) {
val nickname = getUserNickname(userId)
onSuccess(nickname)
@ -425,6 +433,7 @@ class LiveRoomViewModel(
isActivateMenu: Boolean?,
menuId: Long,
menu: String,
isAdult: Boolean?,
onSuccess: () -> Unit
) {
val request = EditLiveRoomInfoRequest(
@ -443,13 +452,15 @@ class LiveRoomViewModel(
timezone = null,
menuPanId = if (isActivateMenu == true) menuId else 0,
menuPan = if (isActivateMenu == true) menu else "",
isActiveMenuPan = isActivateMenu
isActiveMenuPan = isActivateMenu,
isAdult = isAdult
)
val requestJson = if (
request.title != null ||
request.notice != null ||
request.isActiveMenuPan != null ||
request.isAdult != null ||
request.menuPan.isNotBlank()
) {
Gson().toJson(request)

View File

@ -35,8 +35,8 @@ class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapt
}
val ivMuteLp = binding.ivMute.layoutParams
ivMuteLp.width = 30f.dpToPx().toInt()
ivMuteLp.height = 30f.dpToPx().toInt()
ivMuteLp.width = 28f.dpToPx().toInt()
ivMuteLp.height = 28f.dpToPx().toInt()
binding.ivMute.layoutParams = ivMuteLp
}

View File

@ -12,5 +12,6 @@ data class EditLiveRoomInfoRequest(
@SerializedName("timezone") val timezone: String?,
@SerializedName("menuPanId") val menuPanId: Long = 0,
@SerializedName("menuPan") val menuPan: String = "",
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean? = null
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean? = null,
@SerializedName("isAdult") val isAdult: Boolean? = null
)

View File

@ -19,6 +19,7 @@ import androidx.lifecycle.MutableLiveData
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.DialogLiveRoomInfoUpdateBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
@ -39,10 +40,12 @@ class LiveRoomInfoEditDialog(
private var menuId = 0L
private val menuList = mutableListOf<GetMenuPresetResponse>()
private val isAdultLiveData = MutableLiveData(false)
private val isActivateMenuLiveData = MutableLiveData(false)
private val selectedMenuLiveData = MutableLiveData<LiveRoomCreateViewModel.SelectedMenu>()
private var menu: String = ""
private var isAdult: Boolean = false
private var isActivateMenu: Boolean? = null
private lateinit var selectedMenu: LiveRoomCreateViewModel.SelectedMenu
@ -96,6 +99,15 @@ class LiveRoomInfoEditDialog(
selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
}
if (SharedPreferenceManager.isAuth) {
dialogView.llAdult.visibility = View.VISIBLE
dialogView.ivAdultSwitch.setOnClickListener {
isAdultLiveData.value = !isAdultLiveData.value!!
}
} else {
dialogView.llAdult.visibility = View.GONE
}
selectedMenuLiveData.observe(activity) {
deselectAllMenuPreset()
@ -129,14 +141,28 @@ class LiveRoomInfoEditDialog(
dialogView.ivSwitch.setImageResource(R.drawable.btn_toggle_off_big)
}
}
isAdultLiveData.observe(activity) {
dialogView.ivAdultSwitch.setImageResource(
if (it) {
R.drawable.btn_toggle_on_big
} else {
R.drawable.btn_toggle_off_big
}
)
}
}
fun setRoomInfo(
currentTitle: String,
currentContent: String,
isAdult: Boolean
) {
dialogView.etTitle.setText(currentTitle)
dialogView.etNotice.setText(currentContent)
this.isAdult = isAdult
isAdultLiveData.value = isAdult
}
fun setCoverImageUri(coverImageUri: Uri) {
@ -176,7 +202,7 @@ class LiveRoomInfoEditDialog(
}
}
fun setConfirmAction(confirmAction: (String, String, Uri?, Boolean?, Long, String) -> Unit) {
fun setConfirmAction(confirmAction: (String, String, Uri?, Boolean?, Long, String, Boolean?) -> Unit) {
dialogView.tvConfirm.setOnClickListener {
alertDialog.dismiss()
@ -202,7 +228,12 @@ class LiveRoomInfoEditDialog(
isActivateMenu
},
menuId,
menu
menu,
if (isAdult != isAdultLiveData.value!!) {
isAdultLiveData.value!!
} else {
null
}
)
coverImageUri = null
coverImageUrl = null

View File

@ -4,4 +4,8 @@ import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
@Keep
data class CreatorFollowRequestRequest(@SerializedName("creatorId") val creatorId: Long)
data class CreatorFollowRequestRequest(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("isNotify") val isNotify: Boolean = true,
@SerializedName("isActive") val isActive: Boolean = true
)

View File

@ -54,9 +54,15 @@ class UserRepository(private val userApi: UserApi) {
fun creatorFollow(
creatorId: Long,
follow: Boolean = true,
notify: Boolean = true,
token: String
) = userApi.creatorFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
request = CreatorFollowRequestRequest(
creatorId = creatorId,
isActive = follow,
isNotify = notify
),
authHeader = token
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -15,7 +15,7 @@
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="@color/color_9970ff" />
<solid android:color="@color/color_3bb9f1" />
</shape>
</clip>
</item>

View File

@ -735,7 +735,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="미리듣기 시간을 직접 설정하지 않으면 콘텐츠 앞부분 30초가 자동으로 설정됩니다. 미리듣기의 시간제한은 없습니다."
android:text="미리듣기 시간을 직접 설정하지 않으면 콘텐츠 앞부분 15초가 자동으로 설정됩니다. 미리듣기의 시간제한은 없습니다."
android:textColor="@color/color_777777"
android:textSize="13.3sp" />
@ -803,7 +803,7 @@
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:hint="00:30:00"
android:hint="00:00:15"
android:importantForAutofill="no"
android:inputType="textWebEditText"
android:paddingHorizontal="13.3dp"

View File

@ -271,7 +271,7 @@
android:layout_marginTop="12dp">
<RelativeLayout
android:layout_width="180dp"
android:layout_width="166dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_5_3_transparent_bbbbbb"
android:padding="5.3dp">

View File

@ -29,7 +29,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff"
android:textColor="@color/color_3bb9f1"
android:textSize="18.3sp"
app:layout_constraintStart_toEndOf="@+id/tv_title"
app:layout_constraintTop_toTopOf="@+id/tv_title"

View File

@ -138,6 +138,48 @@
tools:ignore="LabelFor" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_adult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="33.3dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="연령제한"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_medium"
android:lineSpacingExtra="5sp"
android:text="19세 이상"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" />
<ImageView
android:id="@+id/iv_adult_switch"
android:layout_width="33.3dp"
android:layout_height="20dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/btn_toggle_off_big" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -5,7 +5,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/bg_round_corner_10_13181b">
android:background="@drawable/bg_round_corner_10_13181b"
android:paddingHorizontal="24dp">
<TextView
android:id="@+id/tv_title"
@ -27,7 +28,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:textColor="@color/color_bbbbbb"
android:textSize="15sp"
app:layout_constraintEnd_toEndOf="parent"
@ -38,7 +38,6 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16.7dp"
android:layout_marginTop="45dp"
android:layout_marginBottom="16.7dp"
android:gravity="center"

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_top_round_corner_10_222222"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="알림"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<LinearLayout
android:id="@+id/ll_notify_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_notify_all" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="전체"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_notify_none"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_notify_none" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="없음"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_unfollow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_avatar_unfollow" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="팔로우 취소"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" />
</LinearLayout>
</LinearLayout>

View File

@ -17,14 +17,14 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="13.3dp"
android:layout_toStartOf="@+id/iv_notification"
android:layout_toStartOf="@+id/iv_follow"
android:layout_toEndOf="@+id/iv_profile"
android:fontFamily="@font/gmarket_sans_medium"
android:textSize="16.7sp"
tools:text="상남자" />
<ImageView
android:id="@+id/iv_notification"
android:id="@+id/iv_follow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="30dp"
android:layout_width="28dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:layout_width="30dp"
android:layout_height="30dp">
android:layout_width="28dp"
android:layout_height="28dp">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="26.7dp"
android:layout_height="26.7dp"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerInParent="true"
android:contentDescription="@null"
tools:src="@mipmap/ic_launcher" />
@ -42,8 +42,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:lines="1"
android:textColor="@color/color_777777"
android:textSize="10.7sp"
android:textSize="8.7sp"
tools:ignore="SmallSp"
tools:text="932sld23" />
</LinearLayout>