prepared PR timeline events view holder.

@yakov116 please review
This commit is contained in:
kosh 2017-08-03 23:50:23 +08:00
parent 83de7da2d0
commit 7d58720ba9
5 changed files with 392 additions and 3 deletions

View File

@ -12,11 +12,11 @@ query PullRequestTimeline($owner: String!, $name: String!, $number: Int!, $page:
}
totalCount
nodes {
__typename
... on Commit {
id
oid
url
committedDate
messageHeadlineHTML
author {
name
@ -130,6 +130,11 @@ query PullRequestTimeline($owner: String!, $name: String!, $number: Int!, $page:
createdAt
isCrossRepository
isDirectReference
actor {
avatarUrl
login
url
}
commitRepository {
nameWithOwner
url
@ -178,6 +183,7 @@ query PullRequestTimeline($owner: String!, $name: String!, $number: Int!, $page:
}
}
... on LabeledEvent {
createdAt
actor {
login
avatarUrl
@ -189,6 +195,7 @@ query PullRequestTimeline($owner: String!, $name: String!, $number: Int!, $page:
}
}
... on UnlabeledEvent {
createdAt
actor {
login
avatarUrl
@ -224,6 +231,11 @@ query PullRequestTimeline($owner: String!, $name: String!, $number: Int!, $page:
createdAt
currentTitle
previousTitle
actor {
login
avatarUrl
url
}
}
... on LockedEvent {
createdAt
@ -243,6 +255,11 @@ query PullRequestTimeline($owner: String!, $name: String!, $number: Int!, $page:
}
... on DeployedEvent {
createdAt
actor {
login
avatarUrl
url
}
ref {
name
prefix

View File

@ -129,7 +129,7 @@ public class HtmlHelper {
return mySpanner;
}
@ColorInt static int getWindowBackground(@PrefGetter.ThemeType int theme) {
@ColorInt public static int getWindowBackground(@PrefGetter.ThemeType int theme) {
switch (theme) {
case PrefGetter.AMLOD:
return Color.parseColor("#0B162A");

View File

@ -2,6 +2,7 @@ package com.fastaccess.ui.adapter
import android.view.ViewGroup
import com.fastaccess.data.dao.timeline.PullRequestTimelineModel
import com.fastaccess.ui.adapter.viewholder.PullRequestEventViewHolder
import com.fastaccess.ui.adapter.viewholder.PullStatusViewHolder
import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
@ -16,13 +17,15 @@ class PullReqeustTimelineAdapter constructor(val data: ArrayList<PullRequestTime
when (viewType) {
PullRequestTimelineModel.STATUS -> PullStatusViewHolder.newInstance(parent)
}
return null
return PullRequestEventViewHolder.newInstance(parent, this)
}
override fun onBindView(holder: BaseViewHolder<PullRequestTimelineModel>?, position: Int) {
val item = data[position]
if (item.type == PullRequestTimelineModel.STATUS) {
(holder as PullStatusViewHolder).bind(item.status)
}else {
holder?.bind(item)
}
}

View File

@ -0,0 +1,368 @@
package com.fastaccess.ui.adapter.viewholder
import android.annotation.SuppressLint
import android.graphics.Color
import android.text.style.BackgroundColorSpan
import android.view.View
import android.view.ViewGroup
import butterknife.BindView
import com.fastaccess.R
import com.fastaccess.data.dao.timeline.PullRequestTimelineModel
import com.fastaccess.helper.ParseDateFormat
import com.fastaccess.helper.PrefGetter
import com.fastaccess.helper.ViewHelper
import com.fastaccess.provider.scheme.LinkParserHelper
import com.fastaccess.provider.timeline.HtmlHelper
import com.fastaccess.ui.widgets.AvatarLayout
import com.fastaccess.ui.widgets.FontTextView
import com.fastaccess.ui.widgets.ForegroundImageView
import com.fastaccess.ui.widgets.SpannableBuilder
import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
import com.zzhoujay.markdown.style.CodeSpan
import pr.PullRequestTimelineQuery
import java.util.*
/**
* Created by kosh on 03/08/2017.
*/
class PullRequestEventViewHolder private constructor(val view: View, adapter: BaseRecyclerAdapter<*, *, *>) :
BaseViewHolder<PullRequestTimelineModel>(view, adapter) {
@BindView(R.id.stateImage) lateinit var stateImage: ForegroundImageView
@BindView(R.id.avatarLayout) lateinit var avatarLayout: AvatarLayout
@BindView(R.id.stateText) lateinit var stateText: FontTextView
override fun bind(t: PullRequestTimelineModel) {
val node = t.node
avatarLayout.setUrl(null, null, false, false)
stateText.text = null
node?.let {
it.asAssignedEvent()?.let { assignedEvent(it) }
it.asBaseRefForcePushedEvent()?.let { forcePushEvent(it) }
it.asClosedEvent()?.let { closedEvent(it) }
it.asCommit()?.let { commitEvent(it) }
it.asDemilestonedEvent()?.let { demilestonedEvent(it) }
it.asDeployedEvent()?.let { deployedEvent(it) }
it.asHeadRefDeletedEvent()?.let { refDeletedEvent(it) }
it.asHeadRefForcePushedEvent()?.let { refForPushedEvent(it) }
it.asHeadRefRestoredEvent()?.let { headRefRestoredEvent(it) }
it.asLabeledEvent()?.let { labeledEvent(it) }
it.asLockedEvent()?.let { lockEvent(it) }
it.asMergedEvent()?.let { mergedEvent(it) }
it.asMilestonedEvent()?.let { milestoneEvent(it) }
it.asReferencedEvent()?.let { referenceEvent(it) }
it.asRenamedTitleEvent()?.let { renamedEvent(it) }
it.asReopenedEvent()?.let { reopenedEvent(it) }
it.asUnassignedEvent()?.let { unassignedEvent(it) }
it.asUnlabeledEvent()?.let { unlabeledEvent(it) }
it.asUnlockedEvent()?.let { unlockedEvent(it) }
}
}
@SuppressLint("SetTextI18n")
private fun unlockedEvent(event: PullRequestTimelineQuery.AsUnlockedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("unlocked this conversation")
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_lock)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun unlabeledEvent(event: PullRequestTimelineQuery.AsUnlabeledEvent) {
event.actor()?.let {
val color = Color.parseColor("#" + event.label().color())
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("unlabeled")
.append(" ")
.append(event.label().name(), CodeSpan(color, ViewHelper.generateTextColor(color), 5.0f))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_label)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun unassignedEvent(event: PullRequestTimelineQuery.AsUnassignedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("unassigned")
.append(" ")
.append(event.user()?.login())
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_profile)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun reopenedEvent(event: PullRequestTimelineQuery.AsReopenedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("reopened this")
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_issue_opened)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun renamedEvent(event: PullRequestTimelineQuery.AsRenamedTitleEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("renamed this from").append(" ").append(event.previousTitle())
.append(" ").append("to").append(" ").bold(event.currentTitle())
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_edit)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun referenceEvent(event: PullRequestTimelineQuery.AsReferencedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append(if (event.isCrossRepository) "cross referenced this" else "referenced this")
.append(" ")
.append("from").append(" ")
.url(if (event.commit() != null) {
substring(event.commit()?.oid()?.toString())
} else if (event.subject().asIssue() != null) {
"${event.subject().asIssue()?.title()}#${event.subject().asIssue()?.number()}"
} else if (event.subject().asPullRequest() != null) {
"${event.subject().asPullRequest()?.title()}#${event.subject().asPullRequest()?.number()}"
} else {
""
})
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_push)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun milestoneEvent(event: PullRequestTimelineQuery.AsMilestonedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("added this to the")
.append(" ")
.append(event.milestoneTitle()).append(" ").append("milestone")
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_milestone)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun mergedEvent(event: PullRequestTimelineQuery.AsMergedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("merged this in")
.append(" ")
.url(substring(event.commit()?.oid()?.toString()))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_merge)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun lockEvent(event: PullRequestTimelineQuery.AsLockedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("locked and limited conversation to collaborators")
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_lock)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun labeledEvent(event: PullRequestTimelineQuery.AsLabeledEvent) {
event.actor()?.let {
val color = Color.parseColor("#" + event.label().color())
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("labeled")
.append(" ")
.append(event.label().name(), CodeSpan(color, ViewHelper.generateTextColor(color), 5.0f))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_label)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun headRefRestoredEvent(event: PullRequestTimelineQuery.AsHeadRefRestoredEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("head ref restored", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType())))
.append(" ")
.url(substring(event.pullRequest().headRefName()))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_push)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun refForPushedEvent(event: PullRequestTimelineQuery.AsHeadRefForcePushedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("reference force pushed to", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType())))
.append(" ")
.url(substring(event.afterCommit().oid().toString()))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_push)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun refDeletedEvent(event: PullRequestTimelineQuery.AsHeadRefDeletedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("head ref delete", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType())))
.append(" ")
.url(substring(event.headRefName()))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_trash)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun deployedEvent(event: PullRequestTimelineQuery.AsDeployedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("make a deployment", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType())))
.append(" ")
.append(event.deployment().latestStatus()?.state()?.name)
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_push)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun demilestonedEvent(event: PullRequestTimelineQuery.AsDemilestonedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("removed this from the")
.append(" ")
.append(event.milestoneTitle()).append(" ").append("milestone")
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_milestone)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun commitEvent(event: PullRequestTimelineQuery.AsCommit) {
event.author()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.name())
.append(" ")
.append("committed")
.append(" ")
.append("${event.messageHeadlineHTML()}#${substring(event.oid().toString())}")
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.committedDate() as Date)))
stateImage.setImageResource(R.drawable.ic_push)
avatarLayout.setUrl(it.user()?.avatarUrl().toString(), it.user()?.login(), false,
LinkParserHelper.isEnterprise(it.user()?.url().toString()))
}
}
private fun closedEvent(event: PullRequestTimelineQuery.AsClosedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("closed this in")
.append(" ")
.url(substring(event.commit()?.oid()?.toString()))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_merge)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun forcePushEvent(event: PullRequestTimelineQuery.AsBaseRefForcePushedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("force pushed to", BackgroundColorSpan(HtmlHelper.getWindowBackground(PrefGetter.getThemeType())))
.append(" ")
.url(substring(event.afterCommit().oid().toString()))
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_push)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun assignedEvent(event: PullRequestTimelineQuery.AsAssignedEvent) {
event.actor()?.let {
stateText.text = SpannableBuilder.builder()
.bold(it.login())
.append(" ")
.append("assigned")
.append(" ")
.append(event.user()?.login())
.append(" ")
.append(ParseDateFormat.getTimeAgo((event.createdAt() as Date)))
stateImage.setImageResource(R.drawable.ic_profile)
avatarLayout.setUrl(it.avatarUrl().toString(), it.login(), false, LinkParserHelper.isEnterprise(it.url().toString()))
}
}
private fun substring(value: String?): String {
if (value == null) {
return ""
}
if (value.length <= 7) return value
else return value.substring(0, 7)
}
companion object {
fun newInstance(parent: ViewGroup, adapter: BaseRecyclerAdapter<*, *, *>): PullRequestEventViewHolder {
return PullRequestEventViewHolder(getView(parent, R.layout.label_row_item), adapter)
}
}
}

View File

@ -120,6 +120,7 @@ public abstract class BaseRecyclerAdapter<M, VH extends BaseViewHolder,
}
public void addItem(M item) {
removeProgress();
data.add(item);
notifyItemInserted(data.size() - 1);
}