Commit 182783e0 authored by Konstantin Tskhovrebov's avatar Konstantin Tskhovrebov 🤖

Add project activity screen.

parent e849afc0
......@@ -29,7 +29,9 @@ import ru.terrakok.gitlabclient.ui.my.todos.MyTodosFragment
import ru.terrakok.gitlabclient.ui.privacypolicy.PrivacyPolicyFragment
import ru.terrakok.gitlabclient.ui.project.ProjectFlowFragment
import ru.terrakok.gitlabclient.ui.project.ProjectFragment
import ru.terrakok.gitlabclient.ui.project.ProjectInfoFragment
import ru.terrakok.gitlabclient.ui.project.info.ProjectEventsFragment
import ru.terrakok.gitlabclient.ui.project.info.ProjectInfoContainerFragment
import ru.terrakok.gitlabclient.ui.project.info.ProjectInfoFragment
import ru.terrakok.gitlabclient.ui.project.issues.ProjectIssuesContainerFragment
import ru.terrakok.gitlabclient.ui.project.issues.ProjectIssuesFragment
import ru.terrakok.gitlabclient.ui.project.mergerequest.ProjectMergeRequestsContainerFragment
......@@ -69,7 +71,9 @@ object Screens {
const val PROJECT_FLOW = "project flow"
const val PROJECT_MAIN_FLOW = "project main flow"
const val PROJECT_INFO_CONTAINER_SCREEN = "project info container screen"
const val PROJECT_INFO_SCREEN = "project info screen"
const val PROJECT_EVENTS_SCREEN = "project events screen"
const val PROJECT_ISSUES_CONTAINER_SCREEN = "project issues container screen"
const val PROJECT_ISSUES_SCREEN = "project issues screen"
const val PROJECT_MR_CONTAINER_SCREEN = "project mr container screen"
......@@ -143,9 +147,14 @@ object Screens {
Screens.PROJECT_FLOW -> ProjectFlowFragment.create(data as Long)
Screens.PROJECT_MAIN_FLOW -> ProjectFragment()
Screens.PROJECT_INFO_CONTAINER_SCREEN -> ProjectInfoContainerFragment()
Screens.PROJECT_INFO_SCREEN -> ProjectInfoFragment()
Screens.PROJECT_EVENTS_SCREEN -> ProjectEventsFragment()
Screens.PROJECT_ISSUES_CONTAINER_SCREEN -> ProjectIssuesContainerFragment()
Screens.PROJECT_ISSUES_SCREEN -> ProjectIssuesFragment.create(data as IssueState)
Screens.PROJECT_MR_CONTAINER_SCREEN -> ProjectMergeRequestsContainerFragment()
Screens.PROJECT_MR_SCREEN -> ProjectMergeRequestsFragment.create(data as MergeRequestState)
......
package ru.terrakok.gitlabclient.presentation.project.events
import com.arellomobile.mvp.InjectViewState
import ru.terrakok.gitlabclient.Screens
import ru.terrakok.gitlabclient.entity.app.target.TargetHeader
import ru.terrakok.gitlabclient.extension.openInfo
import ru.terrakok.gitlabclient.model.interactor.event.EventInteractor
import ru.terrakok.gitlabclient.model.system.flow.FlowRouter
import ru.terrakok.gitlabclient.presentation.global.BasePresenter
import ru.terrakok.gitlabclient.presentation.global.ErrorHandler
import ru.terrakok.gitlabclient.presentation.global.MarkDownConverter
import ru.terrakok.gitlabclient.presentation.global.Paginator
import ru.terrakok.gitlabclient.toothpick.PrimitiveWrapper
import ru.terrakok.gitlabclient.toothpick.qualifier.ProjectId
import javax.inject.Inject
/**
* @author Konstantin Tskhovrebov (aka terrakok) on 15.06.17.
*/
@InjectViewState
class ProjectEventsPresenter @Inject constructor(
@ProjectId private val projectIdWrapper: PrimitiveWrapper<Long>,
private val eventInteractor: EventInteractor,
private val mdConverter: MarkDownConverter,
private val errorHandler: ErrorHandler,
private val router: FlowRouter
) : BasePresenter<ProjectEventsView>() {
private val projectId = projectIdWrapper.value
override fun onFirstViewAttach() {
super.onFirstViewAttach()
refreshEvents()
}
private val paginator = Paginator(
{
eventInteractor.getProjectEvents(projectId, it)
.flattenAsObservable { it }
.concatMap { item ->
mdConverter.markdownToSpannable(item.body.toString())
.map { md -> item.copy(body = md) }
.toObservable()
}
.toList()
},
object : Paginator.ViewController<TargetHeader> {
override fun showEmptyProgress(show: Boolean) {
viewState.showEmptyProgress(show)
}
override fun showEmptyError(show: Boolean, error: Throwable?) {
if (error != null) {
errorHandler.proceed(error, { viewState.showEmptyError(show, it) })
} else {
viewState.showEmptyError(show, null)
}
}
override fun showErrorMessage(error: Throwable) {
errorHandler.proceed(error, { viewState.showMessage(it) })
}
override fun showEmptyView(show: Boolean) {
viewState.showEmptyView(show)
}
override fun showData(show: Boolean, data: List<TargetHeader>) {
viewState.showEvents(show, data)
}
override fun showRefreshProgress(show: Boolean) {
viewState.showRefreshProgress(show)
}
override fun showPageProgress(show: Boolean) {
viewState.showPageProgress(show)
}
}
)
fun onItemClick(item: TargetHeader) = item.openInfo(router)
fun onUserClick(userId: Long) = router.startFlow(Screens.USER_FLOW, userId)
fun refreshEvents() = paginator.refresh()
fun loadNextEventsPage() = paginator.loadNewPage()
fun onBackPressed() = router.exit()
override fun onDestroy() {
super.onDestroy()
paginator.release()
}
}
\ No newline at end of file
package ru.terrakok.gitlabclient.presentation.project.events
import com.arellomobile.mvp.MvpView
import com.arellomobile.mvp.viewstate.strategy.AddToEndSingleStrategy
import com.arellomobile.mvp.viewstate.strategy.OneExecutionStateStrategy
import com.arellomobile.mvp.viewstate.strategy.StateStrategyType
import ru.terrakok.gitlabclient.entity.app.target.TargetHeader
/**
* @author Konstantin Tskhovrebov (aka terrakok) on 15.06.17.
*/
@StateStrategyType(AddToEndSingleStrategy::class)
interface ProjectEventsView : MvpView {
fun showRefreshProgress(show: Boolean)
fun showEmptyProgress(show: Boolean)
fun showPageProgress(show: Boolean)
fun showEmptyView(show: Boolean)
fun showEmptyError(show: Boolean, message: String?)
fun showEvents(show: Boolean, events: List<TargetHeader>)
@StateStrategyType(OneExecutionStateStrategy::class)
fun showMessage(message: String)
}
\ No newline at end of file
......@@ -12,6 +12,7 @@ import ru.terrakok.gitlabclient.extension.shareText
import ru.terrakok.gitlabclient.model.system.flow.FlowRouter
import ru.terrakok.gitlabclient.toothpick.DI
import ru.terrakok.gitlabclient.ui.global.BaseFragment
import ru.terrakok.gitlabclient.ui.project.info.ProjectInfoFragment
import toothpick.Toothpick
import javax.inject.Inject
......@@ -57,7 +58,7 @@ class ProjectFragment : BaseFragment(), ProjectInfoFragment.ProjectInfoToolbar {
setOnTabSelectedListener { position, wasSelected ->
if (!wasSelected) selectTab(
when (position) {
0 -> Screens.PROJECT_INFO_SCREEN
0 -> Screens.PROJECT_INFO_CONTAINER_SCREEN
1 -> Screens.PROJECT_ISSUES_CONTAINER_SCREEN
else -> Screens.PROJECT_MR_CONTAINER_SCREEN
}
......@@ -66,7 +67,7 @@ class ProjectFragment : BaseFragment(), ProjectInfoFragment.ProjectInfoToolbar {
}
}
selectTab(currentTabFragment?.tag ?: Screens.PROJECT_INFO_SCREEN)
selectTab(currentTabFragment?.tag ?: Screens.PROJECT_INFO_CONTAINER_SCREEN)
}
private fun selectTab(tab: String) {
......
package ru.terrakok.gitlabclient.ui.project.info
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import com.arellomobile.mvp.presenter.InjectPresenter
import com.arellomobile.mvp.presenter.ProvidePresenter
import kotlinx.android.synthetic.main.layout_base_list.*
import kotlinx.android.synthetic.main.layout_zero.*
import ru.terrakok.gitlabclient.R
import ru.terrakok.gitlabclient.entity.app.target.TargetHeader
import ru.terrakok.gitlabclient.extension.showSnackMessage
import ru.terrakok.gitlabclient.extension.visible
import ru.terrakok.gitlabclient.presentation.project.events.ProjectEventsPresenter
import ru.terrakok.gitlabclient.presentation.project.events.ProjectEventsView
import ru.terrakok.gitlabclient.toothpick.DI
import ru.terrakok.gitlabclient.ui.global.BaseFragment
import ru.terrakok.gitlabclient.ui.global.ZeroViewHolder
import ru.terrakok.gitlabclient.ui.my.TargetsAdapter
import toothpick.Toothpick
/**
* @author Konstantin Tskhovrebov (aka terrakok). Date: 13.06.17
*/
class ProjectEventsFragment : BaseFragment(), ProjectEventsView {
override val layoutRes = R.layout.fragment_project_events
@InjectPresenter
lateinit var presenter: ProjectEventsPresenter
private val adapter: TargetsAdapter by lazy {
TargetsAdapter(
{ presenter.onUserClick(it) },
{ presenter.onItemClick(it) },
{ presenter.loadNextEventsPage() }
)
}
private var zeroViewHolder: ZeroViewHolder? = null
@ProvidePresenter
fun providePresenter(): ProjectEventsPresenter =
Toothpick
.openScope(DI.PROJECT_FLOW_SCOPE)
.getInstance(ProjectEventsPresenter::class.java)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
recyclerView.apply {
layoutManager = LinearLayoutManager(context)
setHasFixedSize(true)
adapter = this@ProjectEventsFragment.adapter
}
swipeToRefresh.setOnRefreshListener { presenter.refreshEvents() }
zeroViewHolder = ZeroViewHolder(zeroLayout, { presenter.refreshEvents() })
}
override fun showRefreshProgress(show: Boolean) {
postViewAction { swipeToRefresh.isRefreshing = show }
}
override fun showEmptyProgress(show: Boolean) {
fullscreenProgressView.visible(show)
//trick for disable and hide swipeToRefresh on fullscreen progress
swipeToRefresh.visible(!show)
postViewAction { swipeToRefresh.isRefreshing = false }
}
override fun showPageProgress(show: Boolean) {
postViewAction { adapter.showProgress(show) }
}
override fun showEmptyView(show: Boolean) {
if (show) zeroViewHolder?.showEmptyData()
else zeroViewHolder?.hide()
}
override fun showEmptyError(show: Boolean, message: String?) {
if (show) zeroViewHolder?.showEmptyError(message)
else zeroViewHolder?.hide()
}
override fun showEvents(show: Boolean, events: List<TargetHeader>) {
recyclerView.visible(show)
postViewAction { adapter.setData(events) }
}
override fun showMessage(message: String) {
showSnackMessage(message)
}
override fun onBackPressed() {
presenter.onBackPressed()
}
}
\ No newline at end of file
package ru.terrakok.gitlabclient.ui.project.info
import android.os.Bundle
import android.support.v4.app.FragmentPagerAdapter
import kotlinx.android.synthetic.main.fragment_project_info_container.*
import ru.terrakok.gitlabclient.R
import ru.terrakok.gitlabclient.Screens
import ru.terrakok.gitlabclient.model.system.flow.FlowRouter
import ru.terrakok.gitlabclient.toothpick.DI
import ru.terrakok.gitlabclient.ui.global.BaseFragment
import toothpick.Toothpick
import javax.inject.Inject
class ProjectInfoContainerFragment : BaseFragment(), ProjectInfoFragment.ProjectInfoToolbar {
@Inject
lateinit var router: FlowRouter
override val layoutRes = R.layout.fragment_project_info_container
private val adapter: ProjectInfoPagesAdapter by lazy { ProjectInfoPagesAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
Toothpick.inject(this, Toothpick.openScope(DI.PROJECT_FLOW_SCOPE))
super.onCreate(savedInstanceState)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewPager.adapter = adapter
}
override fun onBackPressed() {
router.exit()
}
override fun setTitle(title: String) {
(parentFragment as? ProjectInfoFragment.ProjectInfoToolbar)?.setTitle(title)
}
override fun setShareUrl(url: String?) {
(parentFragment as? ProjectInfoFragment.ProjectInfoToolbar)?.setShareUrl(url)
}
private inner class ProjectInfoPagesAdapter : FragmentPagerAdapter(childFragmentManager) {
override fun getItem(position: Int) = when (position) {
0 -> Screens.createFragment(Screens.PROJECT_INFO_SCREEN)
1 -> Screens.createFragment(Screens.PROJECT_EVENTS_SCREEN)
else -> null
}
override fun getCount() = 2
override fun getPageTitle(position: Int) = when (position) {
0 -> getString(R.string.project_info)
1 -> getString(R.string.project_events)
else -> null
}
}
}
\ No newline at end of file
package ru.terrakok.gitlabclient.ui.project
package ru.terrakok.gitlabclient.ui.project.info
import android.os.Bundle
import android.view.View
......
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/layout_base_list" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
style="@style/ToolbarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.view.ViewPager>
</LinearLayout>
......@@ -153,6 +153,8 @@
<string name="menu_project_info">Info</string>
<string name="menu_project_issue">Issues</string>
<string name="menu_project_merge_request">Merge Requests</string>
<string name="project_info">Info</string>
<string name="project_events">Activity</string>
<!--Privacy policy screen-->
<string name="privacy_policy">Privacy policy</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment