display pullrequest

This commit is contained in:
k0shk0sh 2019-08-27 14:47:45 +02:00
parent d386dc5a8b
commit 0470524f6d
21 changed files with 929 additions and 417 deletions

View File

@ -8,6 +8,7 @@ import com.fastaccess.github.ui.modules.issue.IssueActivity
import com.fastaccess.github.ui.modules.issuesprs.edit.EditIssuePrActivity
import com.fastaccess.github.ui.modules.main.MainActivity
import com.fastaccess.github.ui.modules.multipurpose.MultiPurposeActivity
import com.fastaccess.github.ui.modules.pr.PullRequestActivity
import com.fastaccess.github.ui.modules.profile.ProfileActivity
import com.fastaccess.github.ui.modules.trending.TrendingActivity
import dagger.Module
@ -34,4 +35,5 @@ abstract class ActivityBindingModule {
@PerActivity @ContributesAndroidInjector abstract fun editorActivity(): EditorActivity
@PerActivity @ContributesAndroidInjector abstract fun editIssuePrActivity(): EditIssuePrActivity
@PerActivity @ContributesAndroidInjector abstract fun commentActivity(): CommentActivity
@PerActivity @ContributesAndroidInjector abstract fun pullRequestActivity(): PullRequestActivity
}

View File

@ -17,6 +17,7 @@ import com.fastaccess.github.ui.modules.main.fragment.MainFragment
import com.fastaccess.github.ui.modules.notifications.NotificationPagerFragment
import com.fastaccess.github.ui.modules.notifications.fragment.read.AllNotificationsFragment
import com.fastaccess.github.ui.modules.notifications.fragment.unread.UnreadNotificationsFragment
import com.fastaccess.github.ui.modules.pr.fragment.PullRequestFragment
import com.fastaccess.github.ui.modules.profile.feeds.ProfileFeedFragment
import com.fastaccess.github.ui.modules.profile.followersandfollowings.ProfileFollowersFragment
import com.fastaccess.github.ui.modules.profile.fragment.ProfileFragment
@ -60,4 +61,5 @@ abstract class FragmentBindingModule {
@PerFragment @ContributesAndroidInjector(modules = [EditorModule::class]) abstract fun provideEditorFragment(): EditorFragment
@PerFragment @ContributesAndroidInjector(modules = [EditIssuePrModule::class]) abstract fun provideEditIssuePrFragment(): EditIssuePrFragment
@PerFragment @ContributesAndroidInjector(modules = [CommentModule::class]) abstract fun provideCommentFragment(): CommentFragment
@PerFragment @ContributesAndroidInjector(modules = [PullRequestModule::class]) abstract fun providePullRequestFragment(): PullRequestFragment
}

View File

@ -11,6 +11,7 @@ import com.fastaccess.github.ui.modules.comment.CommentFragment
import com.fastaccess.github.ui.modules.editor.EditorFragment
import com.fastaccess.github.ui.modules.issue.fragment.IssueFragment
import com.fastaccess.github.ui.modules.issuesprs.edit.EditIssuePrFragment
import com.fastaccess.github.ui.modules.pr.fragment.PullRequestFragment
import com.fastaccess.github.usecase.search.FilterSearchUsersUseCase
import com.fastaccess.github.utils.extensions.theme
import com.fastaccess.markdown.GrammarLocatorDef
@ -96,4 +97,9 @@ class EditIssuePrModule {
@Module(includes = [FragmentModule::class])
class CommentModule {
@PerFragment @Provides fun provideEditorContext(fragment: CommentFragment) = fragment.requireContext()
}
@Module(includes = [FragmentModule::class])
class PullRequestModule {
@PerFragment @Provides fun provideEditorContext(fragment: PullRequestFragment) = fragment.requireContext()
}

View File

@ -17,6 +17,7 @@ import com.fastaccess.github.ui.modules.issuesprs.fragment.viewmodel.FilterIssue
import com.fastaccess.github.ui.modules.main.fragment.viewmodel.MainFragmentViewModel
import com.fastaccess.github.ui.modules.notifications.fragment.read.AllNotificationsViewModel
import com.fastaccess.github.ui.modules.notifications.fragment.unread.viewmodel.UnreadNotificationsViewModel
import com.fastaccess.github.ui.modules.pr.fragment.viewmodel.PullRequestTimelineViewModel
import com.fastaccess.github.ui.modules.profile.feeds.viewmodel.ProfileFeedsViewModel
import com.fastaccess.github.ui.modules.profile.followersandfollowings.viewmodel.FollowersFollowingViewModel
import com.fastaccess.github.ui.modules.profile.fragment.viewmodel.ProfileViewModel
@ -104,4 +105,7 @@ abstract class ViewModelModule {
@Binds @IntoMap @ViewModelKey(EditIssuePrViewModel::class)
abstract fun bindEditIssuePrViewModel(viewModel: EditIssuePrViewModel): ViewModel
@Binds @IntoMap @ViewModelKey(PullRequestTimelineViewModel::class)
abstract fun bindPullRequestTimelineViewModel(viewModel: PullRequestTimelineViewModel): ViewModel
}

View File

@ -27,7 +27,7 @@ fun MainScreenModel.onClick(fragment: Fragment) {
MainScreenModelRowType.ISSUES_TITLE -> fragment.route(FILTER_ISSUE_LINK)
MainScreenModelRowType.ISSUES -> fragment.route("${model.issuesPullsModel?.url}")
MainScreenModelRowType.PRS_TITLE -> fragment.route(FILTER_PR_LINK)
MainScreenModelRowType.PRS -> Timber.e("${model.issuesPullsModel}")
MainScreenModelRowType.PRS -> fragment.route(model.issuesPullsModel?.url)
}
}
@ -36,6 +36,9 @@ fun FeedModel.onClick(fragment: Fragment) {
when (type) {
EventsType.IssueCommentEvent -> fragment.route("${payload?.issue?.htmlUrl}")
EventsType.IssuesEvent -> fragment.route("${payload?.issue?.htmlUrl}")
EventsType.PullRequestEvent -> fragment.route("${payload?.pullRequest?.htmlUrl}")
EventsType.PullRequestReviewCommentEvent -> fragment.route("${payload?.pullRequest?.htmlUrl}")
EventsType.PullRequestReviewEvent -> fragment.route("${payload?.pullRequest?.htmlUrl}")
else -> fragment.route(actor?.url) // TODO(handle click)
}
}

View File

@ -160,7 +160,7 @@ class IssueFragment : BaseIssuePrTimelineFragment() {
}
val isAuthor = login == me?.login || model.authorAssociation?.equals(CommentAuthorAssociation.OWNER.rawValue(), true) == true ||
model.authorAssociation?.equals(CommentAuthorAssociation.COLLABORATOR.rawValue(), true) == true
menuClick(model, isAuthor)
menuClick(model.url, model.labels, model.assignees, model.title, model.body, isAuthor)
initLabels(model.labels)
initAssignees(model.assignees)
initMilestone(model.milestone)

