Skip to content
Snippets Groups Projects
Commit b63c0da6 authored by John's avatar John
Browse files

Scroll to the appropriate section of the project based on deeplink

parent 7a37c2bf
No related branches found
No related tags found
No related merge requests found
Showing
with 221 additions and 125 deletions
Change Log
==========
 
Version 2.6.2
----------------------------
- Fix routing of some URLs
Version 2.6.1
----------------------------
 
Loading
Loading
Loading
Loading
@@ -145,8 +145,8 @@ dependencies {
 
implementation 'org.greenrobot:eventbus:3.1.1'
 
implementation 'io.reactivex.rxjava2:rxjava:2.1.16'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
 
implementation "com.uber.autodispose:autodispose-kotlin:$autodisposeVersion"
implementation "com.uber.autodispose:autodispose-android-kotlin:$autodisposeVersion"
Loading
Loading
Loading
Loading
@@ -16,6 +16,7 @@ import android.view.ViewGroup
import android.widget.Toast
import butterknife.BindView
import butterknife.ButterKnife
import com.commit451.addendum.extraOrNull
import com.commit451.addendum.parceler.getParcelerParcelable
import com.commit451.addendum.parceler.getParcelerParcelableExtra
import com.commit451.addendum.parceler.putParcelerParcelable
Loading
Loading
@@ -30,8 +31,8 @@ import com.commit451.gitlab.extension.with
import com.commit451.gitlab.fragment.BaseFragment
import com.commit451.gitlab.model.Ref
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.navigation.DeepLinker
import com.commit451.gitlab.navigation.Navigator
import com.commit451.gitlab.rx.CustomSingleObserver
import com.commit451.gitlab.util.IntentUtil
import io.reactivex.Single
import timber.log.Timber
Loading
Loading
@@ -40,15 +41,16 @@ class ProjectActivity : BaseActivity() {
 
companion object {
 
private val EXTRA_PROJECT = "extra_project"
private val EXTRA_PROJECT_ID = "extra_project_id"
private val EXTRA_PROJECT_NAMESPACE = "extra_project_namespace"
private val EXTRA_PROJECT_NAME = "extra_project_name"
private const val EXTRA_PROJECT = "extra_project"
private const val EXTRA_PROJECT_ID = "extra_project_id"
private const val EXTRA_PROJECT_NAMESPACE = "extra_project_namespace"
private const val EXTRA_PROJECT_NAME = "extra_project_name"
private const val EXTRA_PROJECT_SELECTION = "extra_project_selection"
 
private val STATE_REF = "ref"
private val STATE_PROJECT = "project"
private const val STATE_REF = "ref"
private const val STATE_PROJECT = "project"
 
private val REQUEST_BRANCH_OR_TAG = 1
private const val REQUEST_BRANCH_OR_TAG = 1
 
fun newIntent(context: Context, project: Project): Intent {
val intent = Intent(context, ProjectActivity::class.java)
Loading
Loading
@@ -62,10 +64,11 @@ class ProjectActivity : BaseActivity() {
return intent
}
 
fun newIntent(context: Context, projectNamespace: String, projectName: String): Intent {
fun newIntent(context: Context, projectNamespace: String, projectName: String, projectSelection: DeepLinker.ProjectSelection): Intent {
val intent = Intent(context, ProjectActivity::class.java)
intent.putExtra(EXTRA_PROJECT_NAMESPACE, projectNamespace)
intent.putExtra(EXTRA_PROJECT_NAME, projectName)
intent.putExtra(EXTRA_PROJECT_SELECTION, projectSelection)
return intent
}
}
Loading
Loading
@@ -84,7 +87,9 @@ class ProjectActivity : BaseActivity() {
var project: Project? = null
var ref: Ref? = null
 
val onMenuItemClickListener = Toolbar.OnMenuItemClickListener { item ->
private val projectSelection by extraOrNull<DeepLinker.ProjectSelection>(EXTRA_PROJECT_SELECTION)
private val onMenuItemClickListener = Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_branch -> {
if (project != null) {
Loading
Loading
@@ -185,41 +190,36 @@ class ProjectActivity : BaseActivity() {
return true
}
 
fun loadProject(projectId: String) {
private fun loadProject(projectId: String) {
showProgress()
loadProject(App.get().gitLab.getProject(projectId))
}
 
fun loadProject(projectNamespace: String, projectName: String) {
private fun loadProject(projectNamespace: String, projectName: String) {
showProgress()
loadProject(App.get().gitLab.getProject(projectNamespace, projectName))
}
 
fun loadProject(observable: Single<Project>) {
private fun loadProject(observable: Single<Project>) {
observable.with(this)
.subscribe(object : CustomSingleObserver<Project>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.fadeOut()
Snackbar.make(root, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show()
}
override fun success(project: Project) {
progress.fadeOut()
bindProject(project)
}
.subscribe({
progress.fadeOut()
bindProject(it)
}, {
Timber.e(it)
progress.fadeOut()
Snackbar.make(root, getString(R.string.connection_error), Snackbar.LENGTH_INDEFINITE)
.show()
})
}
 
fun showProgress() {
private fun showProgress() {
progress.alpha = 0.0f
progress.visibility = View.VISIBLE
progress.animate().alpha(1.0f)
}
 
fun broadcastLoad() {
private fun broadcastLoad() {
App.bus().post(ProjectReloadEvent(project!!, ref!!.ref!!))
}
 
Loading
Loading
@@ -230,7 +230,7 @@ class ProjectActivity : BaseActivity() {
return ref!!.ref
}
 
fun bindProject(project: Project) {
private fun bindProject(project: Project) {
this.project = project
if (ref == null) {
ref = Ref(Ref.TYPE_BRANCH, project.defaultBranch)
Loading
Loading
@@ -240,13 +240,17 @@ class ProjectActivity : BaseActivity() {
setupTabs()
}
 
fun setupTabs() {
val projectSectionsPagerAdapter = ProjectPagerAdapter(this, supportFragmentManager)
viewPager.adapter = projectSectionsPagerAdapter
private fun setupTabs() {
val adapter = ProjectPagerAdapter(this, supportFragmentManager)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
projectSelection?.let {
val index = adapter.indexForSelection(it)
viewPager.setCurrentItem(index, false)
}
}
 
fun copyToClipboard(url: String) {
private fun copyToClipboard(url: String) {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
 
// Creates a new text clip to put on the clipboard
Loading
Loading
Loading
Loading
@@ -39,9 +39,9 @@ class RoutingActivity : BaseActivity() {
overridePendingTransition(R.anim.fade_in, R.anim.do_nothing)
}
 
override fun onRouteToProject(projectNamespace: String, projectName: String) {
override fun onRouteToProject(projectNamespace: String, projectName: String, selection: DeepLinker.ProjectSelection) {
Timber.d("Routing to project")
Navigator.navigateToProject(this@RoutingActivity, projectNamespace, projectName)
Navigator.navigateToProject(this@RoutingActivity, projectNamespace, projectName, selection)
}
 
override fun onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String) {
Loading
Loading
Loading
Loading
@@ -3,13 +3,14 @@ package com.commit451.gitlab.adapter
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
import com.commit451.gitlab.BuildConfig
import com.commit451.gitlab.R
import com.commit451.gitlab.activity.ProjectActivity
import com.commit451.gitlab.extension.feedUrl
import com.commit451.gitlab.fragment.*
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.navigation.DeepLinker
import timber.log.Timber
import java.util.*
 
/**
* Controls the sections that should be shown in a [com.commit451.gitlab.activity.ProjectActivity]
Loading
Loading
@@ -17,76 +18,75 @@ import java.util.*
class ProjectPagerAdapter(context: ProjectActivity, fm: FragmentManager) : FragmentPagerAdapter(fm) {
 
companion object {
val PROJECT_POS = 0
val ACTIVITY_POS = 1
val FILES_POS = 2
val COMMITS_POS = 3
val PIPELINES_POS = 4
val BUILDS_POS = 5
val MILESTONES_POS = 6
val ISSUES_POS = 7
val MERGE_REQUESTS_POS = 8
val PROJECT_MEMBERS_POS = 9
val SNIPPETS_POS = 10
const val SECTION_PROJECT = "project"
const val SECTION_ACTIVITY = "activity"
const val SECTION_FILES = "files"
const val SECTION_COMMITS = "commits"
const val SECTION_PIPELINE = "pipeline"
const val SECTION_JOBS = "jobs"
const val SECTION_MILESTONES = "milestones"
const val SECTION_ISSUES = "issues"
const val SECTION_MERGE_REQUESTS = "merge_requests"
const val SECTION_MEMBERS = "members"
const val SECTION_SNIPPETS = "snippets"
}
 
private val project: Project = context.project!!
private val titles: Array<String> = context.resources.getStringArray(R.array.main_tabs)
private val disabledSections = HashSet<Int>()
private val sections = mutableListOf<Section>()
 
init {
val project = context.project!!
if (isDisabled(project.isBuildEnabled)) {
Timber.d("Builds are disabled")
disabledSections.add(BUILDS_POS)
disabledSections.add(PIPELINES_POS)
sections.add(Section(SECTION_PROJECT, context.getString(R.string.title_project)))
sections.add(Section(SECTION_ACTIVITY, context.getString(R.string.title_activity)))
if (!isDisabled(project.isIssuesEnabled)) {
sections.add(Section(SECTION_ISSUES, context.getString(R.string.title_issues)))
}
if (isDisabled(project.isIssuesEnabled)) {
Timber.d("Issues are disabled")
disabledSections.add(ISSUES_POS)
sections.add(Section(SECTION_FILES, context.getString(R.string.title_files)))
sections.add(Section(SECTION_COMMITS, context.getString(R.string.title_commits)))
if (!isDisabled(project.isBuildEnabled)) {
sections.add(Section(SECTION_PIPELINE, context.getString(R.string.title_pipelines)))
sections.add(Section(SECTION_JOBS, context.getString(R.string.title_jobs)))
}
if (isDisabled(project.isMergeRequestsEnabled)) {
Timber.d("Merge requests are disabled")
disabledSections.add(MERGE_REQUESTS_POS)
if (!isDisabled(project.isMergeRequestsEnabled)) {
sections.add(Section(SECTION_MERGE_REQUESTS, context.getString(R.string.title_merge_requests)))
}
if (isDisabled(project.isIssuesEnabled) && isDisabled(project.isMergeRequestsEnabled)) {
Timber.d("Milestones are disabled")
disabledSections.add(MILESTONES_POS)
if (!isDisabled(project.isIssuesEnabled) && !isDisabled(project.isMergeRequestsEnabled)) {
sections.add(Section(SECTION_MILESTONES, context.getString(R.string.title_milestones)))
}
//TODO enable snippets when they are done
if (true) {//!project.isSnippetsEnabled()) {
if (BuildConfig.DEBUG && project.isSnippetsEnabled == true) {
Timber.d("Snippets are disabled")
disabledSections.add(SNIPPETS_POS)
sections.add(Section(SECTION_SNIPPETS, context.getString(R.string.title_snippets)))
}
sections.add(Section(SECTION_MEMBERS, context.getString(R.string.title_members)))
}
 
override fun getCount(): Int {
return titles.size - disabledSections.size
return sections.size
}
 
override fun getPageTitle(position: Int): CharSequence {
return titles[getCorrectPosition(position)]
return sections[position].name
}
 
override fun getItem(position: Int): Fragment {
val correctPosition = getCorrectPosition(position)
val sectionId = sections[position].id
 
when (correctPosition) {
PROJECT_POS -> return ProjectFragment.newInstance()
ACTIVITY_POS -> return FeedFragment.newInstance(project.feedUrl)
FILES_POS -> return FilesFragment.newInstance()
COMMITS_POS -> return CommitsFragment.newInstance()
PIPELINES_POS -> return PipelinesFragment.newInstance()
BUILDS_POS -> return BuildsFragment.newInstance()
MILESTONES_POS -> return MilestonesFragment.newInstance()
ISSUES_POS -> return IssuesFragment.newInstance()
MERGE_REQUESTS_POS -> return MergeRequestsFragment.newInstance()
PROJECT_MEMBERS_POS -> return ProjectMembersFragment.newInstance()
SNIPPETS_POS -> return SnippetsFragment.newInstance()
when (sectionId) {
SECTION_PROJECT -> return ProjectFragment.newInstance()
SECTION_ACTIVITY -> return FeedFragment.newInstance(project.feedUrl)
SECTION_FILES -> return FilesFragment.newInstance()
SECTION_COMMITS -> return CommitsFragment.newInstance()
SECTION_PIPELINE -> return PipelinesFragment.newInstance()
SECTION_JOBS -> return JobsFragment.newInstance()
SECTION_MILESTONES -> return MilestonesFragment.newInstance()
SECTION_ISSUES -> return IssuesFragment.newInstance()
SECTION_MERGE_REQUESTS -> return MergeRequestsFragment.newInstance()
SECTION_MEMBERS -> return ProjectMembersFragment.newInstance()
SECTION_SNIPPETS -> return SnippetsFragment.newInstance()
}
 
throw IllegalStateException("Position exceeded on view pager")
throw IllegalStateException("Nothing to do with sectionId $sectionId")
}
 
private fun isDisabled(enabledState: Boolean?): Boolean {
Loading
Loading
@@ -96,14 +96,20 @@ class ProjectPagerAdapter(context: ProjectActivity, fm: FragmentManager) : Fragm
return false
}
 
private fun getCorrectPosition(position: Int): Int {
var correctPosition = position
for (i in 0..position) {
if (disabledSections.contains(i)) {
correctPosition++
}
fun indexForSelection(projectSelection: DeepLinker.ProjectSelection): Int {
var index = when (projectSelection) {
DeepLinker.ProjectSelection.PROJECT -> sections.indexOfFirst { it.id == SECTION_PROJECT }
DeepLinker.ProjectSelection.ISSUES -> sections.indexOfFirst { it.id == SECTION_ISSUES }
DeepLinker.ProjectSelection.COMMITS -> sections.indexOfFirst { it.id == SECTION_COMMITS }
DeepLinker.ProjectSelection.MILESTONES -> sections.indexOfFirst { it.id == SECTION_MILESTONES }
DeepLinker.ProjectSelection.JOBS -> sections.indexOfFirst { it.id == SECTION_JOBS }
else -> 0
}
return correctPosition
if (index == -1) {
index = 0
}
return index
}
class Section(val id: String, val name: String)
}
Loading
Loading
@@ -31,14 +31,14 @@ import org.greenrobot.eventbus.Subscribe
import timber.log.Timber
 
/**
* Shows the builds of a project
* Shows the jobs of a project
*/
class BuildsFragment : ButterKnifeFragment() {
class JobsFragment : ButterKnifeFragment() {
 
companion object {
 
fun newInstance(): BuildsFragment {
return BuildsFragment()
fun newInstance(): JobsFragment {
return JobsFragment()
}
}
 
Loading
Loading
@@ -81,7 +81,7 @@ class BuildsFragment : ButterKnifeFragment() {
}
 
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_builds, container, false)
return inflater.inflate(R.layout.fragment_jobs, container, false)
}
 
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Loading
Loading
Loading
Loading
@@ -33,11 +33,11 @@ class ProjectFragment : ButterKnifeFragment() {
 
companion object {
 
private val README_TYPE_UNKNOWN = -1
private val README_TYPE_MARKDOWN = 0
private val README_TYPE_TEXT = 1
private val README_TYPE_HTML = 2
private val README_TYPE_NO_EXTENSION = 3
private const val README_TYPE_UNKNOWN = -1
private const val README_TYPE_MARKDOWN = 0
private const val README_TYPE_TEXT = 1
private const val README_TYPE_HTML = 2
private const val README_TYPE_NO_EXTENSION = 3
 
fun newInstance(): ProjectFragment {
return ProjectFragment()
Loading
Loading
@@ -249,6 +249,7 @@ class ProjectFragment : ButterKnifeFragment() {
})
}
 
@Suppress("unused")
@Subscribe
fun onProjectReload(event: ProjectReloadEvent) {
project = event.project
Loading
Loading
Loading
Loading
@@ -31,7 +31,7 @@ object DeepLinker {
navigator.onRouteUnknown(url)
return
}
val path = link.pathSegments().joinToString { "/" }
val path = link.pathSegments().joinToString("/", "/")
if (path.contains("issues")) {
if (link.pathSegments().last() == "issues") {
//this means it was just a link to something like
Loading
Loading
@@ -41,7 +41,7 @@ object DeepLinker {
val namespace = link.pathSegments()[index - 2]
val name = link.pathSegments()[index - 1]
//TODO make this tell what tab to open up when we get to projects
navigator.onRouteToProject(namespace, name)
navigator.onRouteToProject(namespace, name, ProjectSelection.ISSUES)
return
}
} else {
Loading
Loading
@@ -65,7 +65,7 @@ object DeepLinker {
if (index > 1) {
val projectNamespace = link.pathSegments()[index - 2]
val projectName = link.pathSegments()[index - 1]
navigator.onRouteToProject(projectNamespace, projectName)
navigator.onRouteToProject(projectNamespace, projectName, ProjectSelection.COMMITS)
return
}
} else if (path.contains("commit")) {
Loading
Loading
@@ -121,7 +121,7 @@ object DeepLinker {
//exactly two path segments, it is probably a link to a project
val projectNamespace = link.pathSegments()[0]
val projectName = link.pathSegments()[1]
navigator.onRouteToProject(projectNamespace, projectName)
navigator.onRouteToProject(projectNamespace, projectName, ProjectSelection.PROJECT)
return
}
navigator.onRouteUnknown(url)
Loading
Loading
@@ -141,9 +141,18 @@ object DeepLinker {
fun onRouteToIssue(projectNamespace: String, projectName: String, issueIid: String)
fun onRouteToCommit(projectNamespace: String, projectName: String, commitSha: String)
fun onRouteToMergeRequest(projectNamespace: String, projectName: String, mergeRequestIid: String)
fun onRouteToProject(projectNamespace: String, projectName: String)
fun onRouteToProject(projectNamespace: String, projectName: String, selection: ProjectSelection)
fun onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String)
fun onRouteToMilestone(projectNamespace: String, projectName: String, milestoneNumber: String)
fun onRouteUnknown(url: String?)
}
enum class ProjectSelection {
PROJECT,
ISSUES,
COMMITS,
MILESTONES,
JOBS,
MERGE_REQUESTS
}
}
Loading
Loading
@@ -43,8 +43,8 @@ object Navigator {
activity.startActivity(ProjectActivity.newIntent(activity, projectId))
}
 
fun navigateToProject(activity: Activity, projectNamespace: String, projectName: String) {
activity.startActivity(ProjectActivity.newIntent(activity, projectNamespace, projectName))
fun navigateToProject(activity: Activity, projectNamespace: String, projectName: String, selection: DeepLinker.ProjectSelection) {
activity.startActivity(ProjectActivity.newIntent(activity, projectNamespace, projectName, selection))
}
 
fun navigateToPickBranchOrTag(activity: Activity, projectId: Long, currentRef: Ref?, requestCode: Int) {
Loading
Loading
Loading
Loading
@@ -47,23 +47,9 @@
<string name="title_merge_requests">Merge Requests</string>
<string name="title_members">Members</string>
<string name="title_pipelines">Pipelines</string>
<string name="title_builds">Jobs</string>
<string name="title_jobs">Jobs</string>
<string name="title_snippets">Snippets</string>
 
<string-array name="main_tabs">
<item>@string/title_project</item>
<item>@string/title_activity</item>
<item>@string/title_files</item>
<item>@string/title_commits</item>
<item>@string/title_pipelines</item>
<item>@string/title_builds</item>
<item>@string/title_milestones</item>
<item>@string/title_issues</item>
<item>@string/title_merge_requests</item>
<item>@string/title_members</item>
<item>@string/title_snippets</item>
</string-array>
<string name="title_all">All</string>
<string name="title_yours">Yours</string>
<string name="title_starred">Starred</string>
Loading
Loading
package com.commit451.gitlab
import com.commit451.gitlab.navigation.DeepLinker
class CounterCallbacks: DeepLinker.Callbacks {
var issue = 0
var commit = 0
var mergeRequest = 0
var project = 0
var build = 0
var milestone = 0
var unknown = 0
override fun onRouteToIssue(projectNamespace: String, projectName: String, issueIid: String) {
issue++
}
override fun onRouteToCommit(projectNamespace: String, projectName: String, commitSha: String) {
commit++
}
override fun onRouteToMergeRequest(projectNamespace: String, projectName: String, mergeRequestIid: String) {
mergeRequest++
}
override fun onRouteToProject(projectNamespace: String, projectName: String) {
project++
}
override fun onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String) {
build++
}
override fun onRouteToMilestone(projectNamespace: String, projectName: String, milestoneNumber: String) {
milestone++
}
override fun onRouteUnknown(url: String?) {
unknown++
}
}
\ No newline at end of file
package com.commit451.gitlab
import com.commit451.gitlab.navigation.DeepLinker
import org.junit.Assert
import org.junit.Test
/**
* Tests deeplink routing
*/
class DeepLinkerTests {
@Test
fun issuesTest() {
val link = "https://gitlab.com/Commit451/LabCoat/issues"
val callbacks = CounterCallbacks()
DeepLinker.route(link, callbacks)
Assert.assertEquals(1, callbacks.project)
}
@Test
fun projectTest() {
val link = "https://gitlab.com/Commit451/LabCoat"
val callbacks = CounterCallbacks()
DeepLinker.route(link, callbacks)
Assert.assertEquals(1, callbacks.project)
}
@Test
fun commits() {
val link = "https://gitlab.com/Commit451/LabCoat/commits"
val callbacks = CounterCallbacks()
DeepLinker.route(link, callbacks)
Assert.assertEquals(1, callbacks.project)
}
@Test
fun builds() {
val link = "https://gitlab.com/Commit451/LabCoat/builds/artifacts/master/browse"
val callbacks = CounterCallbacks()
DeepLinker.route(link, callbacks)
Assert.assertEquals(1, callbacks.build)
}
}
\ No newline at end of file
apply plugin: 'com.github.ben-manes.versions'
buildscript {
ext.kotlinVersion = '1.2.51'
ext.kotlinVersion = '1.2.60'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.android.tools.build:gradle:3.1.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0'
}
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment