Commit ce19810c authored by Konstantin Tskhovrebov's avatar Konstantin Tskhovrebov 🤖

Merge branch 'feature/project_file_details' into 'feature/project_file_code_highlight'

Implement project file details

See merge request terrakok/gitlab-client!129
parents 271c381b 6dec10ee
......@@ -126,8 +126,8 @@ dependencies {
implementation("com.squareup.okhttp3:logging-interceptor:3.11.0")
implementation("com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion")
//RxJava
implementation("io.reactivex.rxjava2:rxandroid:2.1.0")
implementation("io.reactivex.rxjava2:rxjava:2.2.3")
implementation("io.reactivex.rxjava2:rxandroid:2.1.1")
implementation("io.reactivex.rxjava2:rxjava:2.2.6")
implementation("com.jakewharton.rxrelay2:rxrelay:2.1.0")
//Adapter simplify
implementation("com.hannesdorfmann:adapterdelegates3:3.1.0")
......@@ -147,9 +147,9 @@ dependencies {
//FlexBox Layout
implementation("com.google.android:flexbox:1.0.0")
//Firebase
implementation("com.google.firebase:firebase-core:16.0.6")
implementation("com.google.firebase:firebase-core:16.0.9")
//Crashlytics
implementation("com.crashlytics.sdk.android:crashlytics:2.9.8")
implementation("com.crashlytics.sdk.android:crashlytics:2.10.0")
//JUnit
testImplementation("junit:junit:4.12")
......
......@@ -11,6 +11,7 @@ import ru.terrakok.gitlabclient.ui.about.AboutFragment
import ru.terrakok.gitlabclient.ui.auth.AuthFlowFragment
import ru.terrakok.gitlabclient.ui.auth.AuthFragment
import ru.terrakok.gitlabclient.ui.drawer.DrawerFlowFragment
import ru.terrakok.gitlabclient.ui.file.ProjectFileFragment
import ru.terrakok.gitlabclient.ui.global.StubFragment
import ru.terrakok.gitlabclient.ui.issue.IssueFlowFragment
import ru.terrakok.gitlabclient.ui.issue.IssueFragment
......@@ -239,6 +240,14 @@ object Screens {
override fun getFragment() = PrivacyPolicyFragment()
}
data class ProjectFile(
val projectId: Long,
val filePath: String,
val branchName: String
) : SupportAppScreen() {
override fun getFragment() = ProjectFileFragment.create(projectId, filePath, branchName)
}
data class ExternalBrowserFlow(
val url: String
) : SupportAppScreen() {
......
......@@ -11,8 +11,8 @@ data class MergeRequest(
@SerializedName("iid") val iid: Long,
@SerializedName("created_at") val createdAt: LocalDateTime,
@SerializedName("updated_at") val updatedAt: LocalDateTime?,
@SerializedName("target_branch") val targetBranch: String?,
@SerializedName("source_branch") val sourceBranch: String?,
@SerializedName("target_branch") val targetBranch: String,
@SerializedName("source_branch") val sourceBranch: String,
@SerializedName("project_id") val projectId: Long,
@SerializedName("title") val title: String?,
@SerializedName("state") val state: MergeRequestState,
......
package ru.terrakok.gitlabclient.presentation.file
import com.arellomobile.mvp.InjectViewState
import ru.terrakok.cicerone.Router
import ru.terrakok.gitlabclient.model.interactor.project.ProjectInteractor
import ru.terrakok.gitlabclient.presentation.global.BasePresenter
import ru.terrakok.gitlabclient.presentation.global.ErrorHandler
import ru.terrakok.gitlabclient.toothpick.PrimitiveWrapper
import ru.terrakok.gitlabclient.toothpick.qualifier.BranchName
import ru.terrakok.gitlabclient.toothpick.qualifier.FilePath
import ru.terrakok.gitlabclient.toothpick.qualifier.ProjectId
import javax.inject.Inject
/**
* Created by Eugene Shapovalov (@CraggyHaggy) on 22.11.18.
*/
@InjectViewState
class ProjectFilePresenter @Inject constructor(
@ProjectId projectIdWrapper: PrimitiveWrapper<Long>,
@FilePath filePath: String,
@BranchName branchName: String,
private val projectInteractor: ProjectInteractor,
private val errorHandler: ErrorHandler,
private val router: Router
) : BasePresenter<ProjectFileView>() {
private val projectId = projectIdWrapper.value
fun onBackPressed() = router.exit()
}
\ No newline at end of file
package ru.terrakok.gitlabclient.presentation.file
import com.arellomobile.mvp.MvpView
import com.arellomobile.mvp.viewstate.strategy.AddToEndSingleStrategy
import com.arellomobile.mvp.viewstate.strategy.StateStrategyType
/**
* Created by Eugene Shapovalov (@CraggyHaggy) on 22.11.18.
*/
@StateStrategyType(AddToEndSingleStrategy::class)
interface ProjectFileView : MvpView
\ No newline at end of file
package ru.terrakok.gitlabclient.presentation.mergerequest.changes
import com.arellomobile.mvp.InjectViewState
import ru.terrakok.gitlabclient.Screens
import ru.terrakok.gitlabclient.entity.mergerequest.MergeRequestChange
import ru.terrakok.gitlabclient.model.interactor.mergerequest.MergeRequestInteractor
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.toothpick.PrimitiveWrapper
......@@ -18,7 +20,8 @@ class MergeRequestChangesPresenter @Inject constructor(
@ProjectId projectIdWrapper: PrimitiveWrapper<Long>,
@MergeRequestId mrIdWrapper: PrimitiveWrapper<Long>,
private val mrInteractor: MergeRequestInteractor,
private val errorHandler: ErrorHandler
private val errorHandler: ErrorHandler,
private val flowRouter: FlowRouter
) : BasePresenter<MergeRequestChangesView>() {
private val projectId = projectIdWrapper.value
......@@ -106,4 +109,15 @@ class MergeRequestChangesPresenter @Inject constructor(
)
.connect()
}
fun onMergeRequestChangeClick(item: MergeRequestChange) {
mrInteractor.getMergeRequest(projectId, mrId)
.doOnSubscribe { viewState.showFullscreenProgress(true) }
.doAfterTerminate { viewState.showFullscreenProgress(false) }
.subscribe(
{ flowRouter.startFlow(Screens.ProjectFile(projectId, item.newPath, it.sourceBranch)) },
{ errorHandler.proceed(it, { viewState.showMessage(it) }) }
)
.connect()
}
}
\ No newline at end of file
......@@ -20,4 +20,6 @@ interface MergeRequestChangesView : MvpView {
@StateStrategyType(OneExecutionStateStrategy::class)
fun showMessage(message: String)
fun showFullscreenProgress(show: Boolean)
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import com.arellomobile.mvp.InjectViewState
import io.reactivex.Single
import io.reactivex.functions.BiFunction
import ru.terrakok.gitlabclient.R
import ru.terrakok.gitlabclient.Screens
import ru.terrakok.gitlabclient.entity.Branch
import ru.terrakok.gitlabclient.entity.Project
import ru.terrakok.gitlabclient.entity.RepositoryTreeNodeType
......@@ -208,7 +209,13 @@ class ProjectFilesPresenter @Inject constructor(
if (item.nodeType == RepositoryTreeNodeType.TREE) {
projectFileDestination.moveForward(item.name)
} else {
// TODO: file details (Navigate to file details flow).
router.startFlow(
Screens.ProjectFile(
projectId,
getFilePath(projectFileDestination.isInRoot(), projectFileDestination.paths, item.name),
projectFileDestination.branchName
)
)
}
}
......@@ -235,5 +242,12 @@ class ProjectFilesPresenter @Inject constructor(
} else {
paths.subList(1, paths.size).joinToString(separator = REMOTE_SEPARATOR)
}
private fun getFilePath(inRoot: Boolean, paths: List<String>, fileName: String) =
if (inRoot) {
fileName
} else {
"${paths.subList(1, paths.size).joinToString(separator = REMOTE_SEPARATOR)}$REMOTE_SEPARATOR$fileName"
}
}
}
\ No newline at end of file
......@@ -40,4 +40,10 @@ annotation class UserId
annotation class CacheLifetime
@Qualifier
annotation class WithErrorHandler
\ No newline at end of file
annotation class WithErrorHandler
@Qualifier
annotation class FilePath
@Qualifier
annotation class BranchName
\ No newline at end of file
package ru.terrakok.gitlabclient.ui.file
import android.os.Bundle
import com.arellomobile.mvp.presenter.InjectPresenter
import com.arellomobile.mvp.presenter.ProvidePresenter
import kotlinx.android.synthetic.main.fragment_mr.*
import ru.terrakok.gitlabclient.R
import ru.terrakok.gitlabclient.extension.argument
import ru.terrakok.gitlabclient.presentation.file.ProjectFilePresenter
import ru.terrakok.gitlabclient.presentation.file.ProjectFileView
import ru.terrakok.gitlabclient.toothpick.DI
import ru.terrakok.gitlabclient.toothpick.PrimitiveWrapper
import ru.terrakok.gitlabclient.toothpick.qualifier.BranchName
import ru.terrakok.gitlabclient.toothpick.qualifier.FilePath
import ru.terrakok.gitlabclient.toothpick.qualifier.ProjectId
import ru.terrakok.gitlabclient.ui.global.BaseFragment
import toothpick.Scope
import toothpick.config.Module
/**
* Created by Eugene Shapovalov (@CraggyHaggy) on 22.11.18.
*/
class ProjectFileFragment : BaseFragment(), ProjectFileView {
private val projectId by argument(ARG_PROJECT_ID, 0L)
private val filePath by argument<String>(ARG_FILE_PATH, null)
private val branchName by argument<String>(ARG_BRANCH_NAME, null)
override val layoutRes = R.layout.fragment_project_file
override val parentScopeName = DI.SERVER_SCOPE
override val scopeModuleInstaller = { scope: Scope ->
scope.installModules(
object : Module() {
init {
bind(PrimitiveWrapper::class.java)
.withName(ProjectId::class.java)
.toInstance(PrimitiveWrapper(projectId))
bind(String::class.java)
.withName(FilePath::class.java)
.toInstance(filePath)
bind(String::class.java)
.withName(BranchName::class.java)
.toInstance(branchName)
}
}
)
}
@InjectPresenter
lateinit var presenter: ProjectFilePresenter
@ProvidePresenter
fun providePresenter() = scope.getInstance(ProjectFilePresenter::class.java)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
toolbar.setNavigationOnClickListener { onBackPressed() }
}
override fun onBackPressed() {
super.onBackPressed()
presenter.onBackPressed()
}
companion object {
private const val ARG_PROJECT_ID = "arg_project_id"
private const val ARG_FILE_PATH = "arg_file_path"
private const val ARG_BRANCH_NAME = "arg_branch_name"
fun create(projectId: Long, filePath: String, branchName: String) =
ProjectFileFragment().apply {
arguments = Bundle().apply {
putLong(ARG_PROJECT_ID, projectId)
putString(ARG_FILE_PATH, filePath)
putString(ARG_BRANCH_NAME, branchName)
}
}
}
}
\ No newline at end of file
......@@ -13,7 +13,9 @@ import ru.terrakok.gitlabclient.ui.global.GitDiffViewController
/**
* Created by Eugene Shapovalov (@CraggyHaggy) on 26.10.18.
*/
class MergeRequestChangeAdapterDelegate : AdapterDelegate<MutableList<MergeRequestChange>>() {
class MergeRequestChangeAdapterDelegate(
private val clickListener: (MergeRequestChange) -> Unit
) : AdapterDelegate<MutableList<MergeRequestChange>>() {
override fun isForViewType(items: MutableList<MergeRequestChange>, position: Int) = true
......@@ -33,26 +35,30 @@ class MergeRequestChangeAdapterDelegate : AdapterDelegate<MutableList<MergeReque
}
private inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private lateinit var mergeRequestChange: MergeRequestChange
private lateinit var item: MergeRequestChange
init {
view.setOnClickListener { clickListener(item) }
}
private val gitDiffViewController: GitDiffViewController = GitDiffViewController(itemView.changeFile)
fun bind(mergeRequestChange: MergeRequestChange) {
this.mergeRequestChange = mergeRequestChange
fun bind(item: MergeRequestChange) {
this.item = item
with(itemView) {
changePath.text = mergeRequestChange.newPath
changePath.text = item.newPath
changeIcon.setImageResource(
when {
mergeRequestChange.newFile -> R.drawable.ic_file_added
mergeRequestChange.deletedFile -> R.drawable.ic_file_deleted
item.newFile -> R.drawable.ic_file_added
item.deletedFile -> R.drawable.ic_file_deleted
else -> R.drawable.ic_file_changed
}
)
changeFileName.text = mergeRequestChange.newPath.let {
changeFileName.text = item.newPath.let {
val index = it.lastIndexOf("/")
it.substring(if (index != -1) index + 1 else 0)
}
gitDiffViewController.setText(mergeRequestChange.diff)
gitDiffViewController.setText(item.diff)
changeAddedCount.text = context.getString(
R.string.merge_request_changes_added_count,
gitDiffViewController.getAddedLineCount()
......
......@@ -8,11 +8,13 @@ import ru.terrakok.gitlabclient.ui.global.list.MergeRequestChangeAdapterDelegate
/**
* Created by Eugene Shapovalov (@CraggyHaggy) on 26.10.18.
*/
class MergeRequestChangeAdapter : ListDelegationAdapter<MutableList<MergeRequestChange>>() {
class MergeRequestChangeAdapter(
clickListener: (MergeRequestChange) -> Unit
) : ListDelegationAdapter<MutableList<MergeRequestChange>>() {
init {
items = mutableListOf()
delegatesManager.addDelegate(MergeRequestChangeAdapterDelegate())
delegatesManager.addDelegate(MergeRequestChangeAdapterDelegate(clickListener))
}
fun setData(data: List<MergeRequestChange>) {
......
......@@ -23,7 +23,7 @@ class MergeRequestChangesFragment : BaseFragment(), MergeRequestChangesView {
override val layoutRes = R.layout.fragment_mr_changes
private val adapter by lazy { MergeRequestChangeAdapter() }
private val adapter by lazy { MergeRequestChangeAdapter({ presenter.onMergeRequestChangeClick(it) }) }
private var zeroViewHolder: ZeroViewHolder? = null
@InjectPresenter
......@@ -77,4 +77,8 @@ class MergeRequestChangesFragment : BaseFragment(), MergeRequestChangesView {
override fun showMessage(message: String) {
showSnackMessage(message)
}
override fun showFullscreenProgress(show: Boolean) {
showProgressDialog(show)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/ToolbarStyle"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="0dp"
app:navigationIcon="@drawable/ic_arrow_back_24dp"
tools:title="ProjectFile.kt"
tools:subtitle="app/src/main/java/ru/terrakok/gitlabclient/entity/app/ProjectFile.kt" />
<TextView
android:id="@+id/projectFileDetails"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
\ No newline at end of file
......@@ -5,15 +5,15 @@ buildscript {
maven { url = uri("https://maven.fabric.io/public") }
}
dependencies {
classpath("com.android.tools.build:gradle:3.4.0-alpha10")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.11")
classpath("com.android.tools.build:gradle:3.4.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31")
classpath("com.google.gms:google-services:4.2.0")
classpath("io.fabric.tools:gradle:1.26.1")
classpath("io.fabric.tools:gradle:1.29.0")
}
}
allprojects {
extra["kotlinVersion"] = "1.3.11"
extra["kotlinVersion"] = "1.3.31"
repositories {
google()
jcenter()
......
......@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1-milestone-1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
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