feat(following): 팔로우 해제 확인 dialog를 적용한다
This commit is contained in:
@@ -11,8 +11,8 @@ import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
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.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivity
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
@@ -43,24 +43,22 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
|
||||
)
|
||||
},
|
||||
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 {
|
||||
if (!isFollow) {
|
||||
viewModel.follow(creatorId)
|
||||
}
|
||||
},
|
||||
onClickUnfollow = { creatorId, creatorName ->
|
||||
V2ModalDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = getString(R.string.creator_unfollow_confirm_title),
|
||||
desc = getString(R.string.creator_unfollow_confirm_desc, creatorName),
|
||||
confirmButtonTitle = getString(R.string.creator_unfollow_confirm_confirm),
|
||||
confirmButtonClick = {
|
||||
viewModel.follow(creatorId, follow = false, notify = false)
|
||||
},
|
||||
cancelButtonTitle = getString(R.string.creator_unfollow_confirm_cancel)
|
||||
).show(screenWidth)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -9,10 +9,12 @@ import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
|
||||
class FollowingCreatorAdapter(
|
||||
private val onClickItem: (Long) -> Unit,
|
||||
private val onClickFollow: (Long, Boolean) -> Unit
|
||||
private val onClickFollow: (Long, Boolean) -> Unit,
|
||||
private val onClickUnfollow: ((Long, String) -> Unit)? = null
|
||||
) : RecyclerView.Adapter<FollowingCreatorAdapter.ViewHolder>() {
|
||||
|
||||
private val items = mutableListOf<GetCreatorFollowingAllListItem>()
|
||||
@@ -31,19 +33,22 @@ class FollowingCreatorAdapter(
|
||||
|
||||
binding.ivFollow.visibility = View.VISIBLE
|
||||
if (item.isFollow) {
|
||||
binding.ivFollow.setImageResource(
|
||||
if (item.isNotify) {
|
||||
R.drawable.btn_following_big
|
||||
} else {
|
||||
R.drawable.btn_following_no_alarm_big
|
||||
}
|
||||
)
|
||||
val padding = 8.dpToPx().toInt()
|
||||
binding.ivFollow.setPadding(padding, padding, padding, padding)
|
||||
binding.ivFollow.setBackgroundResource(R.drawable.bg_following_circle_gray_800)
|
||||
binding.ivFollow.setImageResource(R.drawable.ic_new_following_white)
|
||||
} else {
|
||||
binding.ivFollow.setPadding(0, 0, 0, 0)
|
||||
binding.ivFollow.background = null
|
||||
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
|
||||
}
|
||||
|
||||
binding.ivFollow.setOnClickListener {
|
||||
onClickFollow(item.creatorId, item.isFollow)
|
||||
if (item.isFollow && onClickUnfollow != null) {
|
||||
onClickUnfollow.invoke(item.creatorId, item.nickname)
|
||||
} else {
|
||||
onClickFollow(item.creatorId, item.isFollow)
|
||||
}
|
||||
}
|
||||
binding.root.setOnClickListener { onClickItem(item.creatorId) }
|
||||
}
|
||||
|
||||
+11
-1
@@ -332,7 +332,17 @@ class CreatorChannelActivity :
|
||||
return
|
||||
}
|
||||
|
||||
homeActionDelegate?.follow(follow = false, notify = false)
|
||||
V2ModalDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = getString(R.string.creator_unfollow_confirm_title),
|
||||
desc = getString(R.string.creator_unfollow_confirm_desc, header.nickname),
|
||||
confirmButtonTitle = getString(R.string.creator_unfollow_confirm_confirm),
|
||||
confirmButtonClick = {
|
||||
homeActionDelegate?.follow(follow = false, notify = false)
|
||||
},
|
||||
cancelButtonTitle = getString(R.string.creator_unfollow_confirm_cancel)
|
||||
).show(screenWidth)
|
||||
}
|
||||
|
||||
private fun onBellClicked() {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 381 B |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/gray_800" />
|
||||
<corners android:radius="100dp" />
|
||||
</shape>
|
||||
@@ -345,6 +345,10 @@
|
||||
<string name="creator_channel_dm_check_button">Check DMs</string>
|
||||
<string name="creator_channel_follow_button">Follow</string>
|
||||
<string name="creator_channel_unfollow_success">Following has been canceled.</string>
|
||||
<string name="creator_unfollow_confirm_title">Unfollow</string>
|
||||
<string name="creator_unfollow_confirm_desc">You’ll no longer receive updates from %1$s.\nDo you want to unfollow?</string>
|
||||
<string name="creator_unfollow_confirm_cancel">Cancel</string>
|
||||
<string name="creator_unfollow_confirm_confirm">Unfollow</string>
|
||||
<string name="creator_channel_block_success">Blocked.</string>
|
||||
<string name="creator_channel_section_live">Live now</string>
|
||||
<string name="creator_channel_section_latest_audio">Latest audio</string>
|
||||
|
||||
@@ -345,6 +345,10 @@
|
||||
<string name="creator_channel_dm_check_button">DMを確認</string>
|
||||
<string name="creator_channel_follow_button">フォロー</string>
|
||||
<string name="creator_channel_unfollow_success">フォローを解除しました。</string>
|
||||
<string name="creator_unfollow_confirm_title">フォロー解除</string>
|
||||
<string name="creator_unfollow_confirm_desc">%1$sからの最新情報を受け取れなくなります。\nフォローを解除しますか?</string>
|
||||
<string name="creator_unfollow_confirm_cancel">キャンセル</string>
|
||||
<string name="creator_unfollow_confirm_confirm">解除する</string>
|
||||
<string name="creator_channel_block_success">ブロックしました。</string>
|
||||
<string name="creator_channel_section_live">配信中</string>
|
||||
<string name="creator_channel_section_latest_audio">最新オーディオ</string>
|
||||
|
||||
@@ -344,6 +344,10 @@
|
||||
<string name="creator_channel_dm_check_button">DM 확인하기</string>
|
||||
<string name="creator_channel_follow_button">팔로우</string>
|
||||
<string name="creator_channel_unfollow_success">팔로잉이 취소되었습니다.</string>
|
||||
<string name="creator_unfollow_confirm_title">팔로우 해제</string>
|
||||
<string name="creator_unfollow_confirm_desc">팔로우를 해제할까요?\n%1$s의 소식을 받을 수 없어요.</string>
|
||||
<string name="creator_unfollow_confirm_cancel">취소</string>
|
||||
<string name="creator_unfollow_confirm_confirm">해제하기</string>
|
||||
<string name="creator_channel_block_success">차단하였습니다.</string>
|
||||
<string name="creator_channel_section_live">현재 라이브</string>
|
||||
<string name="creator_channel_section_latest_audio">최신 오디오</string>
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package kr.co.vividnext.sodalive.following
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
class FollowingCreatorActivitySourceTest {
|
||||
|
||||
@Test
|
||||
fun `팔로잉 리스트는 Bottom Sheet 대신 해제 확인 Dialog를 표시한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivity.kt"
|
||||
).readText()
|
||||
|
||||
assertFalse(source.contains("CreatorFollowNotifyFragment"))
|
||||
assertTrue(source.contains("onClickUnfollow = { creatorId, creatorName ->"))
|
||||
assertTrue(source.contains("V2ModalDialog("))
|
||||
assertTrue(source.contains("R.string.creator_unfollow_confirm_desc, creatorName"))
|
||||
assertTrue(source.contains("confirmButtonClick = {"))
|
||||
assertTrue(source.contains("viewModel.follow(creatorId, follow = false, notify = false)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `팔로우 해제 확인 문구는 세 locale에서 같은 placeholder 계약을 사용한다`() {
|
||||
val korean = projectFile("app/src/main/res/values/strings.xml").readText()
|
||||
val english = projectFile("app/src/main/res/values-en/strings.xml").readText()
|
||||
val japanese = projectFile("app/src/main/res/values-ja/strings.xml").readText()
|
||||
|
||||
listOf(korean, english, japanese).forEach { strings ->
|
||||
assertTrue(strings.contains("name=\"creator_unfollow_confirm_title\""))
|
||||
assertTrue(strings.contains("name=\"creator_unfollow_confirm_desc\""))
|
||||
assertTrue(strings.contains("name=\"creator_unfollow_confirm_cancel\""))
|
||||
assertTrue(strings.contains("name=\"creator_unfollow_confirm_confirm\""))
|
||||
assertTrue(strings.contains("%1\$s"))
|
||||
}
|
||||
assertTrue(
|
||||
english.contains(
|
||||
"You’ll no longer receive updates from %1\$s.\\nDo you want to unfollow?"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun projectFile(path: String): File = File(projectRoot(), path)
|
||||
|
||||
private fun projectRoot(): File {
|
||||
return generateSequence(File(System.getProperty("user.dir") ?: ".").absoluteFile) { it.parentFile }
|
||||
.first { File(it, "settings.gradle").exists() }
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package kr.co.vividnext.sodalive.following
|
||||
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
class FollowingCreatorAdapterSourceTest {
|
||||
|
||||
@Test
|
||||
fun `팔로잉 중 버튼은 흰색 아이콘과 gray 800 원형 배경을 사용한다`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapter.kt"
|
||||
).readText()
|
||||
val background = projectFile(
|
||||
"app/src/main/res/drawable/bg_following_circle_gray_800.xml"
|
||||
)
|
||||
|
||||
assertTrue(source.contains("R.drawable.ic_new_following_white"))
|
||||
assertTrue(source.contains("R.drawable.bg_following_circle_gray_800"))
|
||||
assertTrue(source.contains("8.dpToPx().toInt()"))
|
||||
assertTrue(background.exists())
|
||||
assertTrue(background.readText().contains("@color/gray_800"))
|
||||
assertTrue(background.readText().contains("android:radius=\"100dp\""))
|
||||
}
|
||||
|
||||
private fun projectFile(path: String): File = File(projectRoot(), path)
|
||||
|
||||
private fun projectRoot(): File {
|
||||
return generateSequence(File(System.getProperty("user.dir") ?: ".").absoluteFile) { it.parentFile }
|
||||
.first { File(it, "settings.gradle").exists() }
|
||||
}
|
||||
}
|
||||
+16
-2
@@ -283,6 +283,11 @@ class CreatorChannelActivitySourceTest {
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt"
|
||||
).readText()
|
||||
val layout = projectFile("app/src/main/res/layout/activity_creator_channel.xml").readText()
|
||||
val followClickSource = sourceSection(
|
||||
source = source,
|
||||
startMarker = "private fun onFollowCapsuleClicked()",
|
||||
endMarker = "private fun onBellClicked()"
|
||||
)
|
||||
|
||||
assertFalse(source.contains("CreatorFollowNotifyFragment"))
|
||||
assertTrue(layout.contains("android:id=\"@+id/layout_follow_capsule\""))
|
||||
@@ -294,7 +299,11 @@ class CreatorChannelActivitySourceTest {
|
||||
assertTrue(source.contains("if (!header.isFollow)"))
|
||||
assertTrue(source.contains("homeActionDelegate?.follow(follow = true, notify = true)"))
|
||||
assertTrue(source.contains("homeActionDelegate?.follow(follow = true, notify = !header.isNotify)"))
|
||||
assertTrue(source.contains("homeActionDelegate?.follow(follow = false, notify = false)"))
|
||||
assertTrue(followClickSource.contains("V2ModalDialog("))
|
||||
assertTrue(followClickSource.contains("R.string.creator_unfollow_confirm_title"))
|
||||
assertTrue(followClickSource.contains("R.string.creator_unfollow_confirm_desc, header.nickname"))
|
||||
assertTrue(followClickSource.contains("confirmButtonClick = {"))
|
||||
assertTrue(followClickSource.contains("homeActionDelegate?.follow(follow = false, notify = false)"))
|
||||
assertFalse(source.contains("showFollowNotifyFragment"))
|
||||
assertTrue(source.contains("onCreatorChannelFollowProgressChanged"))
|
||||
assertTrue(source.contains("binding.layoutFollowCapsule.isEnabled = titleBarState.isActionEnabled"))
|
||||
@@ -1317,7 +1326,12 @@ class CreatorChannelActivitySourceTest {
|
||||
assertTrue(en.contains("name=\"creator_channel_home_donation_empty_title\">Be the first to\\nsupport this creator!"))
|
||||
assertTrue(ja.contains("name=\"creator_channel_home_donation_empty_title\">最初のサポートをしてみましょう!"))
|
||||
assertTrue(ko.contains("name=\"creator_channel_donation_empty_title\">아직 후원이 없습니다.\\n처음으로 크리에이터를 후원해 보세요!"))
|
||||
assertTrue(en.contains("name=\"creator_channel_donation_empty_title\">No support yet.\\nBe the first to support this creator!"))
|
||||
assertTrue(
|
||||
en.contains(
|
||||
"name=\"creator_channel_donation_empty_title\">No support yet.\\n" +
|
||||
"Be the first to support this creator!"
|
||||
)
|
||||
)
|
||||
assertTrue(ja.contains("name=\"creator_channel_donation_empty_title\">まだサポートがありません。\\n最初のサポートをしてみましょう!"))
|
||||
assertTrue(ko.contains("name=\"creator_channel_donation_action\">후원하기"))
|
||||
assertTrue(en.contains("name=\"creator_channel_donation_action\">Support"))
|
||||
|
||||
Reference in New Issue
Block a user