View File

@ -19,6 +19,7 @@ import com.fastaccess.data.model.parcelable.LabelModel
import com.fastaccess.data.model.parcelable.LoginRepoParcelableModel
import com.fastaccess.data.model.parcelable.MilestoneModel
import com.fastaccess.data.persistence.models.IssueModel
import com.fastaccess.data.persistence.models.PullRequestModel
import com.fastaccess.github.R
import com.fastaccess.github.base.BaseFragment
import com.fastaccess.github.extensions.*
@ -215,7 +216,11 @@ abstract class BaseIssuePrTimelineFragment : BaseFragment(),
}
protected fun menuClick(
model: IssueModel,
url: String?,
labels: List<LabelModel>?,
assignees: List<ShortUserModel>?,
title: String?,
body: String?,
isOwner: Boolean
) {
toolbar.setOnMenuItemClickListener { item ->
@ -230,7 +235,7 @@ abstract class BaseIssuePrTimelineFragment : BaseFragment(),
recyclerView.scrollToPosition(0)
}
R.id.closeIssue -> closeOpenIssuePr()
R.id.share -> requireActivity().shareUrl(model.url)
R.id.share -> requireActivity().shareUrl(url)
R.id.lockIssue -> if (item.title == getString(R.string.lock_issue)) {
MultiPurposeBottomSheetDialog.show(childFragmentManager, MultiPurposeBottomSheetDialog.BottomSheetFragmentType.LOCK_UNLOCK)
} else {
@ -238,26 +243,30 @@ abstract class BaseIssuePrTimelineFragment : BaseFragment(),
}
R.id.labels -> MultiPurposeBottomSheetDialog.show(
childFragmentManager,
MultiPurposeBottomSheetDialog.BottomSheetFragmentType.LABELS, LoginRepoParcelableModel(login, repo, model.labels, number)
MultiPurposeBottomSheetDialog.BottomSheetFragmentType.LABELS, LoginRepoParcelableModel(login, repo, labels, number)
)
R.id.assignees -> MultiPurposeBottomSheetDialog.show(
childFragmentManager,
MultiPurposeBottomSheetDialog.BottomSheetFragmentType.ASSIGNEES, LoginRepoParcelableModel(login, repo, model.assignees, number)
MultiPurposeBottomSheetDialog.BottomSheetFragmentType.ASSIGNEES, LoginRepoParcelableModel(login, repo, assignees, number)
)
R.id.milestone -> MultiPurposeBottomSheetDialog.show(
childFragmentManager,
MultiPurposeBottomSheetDialog.BottomSheetFragmentType.MILESTONE, LoginRepoParcelableModel(login, repo, model.assignees, number)
MultiPurposeBottomSheetDialog.BottomSheetFragmentType.MILESTONE, LoginRepoParcelableModel(login, repo, assignees, number)
)
R.id.edit -> startEditingIssue(model, isOwner)
R.id.edit -> startEditingIssue(title, body, isOwner)
}
return@setOnMenuItemClickListener true
}
}
private fun startEditingIssue(model: IssueModel, isOwner: Boolean) {
private fun startEditingIssue(
title: String?,
body: String?,
isOwner: Boolean
) {
EditIssuePrActivity.startForResult(
this, EditIssuePrBundleModel(
login, repo, number, model.title, model.body, false, isOwner = isOwner
login, repo, number, title, body, false, isOwner = isOwner
), EDIT_ISSUE_REQUEST_CODE
)
}

View File

@ -6,6 +6,7 @@ import com.fastaccess.github.base.BaseActivity
import com.fastaccess.github.extensions.replace
import com.fastaccess.github.platform.deeplink.WebDeepLink
import com.fastaccess.github.ui.modules.issue.fragment.IssueFragment
import com.fastaccess.github.ui.modules.pr.fragment.PullRequestFragment
/**
* Created by Kosh on 28.01.19.
@ -23,7 +24,7 @@ class PullRequestActivity : BaseActivity() {
finish()
return
}
replace(R.id.container, IssueFragment.newInstance(login, repo, number), IssueFragment.TAG)
replace(R.id.container, PullRequestFragment.newInstance(login, repo, number), IssueFragment.TAG)
}
}

View File

@ -0,0 +1,217 @@
package com.fastaccess.github.ui.modules.pr.fragment
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.fastaccess.data.model.CommentModel
import com.fastaccess.data.model.TimelineModel
import com.fastaccess.data.persistence.models.LoginModel
import com.fastaccess.data.persistence.models.PullRequestModel
import com.fastaccess.data.storage.FastHubSharedPreference
import com.fastaccess.github.R
import com.fastaccess.github.base.BaseViewModel
import com.fastaccess.github.extensions.isTrue
import com.fastaccess.github.extensions.observeNotNull
import com.fastaccess.github.extensions.routeForResult
import com.fastaccess.github.extensions.timeAgo
import com.fastaccess.github.ui.adapter.IssueTimelineAdapter
import com.fastaccess.github.ui.modules.issuesprs.BaseIssuePrTimelineFragment
import com.fastaccess.github.ui.modules.pr.fragment.viewmodel.PullRequestTimelineViewModel
import com.fastaccess.github.utils.EDITOR_DEEPLINK
import com.fastaccess.github.utils.EXTRA
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.theme
import com.fastaccess.markdown.widget.SpannableBuilder
import github.type.CommentAuthorAssociation
import github.type.IssueState
import github.type.LockReason
import io.noties.markwon.Markwon
import io.noties.markwon.utils.NoCopySpannableFactory
import kotlinx.android.synthetic.main.comment_box_layout.*
import kotlinx.android.synthetic.main.issue_header_row_item.*
import kotlinx.android.synthetic.main.issue_pr_view_layout.*
import kotlinx.android.synthetic.main.recyclerview_fastscroll_empty_state_layout.*
import kotlinx.android.synthetic.main.title_toolbar_layout.*
import javax.inject.Inject
/**
* Created by Kosh on 28.01.19.
*/
class PullRequestFragment : BaseIssuePrTimelineFragment() {
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
@Inject lateinit var markwon: Markwon
@Inject lateinit var preference: FastHubSharedPreference
private val viewModel by lazy { ViewModelProviders.of(this, viewModelFactory).get(PullRequestTimelineViewModel::class.java) }
override val adapter by lazy {
IssueTimelineAdapter(markwon, preference.theme, onCommentClicked(), onDeleteCommentClicked(), onEditCommentClicked())
}
override fun layoutRes(): Int = R.layout.issue_pr_fragment_layout
override fun viewModel(): BaseViewModel? = viewModel
override fun isPr(): Boolean = true
override fun lockIssuePr(lockReason: LockReason?) = viewModel.lockUnlockIssue(login, repo, number, lockReason, true)
override fun onMilestoneAdd(timeline: TimelineModel) = viewModel.addTimeline(timeline)
override fun reload(refresh: Boolean) = viewModel.loadData(login, repo, number, refresh)
override fun sendComment(comment: String) = viewModel.createComment(login, repo, number, comment)
override fun onFragmentCreatedWithUser(
view: View,
savedInstanceState: Bundle?
) {
super.onFragmentCreatedWithUser(view, savedInstanceState)
observeChanges()
}
override fun onDestroyView() {
mentionsPresenter.onDispose()
super.onDestroyView()
}
override fun editIssuerPr(
title: String?,
description: String?
) = viewModel.editIssue(login, repo, number, title, description)
override fun lockUnlockIssuePr() = viewModel.lockUnlockIssue(login, repo, number)
override fun closeOpenIssuePr() = viewModel.closeOpenIssue(login, repo, number)
private fun observeChanges() {
viewModel.getPullRequest(login, repo, number).observeNotNull(this) {
initIssue(it.first, it.second)
}
viewModel.timeline.observeNotNull(this) { timeline ->
adapter.submitList(timeline)
}
viewModel.userNamesLiveData.observeNotNull(this) {
mentionsPresenter.setUsers(it)
}
viewModel.commentProgress.observeNotNull(this) {
commentProgress.isVisible = it
sendComment.isVisible = !it
if (!it) {
commentText.setText("")
commentText.hideKeyboard()
recyclerView.scrollToPosition(adapter.itemCount)
}
}
viewModel.forceAdapterUpdate.observeNotNull(this) {
it.isTrue { adapter.notifyDataSetChanged() }
}
}
@SuppressLint("DefaultLocale")
private fun initIssue(
model: PullRequestModel,
me: LoginModel?
) {
issueHeaderWrapper.isVisible = true
val theme = preference.theme
title.text = model.title
toolbar.title = SpannableBuilder.builder()
.append(getString(R.string.pull_request))
.bold("#${model.number}")
opener.text = if (model.merged == true) {
SpannableBuilder.builder()
.bold(model.mergedBy?.login)
.space()
.append(getString(R.string.merged).toLowerCase())
.space()
.bold(model.headRefName)
.space()
.append(getString(R.string.to))
.space()
.bold(model.baseRefName)
.space()
.append(model.mergedAt?.timeAgo())
} else {
SpannableBuilder.builder()
.bold(model.author?.login)
.space()
.append(getString(R.string.want_to_merge))
.space()
.bold(model.headRefName)
.space()
.append(getString(R.string.to))
.space()
.bold(model.baseRefName)
.space()
.append(model.createdAt?.timeAgo())
}
userIcon.loadAvatar(model.author?.avatarUrl, model.author?.url ?: "")
author.text = model.author?.login
association.text = if (CommentAuthorAssociation.NONE.rawValue() == model.authorAssociation) {
model.updatedAt?.timeAgo()
} else {
"${model.authorAssociation?.toLowerCase()?.replace("_", "")} ${model.updatedAt?.timeAgo()}"
}
description.post {
val bodyMd = model.body
// description.setMovementMethod(LinkMovementMethod.getInstance())
description.setSpannableFactory(NoCopySpannableFactory.getInstance())
markwon.setMarkdown(
description, if (!bodyMd.isNullOrEmpty()) bodyMd else "**${getString(R.string.no_description_provided)}**"
)
}
state.text = model.state?.toLowerCase()
state.setChipBackgroundColorResource(
if (IssueState.OPEN.rawValue().equals(model.state, true)) {
R.color.material_green_500
} else {
R.color.material_red_500
}
)
adaptiveEmoticon.init(requireNotNull(model.id), model.reactionGroups) {
adaptiveEmoticon.initReactions(model.reactionGroups)
}
val isAuthor = login == me?.login || model.authorAssociation?.equals(CommentAuthorAssociation.OWNER.rawValue(), true) == true ||
model.authorAssociation?.equals(CommentAuthorAssociation.COLLABORATOR.rawValue(), true) == true
menuClick(model.url, model.labels, model.assignees, model.title, model.body, isAuthor)
initLabels(model.labels)
initAssignees(model.assignees)
initMilestone(model.milestone)
initToolbarMenu(isAuthor, model.viewerCanUpdate == true, model.viewerDidAuthor, model.locked, state = model.state)
recyclerView.removeEmptyView()
}
override fun onEditCommentClicked(): (position: Int, comment: CommentModel) -> Unit = { position, comment ->
routeForResult(
EDITOR_DEEPLINK, EDIT_COMMENT_REQUEST_CODE, bundleOf(
EXTRA to comment.body,
EXTRA_TWO to comment.databaseId
)
)
}
override fun onDeleteCommentClicked(): (position: Int, comment: CommentModel) -> Unit = { position, comment ->
viewModel.deleteComment(login, repo, comment.databaseId?.toLong() ?: 0L)
}
override fun onEditComment(comment: String?, commentId: Int?) {
viewModel.editComment(login, repo, comment, commentId?.toLong())
}
companion object {
const val TAG = "IssueFragment"
fun newInstance(
login: String,
repo: String,
number: Int
) = PullRequestFragment().apply {
arguments = bundleOf(EXTRA to login, EXTRA_TWO to repo, EXTRA_THREE to number)
}
}
}

View File

@ -0,0 +1,222 @@
package com.fastaccess.github.ui.modules.pr.fragment.viewmodel
import androidx.lifecycle.MutableLiveData
import com.fastaccess.data.model.PageInfoModel
import com.fastaccess.data.model.TimelineModel
import com.fastaccess.data.repository.LoginLocalRepository
import com.fastaccess.data.repository.PullRequestRepository
import com.fastaccess.github.base.BaseViewModel
import com.fastaccess.github.extensions.filterNull
import com.fastaccess.github.extensions.map
import com.fastaccess.github.usecase.issuesprs.*
import github.type.LockReason
import io.reactivex.Observable
import timber.log.Timber
import javax.inject.Inject
/**
* Created by Kosh on 20.10.18.
*/
class PullRequestTimelineViewModel @Inject constructor(
private val issueUseCase: GetPullRequestUseCase,
private val timelineUseCase: GetIssueTimelineUseCase,
private val issueRepositoryProvider: PullRequestRepository,
private val closeOpenIssuePrUseCase: CloseOpenIssuePrUseCase,
private val lockUnlockIssuePrUseCase: LockUnlockIssuePrUseCase,
private val loginRepositoryProvider: LoginLocalRepository,
private val createIssueCommentUseCase: CreateIssueCommentUseCase,
private val editIssuePrUseCase: EditIssuePrUseCase,
private val deleteCommentUseCase: DeleteCommentUseCase,
private val editCommentUseCase: EditCommentUseCase
) : BaseViewModel() {
private var pageInfo: PageInfoModel? = null
private val list = arrayListOf<TimelineModel>()
val forceAdapterUpdate = MutableLiveData<Boolean>()
val timeline = MutableLiveData<ArrayList<TimelineModel>>()
val userNamesLiveData = MutableLiveData<ArrayList<String>>()
val commentProgress = MutableLiveData<Boolean>()
fun getPullRequest(
login: String,
repo: String,
number: Int
) = issueRepositoryProvider.getPullRequestByNumber("$login/$repo", number)
.filterNull()
.map { Pair(it, loginRepositoryProvider.getLoginBlocking()) }
fun loadData(
login: String,
repo: String,
number: Int,
reload: Boolean = false
) {
if (reload) {
pageInfo = null
list.clear()
}
val pageInfo = pageInfo
if (!reload && (pageInfo != null && !pageInfo.hasNextPage)) return
val cursor = if (hasNext()) pageInfo?.endCursor else null
if (pageInfo == null) {
issueUseCase.login = login
issueUseCase.repo = repo
issueUseCase.number = number
justSubscribe(issueUseCase.buildObservable()
.flatMap { loadTimeline(login, repo, number, cursor) }
.map { mapToUserNames(it.second) })
} else {
justSubscribe(loadTimeline(login, repo, number, cursor)
.map { mapToUserNames(it.second) })
}
}
private fun loadTimeline(
login: String,
repo: String,
number: Int,
cursor: String?
): Observable<Pair<PageInfoModel, List<TimelineModel>>> {
return Observable.empty()
// timelineUseCase.login = login
// timelineUseCase.repo = repo
// timelineUseCase.number = number
// timelineUseCase.page = Input.optional(cursor)
// return timelineUseCase.buildObservable()
// .doOnNext {
// this.pageInfo = it.first
// list.addAll(it.second)
// timeline.postValue(ArrayList(list))
// }
}
fun closeOpenIssue(
login: String,
repo: String,
number: Int
) {
closeOpenIssuePrUseCase.repo = repo
closeOpenIssuePrUseCase.login = login
closeOpenIssuePrUseCase.number = number
justSubscribe(closeOpenIssuePrUseCase.buildObservable()
.doOnNext {
addTimeline(it)
})
}
fun lockUnlockIssue(
login: String,
repo: String,
number: Int,
lockReason: LockReason? = null,
lock: Boolean = false
) {
lockUnlockIssuePrUseCase.repo = repo
lockUnlockIssuePrUseCase.login = login
lockUnlockIssuePrUseCase.number = number
lockUnlockIssuePrUseCase.lockReason = lockReason
lockUnlockIssuePrUseCase.lock = lock
justSubscribe(lockUnlockIssuePrUseCase.buildObservable()
.doOnNext {
addTimeline(it)
})
}
fun createComment(
login: String,
repo: String,
number: Int,
comment: String
) {
createIssueCommentUseCase.login = login
createIssueCommentUseCase.repo = repo
createIssueCommentUseCase.number = number
createIssueCommentUseCase.body = comment
add(createIssueCommentUseCase.buildObservable()
.doOnSubscribe { commentProgress.postValue(true) }
.subscribe({
addTimeline(it)
commentProgress.postValue(false)
}, {
commentProgress.postValue(false)
handleError(it)
})
)
}
fun addTimeline(it: TimelineModel) {
list.add(it)
timeline.postValue(ArrayList(list))
}
fun hasNext() = pageInfo?.hasNextPage ?: false
private fun mapToUserNames(list: List<TimelineModel>) {
val _list = userNamesLiveData.value ?: arrayListOf()
_list.addAll(list.map { it.comment?.author?.login ?: it.comment?.author?.name ?: "" })
userNamesLiveData.postValue(_list)
}
fun editIssue(
login: String,
repo: String,
number: Int,
title: String?,
description: String?
) {
editIssuePrUseCase.login = login
editIssuePrUseCase.repo = repo
editIssuePrUseCase.number = number
editIssuePrUseCase.title = title
editIssuePrUseCase.description = description
justSubscribe(editIssuePrUseCase.buildObservable())
}
fun deleteComment(
login: String,
repo: String,
commentId: Long
) {
deleteCommentUseCase.commentId = commentId
deleteCommentUseCase.login = login
deleteCommentUseCase.repo = repo
justSubscribe(deleteCommentUseCase.buildObservable()
.map {
val index = list.indexOfFirst { it.comment?.databaseId?.toLong() == commentId }
if (index != -1) {
list.removeAt(index)
}
return@map list
}
.doOnNext { list ->
timeline.postValue(ArrayList(list))
})
}
fun editComment(
login: String,
repo: String,
comment: String?,
commentId: Long?
) {
if (!comment.isNullOrBlank() && commentId != null) {
editCommentUseCase.comment = comment
editCommentUseCase.login = login
editCommentUseCase.repo = repo
editCommentUseCase.commentId = commentId
justSubscribe(editCommentUseCase.buildObservable()
.map {
val index = list.indexOfFirst { it.comment?.databaseId?.toLong() == commentId }
val item = list.getOrNull(index) ?: return@map list
item.comment?.body = comment
list[index] = item
Timber.e("${list[index]}")
return@map list
}
.doOnNext { list ->
timeline.postValue(ArrayList(list))
forceAdapterUpdate.postValue(true)
})
}
}
}

View File

@ -85,9 +85,7 @@ class ProfileFragment : BasePagerFragment() {
organizationList.adapter = orgsAdapter
pinnedList.adapter = pinnedReposAdapter
pinnedList.addDivider()
observeChanges()
behaviour.state = AnchorSheetBehavior.STATE_ANCHOR
toggleArrow.setOnClickListener {
@ -120,6 +118,7 @@ class ProfileFragment : BasePagerFragment() {
}
followers.setOnClickListener { if (pager.adapter != null) selectTab(FragmentType.FOLLOWERS) }
following.setOnClickListener { if (pager.adapter != null) selectTab(FragmentType.FOLLOWINGS) }
viewModel.getUserFromRemote(loginBundle)
}
override fun onBackPressed(): Boolean {
@ -132,12 +131,8 @@ class ProfileFragment : BasePagerFragment() {
}
private fun observeChanges() {
viewModel.getUser(loginBundle).observeNull(this) { user ->
if (user == null) {
viewModel.getUserFromRemote(loginBundle)
} else {
initUI(user)
}
viewModel.getUser(loginBundle).observeNotNull(this) { user ->
initUI(user)
}
viewModel.isBlocked.observeNotNull(this) {

View File

@ -0,0 +1,212 @@
package com.fastaccess.github.usecase.issuesprs
import com.fastaccess.data.model.*
import com.fastaccess.data.model.parcelable.LabelModel
import com.fastaccess.domain.usecase.base.BaseObservableUseCase
import com.fastaccess.extension.*
import github.fragment.*
abstract class BaseTimelineUseCase : BaseObservableUseCase() {
protected fun getTransferred(node: Transferred): TimelineModel = TimelineModel(
transferredEventModel = TransferredEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.fromRepository?.nameWithOwner
)
)
protected fun getRenamed(node: Renamed): TimelineModel = TimelineModel(
renamedEventModel = RenamedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.currentTitle, node.previousTitle
)
)
protected fun getDemilestoned(node: Demilestoned): TimelineModel = TimelineModel(
milestoneEventModel = MilestoneDemilestonedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.milestoneTitle, false
)
)
protected fun getMilestone(node: Milestoned): TimelineModel = TimelineModel(
milestoneEventModel = MilestoneDemilestonedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.milestoneTitle, true
)
)
protected fun getUnassigned(
node: UnAssigned,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.assignedEventModel != null }.map {
if (it.assignedEventModel?.createdAt?.time == node.createdAt.time) {
it.assignedEventModel?.users?.add(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
assignedEventModel = AssignedUnAssignedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false,
arrayListOf(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
)
)
}
return null
}
protected fun getAssigned(
node: Assigned,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.assignedEventModel != null }.map {
if (it.assignedEventModel?.createdAt?.time == node.createdAt.time) {
it.assignedEventModel?.users?.add(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
assignedEventModel = AssignedUnAssignedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), true,
arrayListOf(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
)
)
}
return null
}
protected fun getUnsubscribed(
node: Unsubscribed
): TimelineModel = TimelineModel(
subscribedUnsubscribedEvent = SubscribedUnsubscribedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false
)
)
protected fun getSubscribed(node: Subscribed): TimelineModel = TimelineModel(
subscribedUnsubscribedEvent = SubscribedUnsubscribedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false
)
)
protected fun getUnlabeled(
node: UnLabeled,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.labelUnlabeledEvent != null }.map {
if (it.labelUnlabeledEvent?.createdAt?.time == node.createdAt.time) {
it.labelUnlabeledEvent?.labels?.add(constructLabel(node.label))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
labelUnlabeledEvent = LabelUnlabeledEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false, arrayListOf(constructLabel(node.label))
)
)
}
return null
}
protected fun getLabel(
node: Labeled,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.labelUnlabeledEvent != null }.map {
if (it.labelUnlabeledEvent?.createdAt?.time == node.createdAt.time) {
it.labelUnlabeledEvent?.labels?.add(constructLabel(node.label))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
labelUnlabeledEvent = LabelUnlabeledEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), true, arrayListOf(constructLabel(node.label))
)
)
}
return null
}
protected fun constructLabel(m: Any): LabelModel {
return when (m) {
is Labels -> LabelModel(m.name, m.color)
else -> throw IllegalArgumentException("$m is not instance of any Label")
}
}
protected fun getUnlocked(node: Unlocked): TimelineModel = TimelineModel(
lockUnlockEventModel = LockUnlockEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), null, node.lockable.activeLockReason?.rawValue()
)
)
protected fun getLock(node: Locked): TimelineModel = TimelineModel(
lockUnlockEventModel = LockUnlockEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.lockReason?.rawValue(), node.lockable.activeLockReason?.rawValue(), true
)
)
protected fun getReopened(node: Reopened): TimelineModel {
return TimelineModel(
closeOpenEventModel = CloseOpenEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser()
)
)
}
protected fun getClosed(node: Closed): TimelineModel {
val commit = node.closer?.fragments?.commitFragment?.toCommit()
val pr = node.closer?.fragments?.shortPullRequestRowItem?.toPullRequest()
return TimelineModel(
closeOpenEventModel = CloseOpenEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), commit, pr, true
)
)
}
protected fun getReference(node: Referenced): TimelineModel {
val issueModel = node.subject.fragments.shortIssueRowItem?.toIssue()
val pullRequest = node.subject.fragments.shortPullRequestRowItem?.toPullRequest()
return TimelineModel(
referencedEventModel = ReferencedEventModel(
node.commitRepository.nameWithOwner, node.createdAt, ShortUserModel(
node.actor?.fragments?.shortActor?.login, node.actor?.fragments?.shortActor?.login,
node.actor?.fragments?.shortActor?.url?.toString(),
avatarUrl = node.actor?.fragments?.shortActor?.avatarUrl?.toString()
), node.isCrossRepository, node.isDirectReference,
node.commit?.fragments?.commitFragment?.toCommit(), issueModel, pullRequest
)
)
}
protected fun getCrossReference(node: CrossReferenced): TimelineModel {
val actor = node.actor?.fragments?.shortActor?.toUser()
val issueModel = node.source.fragments.shortIssueRowItem?.toIssue()
val pullRequest = node.source.fragments.shortPullRequestRowItem?.toPullRequest()
return TimelineModel(
crossReferencedEventModel = CrossReferencedEventModel(
node.createdAt, node.referencedAt,
node.isCrossRepository, node.isWillCloseTarget, actor, issueModel, pullRequest
)
)
}
protected fun getComment(node: Comment) = TimelineModel(
comment = CommentModel(
node.id, node.databaseId,
ShortUserModel(node.author?.login, node.author?.login, node.author?.url?.toString(), avatarUrl = node.author?.avatarUrl.toString()),
node.bodyHTML.toString(), node.body, CommentAuthorAssociation.fromName(node.authorAssociation.rawValue()),
node.viewerCannotUpdateReasons.map { reason -> CommentCannotUpdateReason.fromName(reason.rawValue()) }.toList(),
node.reactionGroups?.map { it.fragments.reactions.toReactionGroup() }, node.createdAt, node.updatedAt,
node.isViewerCanReact, node.isViewerCanDelete, node.isViewerCanUpdate, node.isViewerDidAuthor, node.isViewerCanMinimize
)
)
}

