provide better way of reacting to comment

This commit is contained in:
k0shk0sh 2019-07-30 19:45:20 +02:00
parent 1771991ec9
commit 23d2efd1db
9 changed files with 306 additions and 71 deletions

View File

@ -6,11 +6,9 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import com.fastaccess.data.model.CommentAuthorAssociation
import com.fastaccess.data.model.CommentModel
import com.fastaccess.data.model.getEmoji
import com.fastaccess.github.R
import com.fastaccess.github.extensions.timeAgo
import com.fastaccess.github.ui.adapter.base.BaseViewHolder
import com.fastaccess.github.utils.extensions.popupEmoji
import io.noties.markwon.Markwon
import kotlinx.android.synthetic.main.comment_row_item.view.*
@ -62,26 +60,8 @@ class CommentViewHolder(
// val urlPattern = Patterns.WEB_URL
// Linkify.addLinks(description, urlPattern, null, null, filter)
addEmoji.setOnClickListener {
it.popupEmoji(requireNotNull(model.id), model.reactionGroups) {
callback.invoke(adapterPosition)
}
}
reactionsText.isVisible = model.reactionGroups?.any { it.users?.totalCount != 0 } ?: false
if (reactionsText.isVisible) {
val stringBuilder = StringBuilder()
model.reactionGroups?.forEach {
if (it.users?.totalCount != 0) {
stringBuilder.append(it.content.getEmoji())
.append(" ")
.append("${it.users?.totalCount}")
.append(" ")
}
}
reactionsText.text = stringBuilder
} else {
reactionsText.text = ""
adaptiveEmoticon.init(requireNotNull(model.id), model.reactionGroups) {
callback.invoke(adapterPosition)
}
}
}

View File

@ -36,12 +36,12 @@ import javax.inject.Inject
class EditorFragment : BaseFragment(), IconDialogFragment.IconDialogClickListener,
MarkdownLayout.MarkdownLayoutCallback,
CreateLinkDialogFragment.OnLinkSelected {
@Inject lateinit var markwon: Markwon
@Inject lateinit var preference: FastHubSharedPreference
@Inject lateinit var mentionsPresenter: MentionsPresenter
@Inject lateinit var markwonAdapterBuilder: MarkwonAdapter.Builder
override fun viewModel(): BaseViewModel? = null
override fun layoutRes(): Int = R.layout.editor_fragment_layout
@ -107,10 +107,7 @@ class EditorFragment : BaseFragment(), IconDialogFragment.IconDialogClickListene
title: String,
link: String,
isImage: Boolean
) {
//TODO upload pic and get URL
markdownLayout.onLinkSelected(title, link, isImage)
}
) = markdownLayout.onLinkSelected(title, link, isImage)
private fun initEditText() {
Autocomplete.on<String>(editText)

View File

@ -40,7 +40,6 @@ import com.fastaccess.github.utils.EXTRA_THREE
import com.fastaccess.github.utils.EXTRA_TWO
import com.fastaccess.github.utils.extensions.hideKeyboard
import com.fastaccess.github.utils.extensions.isConnected
import com.fastaccess.github.utils.extensions.popupEmoji
import com.fastaccess.github.utils.extensions.theme
import com.fastaccess.markdown.MarkdownProvider
import com.fastaccess.markdown.spans.LabelSpan
@ -291,10 +290,8 @@ class IssueFragment : BaseFragment(), LockUnlockFragment.OnLockReasonSelected,
R.color.material_red_500
}
)
addEmoji.setOnClickListener {
it.popupEmoji(requireNotNull(model.id), model.reactionGroups) {
initReactions(model)
}
adaptiveEmoticon.init(requireNotNull(model.id), model.reactionGroups) {
initReactions(model)
}
val isAuthor = login == me?.login || model.authorAssociation?.equals(CommentAuthorAssociation.OWNER.rawValue(), true) == true ||
model.authorAssociation?.equals(CommentAuthorAssociation.COLLABORATOR.rawValue(), true) == true

View File

@ -0,0 +1,176 @@
package com.fastaccess.github.ui.widget
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import androidx.core.view.isVisible
import com.fastaccess.data.model.ReactionContent
import com.fastaccess.data.model.ReactionGroupModel
import com.fastaccess.data.model.getEmoji
import com.fastaccess.github.R
import com.fastaccess.github.platform.works.ReactionWorker
import com.fastaccess.github.utils.extensions.popupEmoji
import kotlinx.android.synthetic.main.add_reactions_layout.view.*
/**
* Created by Kosh on 2019-07-30.
*/
class AdaptiveEmoticonLayout : LinearLayout {
constructor(context: Context?) : super(context)
constructor(
context: Context?,
attrs: AttributeSet?
) : super(context, attrs)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int
) : super(context, attrs, defStyleAttr)
@SuppressLint("RestrictedApi")
override fun onFinishInflate() {
super.onFinishInflate()
View.inflate(context, R.layout.add_reactions_layout, this)
}
fun init(
id: String,
reactionGroups: List<ReactionGroupModel>?,
callback: (() -> Unit)?
) {
addEmoji.setOnClickListener {
it.popupEmoji(id, reactionGroups) {
initReactions(reactionGroups)
callback?.invoke()
}
}
initReactions(reactionGroups)
thumbsUp.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.THUMBS_UP }, callback) }
thumbsDown.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.THUMBS_DOWN }, callback) }
confused.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.CONFUSED }, callback) }
laugh.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.LAUGH }, callback) }
hooray.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.HOORAY }, callback) }
heart.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.HEART }, callback) }
rocket.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.ROCKET }, callback) }
eyes.setOnClickListener { react(it, id, reactionGroups?.firstOrNull { it.content == ReactionContent.EYES }, callback) }
}
@SuppressLint("SetTextI18n")
private fun initReactions(
reactionGroups: List<ReactionGroupModel>?
) {
getReactionCount(reactionGroups, ReactionContent.THUMBS_UP).let {
if (it > 0) {
thumbsUp.isVisible = true
thumbsUp.text = "${ReactionContent.THUMBS_UP.getEmoji()} $it"
} else {
thumbsUp.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.THUMBS_DOWN).let {
if (it > 0) {
thumbsDown.isVisible = true
thumbsDown.text = "${ReactionContent.THUMBS_DOWN.getEmoji()} $it"
} else {
thumbsDown.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.CONFUSED).let {
if (it > 0) {
confused.isVisible = true
confused.text = "${ReactionContent.CONFUSED.getEmoji()} $it"
} else {
confused.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.LAUGH).let {
if (it > 0) {
laugh.isVisible = true
laugh.text = "${ReactionContent.LAUGH.getEmoji()} $it"
} else {
laugh.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.HOORAY).let {
if (it > 0) {
hooray.isVisible = true
hooray.text = "${ReactionContent.HOORAY.getEmoji()} $it"
} else {
hooray.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.HEART).let {
if (it > 0) {
heart.isVisible = true
heart.text = "${ReactionContent.HEART.getEmoji()} $it"
} else {
heart.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.ROCKET).let {
if (it > 0) {
rocket.isVisible = true
rocket.text = "${ReactionContent.ROCKET.getEmoji()} $it"
} else {
rocket.isVisible = false
}
}
getReactionCount(reactionGroups, ReactionContent.EYES).let {
if (it > 0) {
eyes.isVisible = true
eyes.text = "${ReactionContent.EYES.getEmoji()} $it"
} else {
eyes.isVisible = false
}
}
}
private fun getReactionCount(
reactionGroups: List<ReactionGroupModel>?,
content: ReactionContent
): Int = reactionGroups
?.filter { it.users != null && it.content != null }
?.firstOrNull { it.content == content }?.let {
return@let it.users?.totalCount ?: 0
} ?: 0
private fun react(
view: View,
id: String,
model: ReactionGroupModel?,
callback: (() -> Unit)?
) {
model?.let { reaction ->
val add: Boolean
if (reaction.viewerHasReacted == true) {
reaction.users?.totalCount = reaction.users?.totalCount?.minus(1)
model.viewerHasReacted = false
add = false
} else {
reaction.users?.totalCount = reaction.users?.totalCount?.plus(1)
model.viewerHasReacted = true
add = true
}
if (reaction.users?.totalCount == 0) {
view.isVisible = false
}
ReactionWorker.enqueue(model.content?.value ?: "", id, add)
callback?.invoke()
}
}
}

View File

@ -18,8 +18,16 @@ import kotlinx.android.synthetic.main.reactions_chips_layout.view.*
*/
class ReactionsChipGroup : ChipGroup {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(
context: Context?,
attrs: AttributeSet?
) : super(context, attrs)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int
) : super(context, attrs, defStyleAttr)
@SuppressLint("RestrictedApi")
override fun onFinishInflate() {
@ -31,7 +39,8 @@ class ReactionsChipGroup : ChipGroup {
id: String,
reactionGroups: List<ReactionGroupModel>?,
popupWindow: PopupWindow? = null,
callback: (() -> Unit)?) {
callback: (() -> Unit)?
) {
thumbsUp.text = "${ReactionContent.THUMBS_UP.getEmoji()} ${reactionGroups
?.firstOrNull { it.content == ReactionContent.THUMBS_UP }
?.users?.totalCount}"
@ -71,7 +80,8 @@ class ReactionsChipGroup : ChipGroup {
id: String,
model: ReactionGroupModel?,
popupWindow: PopupWindow?,
callback: (() -> Unit)?) {
callback: (() -> Unit)?
) {
model?.let { reaction ->
val add: Boolean
if (reaction.viewerHasReacted == true) {

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<merge 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="wrap_content"
android:orientation="horizontal"
tools:parentTag="com.fastaccess.github.ui.widget.AdaptiveEmoticonLayout"
tools:showIn="@layout/comment_row_item">
<com.google.android.material.chip.ChipGroup
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.chip.Chip
android:id="@+id/addEmoji"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/spacing_normal"
android:text="+"
app:chipBackgroundColor="?colorPrimaryDark"
app:chipIcon="@drawable/ic_add_emoji"
tools:ignore="HardcodedText" />
<com.google.android.material.chip.Chip
android:id="@+id/thumbsUp"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/thumbsDown"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/confused"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/laugh"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/hooray"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/heart"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/rocket"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
<com.google.android.material.chip.Chip
android:id="@+id/eyes"
style="@style/ChipStyleNoElevation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:chipBackgroundColor="?colorPrimaryDark" />
</com.google.android.material.chip.ChipGroup>
</merge>

View File

@ -64,28 +64,8 @@
app:autoSizeTextType="uniform"
tools:text="Owner" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/reactionsText"
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
app:autoSizeMaxTextSize="12sp"
app:autoSizeMinTextSize="10sp"
app:autoSizeStepGranularity="1dp"
tools:text="emoji 1, emoji 1, emoji 1, emoji 1, emoji 1, emoji 1, emoji 1, emoji 1, " />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/addEmoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="@dimen/spacing_normal"
android:layout_marginEnd="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_add_emoji" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu"
android:layout_width="wrap_content"
@ -103,6 +83,12 @@
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
android:textIsSelectable="true"
tools:text="Place the truffels in an ice blender, and toss immediately with tangy lime.immediately with tangy lime" />
<com.fastaccess.github.ui.widget.AdaptiveEmoticonLayout
android:id="@+id/adaptiveEmoticon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_normal" />
</LinearLayout>
</FrameLayout>

View File

@ -132,16 +132,6 @@
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/addEmoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="@dimen/spacing_normal"
android:layout_marginEnd="@dimen/spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_add_emoji" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu"
android:layout_width="wrap_content"
@ -231,4 +221,10 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
<com.fastaccess.github.ui.widget.AdaptiveEmoticonLayout
android:id="@+id/adaptiveEmoticon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_normal" />
</LinearLayout>

View File

@ -1,10 +1,11 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?icon_color"
android:pathData="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,9.5C14,8.7 14.7,8 15.5,8C16.3,8 17,8.7 17,9.5M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23Z"/>
android:pathData="M20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M10,9.5C10,10.3 9.3,11 8.5,11C7.7,11 7,10.3 7,9.5C7,8.7 7.7,8 8.5,8C9.3,8 10,8.7 10,9.5M17,9.5C17,10.3 16.3,11 15.5,11C14.7,11 14,10.3 14,9.5C14,8.7 14.7,8 15.5,8C16.3,8 17,8.7 17,9.5M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23Z"
tools:fillColor="#000" />
</vector>