View File

@ -31,8 +31,9 @@ class CreateIssueCommentUseCase @Inject constructor(
.observeOn(schedulerProvider.uiThread())
.flatMap { Rx2Apollo.from(apolloClient.query(GetLastIssueCommentQuery(login, repo, number))) }
.map {
val node = it.data()?.repositoryOwner?.repository?.issue?.timelineItems?.nodes?.firstOrNull()
val type = it.data()?.repositoryOwner?.repository?.issue?.timelineItems?.nodes?.firstOrNull()
as? GetLastIssueCommentQuery.AsIssueComment ?: return@map TimelineModel()
val node = type.fragments.comment ?: return@map TimelineModel()
return@map TimelineModel(
comment = CommentModel(
node.id,

View File

@ -11,6 +11,7 @@ import com.fastaccess.extension.*
import com.fastaccess.github.extensions.addIfNotNull
import github.GetIssueTimelineQuery
import github.GetIssueTimelineQuery.*
import github.fragment.*
import io.reactivex.Observable
import javax.inject.Inject
@ -20,7 +21,7 @@ import javax.inject.Inject
class GetIssueTimelineUseCase @Inject constructor(
private val apolloClient: ApolloClient,
private val schedulerProvider: SchedulerProvider
) : BaseObservableUseCase() {
) : BaseTimelineUseCase() {
var login: String? = null
var repo: String? = null
@ -40,236 +41,35 @@ class GetIssueTimelineUseCase @Inject constructor(
.subscribeOn(schedulerProvider.ioThread())
.observeOn(schedulerProvider.uiThread())
.map { it.data()?.repositoryOwner?.repository?.issue }
.map {
.map { issue ->
val list = arrayListOf<TimelineModel>()
val timeline = it.timelineItems
val timeline = issue.timelineItems
val pageInfo = PageInfoModel(
timeline.pageInfo.startCursor, timeline.pageInfo.endCursor,
timeline.pageInfo.isHasNextPage, timeline.pageInfo.isHasPreviousPage
)
timeline.nodes?.forEach { node ->
when (node) {
is AsIssueComment -> list.add(getComment(node))
is AsCrossReferencedEvent -> list.add(getCrossReference(node))
is AsClosedEvent -> list.add(getClosed(node))
is AsReopenedEvent -> list.add(getReopened(node))
is AsSubscribedEvent -> list.add(getSubscribed(node))
is AsUnsubscribedEvent -> list.add(getUnsubscribed(node))
is AsReferencedEvent -> list.add(getReference(node))
is AsAssignedEvent -> list.addIfNotNull(getAssigned(node, list))
is AsUnassignedEvent -> list.addIfNotNull(getUnassigned(node, list))
is AsLabeledEvent -> list.addIfNotNull(getLabel(node, list))
is AsUnlabeledEvent -> list.addIfNotNull(getUnlabeled(node, list))
is AsMilestonedEvent -> list.add(getMilestone(node))
is AsDemilestonedEvent -> list.add(getDemilestoned(node))
is AsRenamedTitleEvent -> list.add(getRenamed(node))
is AsLockedEvent -> list.add(getLock(node))
is AsUnlockedEvent -> list.add(getUnlocked(node))
is AsTransferredEvent -> list.add(getTransferred(node))
is AsIssueComment -> node.fragments.comment?.let { list.add(getComment(it)) }
is AsCrossReferencedEvent -> node.fragments.crossReferenced?.let { list.add(getCrossReference(it)) }
is AsClosedEvent -> node.fragments.closed?.let { list.add(getClosed(it)) }
is AsReopenedEvent -> node.fragments.reopened?.let { list.add(getReopened(it)) }
is AsSubscribedEvent -> node.fragments.subscribed?.let { list.add(getSubscribed(it)) }
is AsUnsubscribedEvent -> node.fragments.unsubscribed?.let { list.add(getUnsubscribed(it)) }
is AsReferencedEvent -> node.fragments.referenced?.let { list.add(getReference(it)) }
is AsAssignedEvent -> node.fragments.assigned?.let { list.addIfNotNull(getAssigned(it, list)) }
is AsUnassignedEvent -> node.fragments.unAssigned?.let { list.addIfNotNull(getUnassigned(it, list)) }
is AsLabeledEvent -> node.fragments.labeled?.let { list.addIfNotNull(getLabel(it, list)) }
is AsUnlabeledEvent -> node.fragments.unLabeled?.let { list.addIfNotNull(getUnlabeled(it, list)) }
is AsMilestonedEvent -> node.fragments.milestoned?.let { list.add(getMilestone(it)) }
is AsDemilestonedEvent -> node.fragments.demilestoned?.let { list.add(getDemilestoned(it)) }
is AsRenamedTitleEvent -> node.fragments.renamed?.let { list.add(getRenamed(it)) }
is AsLockedEvent -> node.fragments.locked?.let { list.add(getLock(it)) }
is AsUnlockedEvent -> node.fragments.unlocked?.let { list.add(getUnlocked(it)) }
is AsTransferredEvent -> node.fragments.transferred?.let { list.add(getTransferred(it)) }
}
}
return@map Pair(pageInfo, list)
}
}
private fun getTransferred(node: AsTransferredEvent): TimelineModel = TimelineModel(
transferredEventModel = TransferredEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.fromRepository?.nameWithOwner
)
)
private fun getRenamed(node: AsRenamedTitleEvent): TimelineModel = TimelineModel(
renamedEventModel = RenamedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.currentTitle, node.previousTitle
)
)
private fun getDemilestoned(node: AsDemilestonedEvent): TimelineModel = TimelineModel(
milestoneEventModel = MilestoneDemilestonedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.milestoneTitle, false
)
)
private fun getMilestone(node: AsMilestonedEvent): TimelineModel = TimelineModel(
milestoneEventModel = MilestoneDemilestonedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.milestoneTitle, true
)
)
private fun getUnassigned(
node: AsUnassignedEvent,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.assignedEventModel != null }.map {
if (it.assignedEventModel?.createdAt?.time == node.createdAt.time) {
it.assignedEventModel?.users?.add(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
assignedEventModel = AssignedUnAssignedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false,
arrayListOf(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
)
)
}
return null
}
private fun getAssigned(
node: AsAssignedEvent,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.assignedEventModel != null }.map {
if (it.assignedEventModel?.createdAt?.time == node.createdAt.time) {
it.assignedEventModel?.users?.add(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
assignedEventModel = AssignedUnAssignedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), true,
arrayListOf(ShortUserModel(node.user?.login, node.user?.login, avatarUrl = node.user?.avatarUrl?.toString()))
)
)
}
return null
}
private fun getUnsubscribed(
node: AsUnsubscribedEvent
): TimelineModel = TimelineModel(
subscribedUnsubscribedEvent = SubscribedUnsubscribedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false
)
)
private fun getSubscribed(node: AsSubscribedEvent): TimelineModel = TimelineModel(
subscribedUnsubscribedEvent = SubscribedUnsubscribedEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false
)
)
private fun getUnlabeled(
node: AsUnlabeledEvent,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.labelUnlabeledEvent != null }.map {
if (it.labelUnlabeledEvent?.createdAt?.time == node.createdAt.time) {
it.labelUnlabeledEvent?.labels?.add(constructLabel(node.label))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
labelUnlabeledEvent = LabelUnlabeledEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), false, arrayListOf(constructLabel(node.label))
)
)
}
return null
}
private fun getLabel(
node: AsLabeledEvent,
list: ArrayList<TimelineModel>
): TimelineModel? {
var shouldAdd = true
list.filter { it.labelUnlabeledEvent != null }.map {
if (it.labelUnlabeledEvent?.createdAt?.time == node.createdAt.time) {
it.labelUnlabeledEvent?.labels?.add(constructLabel(node.label))
shouldAdd = false
}
}
if (shouldAdd) {
return TimelineModel(
labelUnlabeledEvent = LabelUnlabeledEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), true, arrayListOf(constructLabel(node.label))
)
)
}
return null
}
private fun constructLabel(m: Any): LabelModel {
return when (m) {
is Label -> LabelModel(m.name, m.color)
is Label1 -> LabelModel(m.name, m.color)
else -> throw IllegalArgumentException("$m is not instance of any Label")
}
}
private fun getUnlocked(node: AsUnlockedEvent): TimelineModel = TimelineModel(
lockUnlockEventModel = LockUnlockEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), null, node.lockable.activeLockReason?.rawValue()
)
)
private fun getLock(node: AsLockedEvent): TimelineModel = TimelineModel(
lockUnlockEventModel = LockUnlockEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), node.lockReason?.rawValue(), node.lockable.activeLockReason?.rawValue(), true
)
)
private fun getReopened(node: AsReopenedEvent): TimelineModel {
return TimelineModel(
closeOpenEventModel = CloseOpenEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser()
)
)
}
private fun getClosed(node: AsClosedEvent): TimelineModel {
val commit = node.closer?.fragments?.commitFragment?.toCommit()
val pr = node.closer?.fragments?.shortPullRequestRowItem?.toPullRequest()
return TimelineModel(
closeOpenEventModel = CloseOpenEventModel(
node.createdAt, node.actor?.fragments?.shortActor?.toUser(), commit, pr, true
)
)
}
private fun getReference(node: AsReferencedEvent): TimelineModel {
val issueModel = node.subject.fragments.shortIssueRowItem?.toIssue()
val pullRequest = node.subject.fragments.shortPullRequestRowItem?.toPullRequest()
return TimelineModel(
referencedEventModel = ReferencedEventModel(
node.commitRepository.nameWithOwner, node.createdAt, ShortUserModel(
node.actor?.fragments?.shortActor?.login, node.actor?.fragments?.shortActor?.login,
node.actor?.fragments?.shortActor?.url?.toString(),
avatarUrl = node.actor?.fragments?.shortActor?.avatarUrl?.toString()
), node.isCrossRepository, node.isDirectReference,
node.commit?.fragments?.commitFragment?.toCommit(), issueModel, pullRequest
)
)
}
private fun getCrossReference(node: AsCrossReferencedEvent): TimelineModel {
val actor = node.actor?.fragments?.shortActor?.toUser()
val issueModel = node.source.fragments.shortIssueRowItem?.toIssue()
val pullRequest = node.source.fragments.shortPullRequestRowItem?.toPullRequest()
return TimelineModel(
crossReferencedEventModel = CrossReferencedEventModel(
node.createdAt, node.referencedAt,
node.isCrossRepository, node.isWillCloseTarget, actor, issueModel, pullRequest
)
)
}
private fun getComment(node: AsIssueComment) = TimelineModel(
comment = CommentModel(
node.id, node.databaseId,
ShortUserModel(node.author?.login, node.author?.login, node.author?.url?.toString(), avatarUrl = node.author?.avatarUrl.toString()),
node.bodyHTML.toString(), node.body, CommentAuthorAssociation.fromName(node.authorAssociation.rawValue()),
node.viewerCannotUpdateReasons.map { reason -> CommentCannotUpdateReason.fromName(reason.rawValue()) }.toList(),
node.reactionGroups?.map { it.fragments.reactions.toReactionGroup() }, node.createdAt, node.updatedAt,
node.isViewerCanReact, node.isViewerCanDelete, node.isViewerCanUpdate, node.isViewerDidAuthor, node.isViewerCanMinimize
)
)
}

View File

@ -60,7 +60,8 @@ class GetPullRequestUseCase @Inject constructor(
issue.isViewerCanReact, issue.isViewerCanSubscribe, issue.isViewerCanUpdate, issue.isViewerDidAuthor,
issue.mergeable.rawValue(), issue.isMerged, issue.mergedAt,
issue.authorAssociation.rawValue(), issue.url.toString(), issue.labels?.nodes?.map { it.fragments.labels.toLabels() },
issue.milestone?.toMilestone(), issue.assignees.nodes?.map { it.fragments }?.map { it.shortUserRowItem.toUser() })
issue.milestone?.toMilestone(), issue.assignees.nodes?.map { it.fragments }?.map { it.shortUserRowItem.toUser() },
issue.headRefName, issue.baseRefName)
)
}
}

View File

@ -83,6 +83,10 @@ fragment CommitFragment on Commit {
authoredDate
committedViaWeb
id
oid
status {
state
}
}
fragment FullIssue on Issue {
@ -165,40 +169,42 @@ fragment FullPullRequest on PullRequest {
mergeable
merged
mergedAt
headRefName
baseRefName
mergedBy {
avatarUrl
login
url
avatarUrl
login
url
}
url
userContentEdits(first: 0) {
totalCount
totalCount
}
author {
avatarUrl
login
url
avatarUrl
login
url
}
reactionGroups {
...Reactions
...Reactions
}
createdViaEmail
repository {
nameWithOwner
nameWithOwner
}
authorAssociation
labels(first: 30) {
nodes {
...Labels
}
nodes {
...Labels
}
}
assignees(first: 30) {
nodes {
...ShortUserRowItem
}
nodes {
...ShortUserRowItem
}
}
milestone {
...MilestoneFragment
...MilestoneFragment
}
}
@ -230,4 +236,167 @@ fragment MilestoneFragment on Milestone {
url
title
state
}
fragment Comment on IssueComment {
author {
login
avatarUrl
url
}
createdAt
authorAssociation
bodyHTML
body
id
databaseId
updatedAt
viewerCanReact
viewerCanDelete
viewerCanUpdate
viewerDidAuthor
viewerCanMinimize
viewerCannotUpdateReasons
reactionGroups {
... Reactions
}
}
fragment CrossReferenced on CrossReferencedEvent {
createdAt
isCrossRepository
referencedAt
source {
... ShortPullRequestRowItem
... ShortIssueRowItem
}
willCloseTarget
actor { ... ShortActor }
}
fragment Closed on ClosedEvent {
actor { ... ShortActor }
createdAt
closer {
... CommitFragment
... ShortPullRequestRowItem
}
}
fragment Reopened on ReopenedEvent {
actor { ... ShortActor }
createdAt
}
fragment Subscribed on SubscribedEvent {
actor { ... ShortActor }
createdAt
}
fragment Unsubscribed on UnsubscribedEvent {
actor { ... ShortActor }
createdAt
}
fragment Referenced on ReferencedEvent {
actor { ... ShortActor }
createdAt
commitRepository {
nameWithOwner
}
isCrossRepository
isDirectReference
commit {
... CommitFragment
}
subject {
... ShortPullRequestRowItem
... ShortIssueRowItem
}
}
fragment Assigned on AssignedEvent {
actor { ... ShortActor }
createdAt
user {
login
avatarUrl
}
}
fragment UnAssigned on UnassignedEvent {
actor { ... ShortActor }
createdAt
user {
login
avatarUrl
}
}
fragment Labeled on LabeledEvent {
actor { ... ShortActor }
createdAt
label {
color
name
isDefault
}
}
fragment UnLabeled on UnlabeledEvent {
actor { ... ShortActor }
createdAt
label {
... Labels
}
}
fragment Milestoned on MilestonedEvent {
actor { ... ShortActor }
createdAt
milestoneTitle
}
fragment Demilestoned on DemilestonedEvent {
actor { ... ShortActor }
createdAt
milestoneTitle
}
fragment Renamed on RenamedTitleEvent {
actor { ... ShortActor }
createdAt
currentTitle
previousTitle
}
fragment Locked on LockedEvent {
actor { ... ShortActor }
createdAt
lockReason
lockable {
activeLockReason
}
}
fragment Unlocked on UnlockedEvent {
actor { ... ShortActor }
createdAt
lockable {
activeLockReason
}
}
fragment Transferred on TransferredEvent {
actor { ... ShortActor }
createdAt
fromRepository {
id
nameWithOwner
url
}
issue {
number
url
}
}

View File

@ -55,26 +55,7 @@ query getLastIssueComment($login: String!, $repo: String!, $number: Int!) {
timelineItems(last: 1, itemTypes: [ISSUE_COMMENT]) {
nodes {
... on IssueComment {
author {
login
avatarUrl
}
createdAt
authorAssociation
bodyHTML
body
id
databaseId
updatedAt
viewerCanReact
viewerCanDelete
viewerCanUpdate
viewerDidAuthor
viewerCanMinimize
viewerCannotUpdateReasons
reactionGroups {
... Reactions
}
... Comment
}
}
}
@ -90,26 +71,7 @@ query getLastPrComment($login: String!, $repo: String!, $number: Int!) {
timelineItems(last: 1, itemTypes: [ISSUE_COMMENT]) {
nodes {
... on IssueComment {
author {
login
avatarUrl
}
createdAt
authorAssociation
bodyHTML
body
id
databaseId
updatedAt
viewerCanReact
viewerCanDelete
viewerCanUpdate
viewerDidAuthor
viewerCanMinimize
viewerCannotUpdateReasons
reactionGroups {
... Reactions
}
... Comment
}
}
}
@ -133,152 +95,55 @@ query getIssueTimeline($login: String!, $repo: String!, $number: Int!, $page: St
nodes {
__typename
... on IssueComment {
author {
login
avatarUrl
url
}
createdAt
authorAssociation
bodyHTML
body
id
databaseId
updatedAt
viewerCanReact
viewerCanDelete
viewerCanUpdate
viewerDidAuthor
viewerCanMinimize
viewerCannotUpdateReasons
reactionGroups {
... Reactions
}
... Comment
}
... on CrossReferencedEvent {
createdAt
isCrossRepository
referencedAt
source {
... ShortPullRequestRowItem
... ShortIssueRowItem
}
willCloseTarget
actor { ... ShortActor }
... CrossReferenced
}
... on ClosedEvent {
actor { ... ShortActor }
createdAt
closer {
... CommitFragment
... ShortPullRequestRowItem
}
... Closed
}
... on ReopenedEvent {
actor { ... ShortActor }
createdAt
... Reopened
}
... on SubscribedEvent {
actor { ... ShortActor }
createdAt
... Subscribed
}
... on UnsubscribedEvent {
actor { ... ShortActor }
createdAt
... Unsubscribed
}
... on ReferencedEvent {
actor { ... ShortActor }
createdAt
commitRepository {
nameWithOwner
}
isCrossRepository
isDirectReference
commit {
... CommitFragment
}
subject {
... ShortPullRequestRowItem
... ShortIssueRowItem
}
... Referenced
}
... on AssignedEvent {
actor { ... ShortActor }
createdAt
user {
login
avatarUrl
}
... Assigned
}
... on UnassignedEvent {
actor { ... ShortActor }
createdAt
user {
login
avatarUrl
}
... UnAssigned
}
... on LabeledEvent {
actor { ... ShortActor }
createdAt
label {
color
name
isDefault
}
... Labeled
}
... on UnlabeledEvent {
actor { ... ShortActor }
createdAt
label {
color
name
isDefault
}
... UnLabeled
}
... on MilestonedEvent {
actor { ... ShortActor }
createdAt
milestoneTitle
... Milestoned
}
... on DemilestonedEvent {
actor { ... ShortActor }
createdAt
milestoneTitle
... Demilestoned
}
... on RenamedTitleEvent {
actor { ... ShortActor }
createdAt
currentTitle
previousTitle
... Renamed
}
... on LockedEvent {
actor { ... ShortActor }
createdAt
lockReason
lockable {
activeLockReason
}
... Locked
}
... on UnlockedEvent {
actor { ... ShortActor }
createdAt
lockable {
activeLockReason
}
... Unlocked
}
... on TransferredEvent {
actor { ... ShortActor }
createdAt
fromRepository {
id
nameWithOwner
url
}
issue {
number
url
}
... Transferred
}
}
}

View File

@ -3,6 +3,7 @@ package com.fastaccess.data.model
import com.fastaccess.data.model.parcelable.LabelModel
import com.fastaccess.data.persistence.models.IssueModel
import com.fastaccess.data.persistence.models.MyIssuesPullsModel
import com.fastaccess.data.persistence.models.PullRequestModel
import com.google.gson.annotations.SerializedName
import java.util.*
@ -22,7 +23,8 @@ data class TimelineModel(
@SerializedName("assignedUnassignedEvent") val assignedEventModel: AssignedUnAssignedEventModel? = null,
@SerializedName("milestoneDemilestoneEvent") val milestoneEventModel: MilestoneDemilestonedEventModel? = null,
@SerializedName("renamedEvent") val renamedEventModel: RenamedEventModel? = null,
@SerializedName("transferredEvent") val transferredEventModel: TransferredEventModel? = null
@SerializedName("transferredEvent") val transferredEventModel: TransferredEventModel? = null,
@SerializedName("pullRequest") val pullRequest: PullRequestModel? = null
)
data class CommitModel(

View File

@ -10,7 +10,7 @@ import com.fastaccess.data.persistence.models.*
* Created by Kosh on 11.05.18.
*/
const val VERSION = 29
const val VERSION = 30
const val DATABASE_NAME = "FastHub-Room-DB"
@Database(

View File

@ -50,7 +50,9 @@ data class PullRequestModel(
@SerializedName("url") var url: String? = null,
@SerializedName("labels") var labels: List<LabelModel>? = null,
@SerializedName("milestone") @Embedded(prefix = "milestone_") var milestone: MilestoneModel? = null,
@SerializedName("assignees") var assignees: List<ShortUserModel>? = null
@SerializedName("assignees") var assignees: List<ShortUserModel>? = null,
@SerializedName("headRefName") var headRefName: String? = null,
@SerializedName("baseRefName") var baseRefName: String? = null
) {
companion object {
const val TABLE_NAME = "pullrequest_table"

View File

@ -6,7 +6,6 @@ import com.fastaccess.data.persistence.dao.PullRequestDao
import com.fastaccess.data.persistence.models.PullRequestModel
import io.reactivex.Maybe
import javax.inject.Inject
import javax.inject.Singleton
/**
* Created by Kosh on 27.01.19.
@ -15,7 +14,7 @@ class PullRequestRepositoryProvider @Inject constructor(
private val dao: PullRequestDao
) : PullRequestRepository {
override fun upsert(pr: PullRequestModel) = dao.update(pr)
override fun upsert(pr: PullRequestModel) = dao.upsert(pr)
override fun getPullRequests(
repo: String,
state: String