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

Refactor deep lninking

parent 792cc6c2
No related branches found
No related tags found
No related merge requests found
Showing
with 135 additions and 265 deletions
Loading
Loading
@@ -78,12 +78,6 @@ android {
versionNameSuffix "-debug"
}
}
lintOptions {
abortOnError false
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
 
packagingOptions {
exclude 'META-INF/MANIFEST.MF'
Loading
Loading
@@ -101,14 +95,16 @@ ext {
adapterLayout = '1.1.2'
materialDialogsVersion = '0.9.6.0'
leakCanaryVersion = '1.5.4'
addendumVersion = '1.7.1'
moshiVersion = '1.5.0'
autodisposeVersion = '0.7.0'
addendumVersion = '2.0.0'
moshiVersion = '1.6.0'
autodisposeVersion = '0.8.0'
}
 
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
 
implementation 'androidx.core:core-ktx:0.3'
implementation "com.android.support:appcompat-v7:$supportLibVersion"
implementation "com.android.support:support-v13:$supportLibVersion"
implementation "com.android.support:design:$supportLibVersion"
Loading
Loading
@@ -143,7 +139,7 @@ dependencies {
 
implementation 'org.greenrobot:eventbus:3.1.1'
 
implementation 'io.reactivex.rxjava2:rxjava:2.1.13'
implementation 'io.reactivex.rxjava2:rxjava:2.1.14'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
 
implementation "com.uber.autodispose:autodispose-kotlin:$autodisposeVersion"
Loading
Loading
@@ -167,7 +163,7 @@ dependencies {
}
implementation 'com.github.Commit451:Easel:3.0.0'
implementation 'com.github.Commit451:Gimbal:2.0.2'
implementation 'com.github.Commit451:Teleprinter:2.0.2'
implementation 'com.github.Commit451:Teleprinter:2.1.1'
implementation 'com.github.Commit451:Jounce:1.0.2'
implementation 'com.github.Commit451:ForegroundViews:2.4.4'
implementation 'com.github.Commit451:MorphTransitions:2.0.0'
Loading
Loading
@@ -195,7 +191,7 @@ dependencies {
 
implementation 'com.github.alorma:diff-textview:1.3.0'
 
implementation 'com.wdullaer:materialdatetimepicker:3.5.2'
implementation 'com.wdullaer:materialdatetimepicker:3.6.0'
 
implementation 'com.github.novoda:simple-chrome-custom-tabs:0.1.6'
 
Loading
Loading
@@ -212,7 +208,7 @@ dependencies {
 
implementation 'com.atlassian.commonmark:commonmark:0.11.0'
 
normalImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.2'
normalImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.3'
 
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
Loading
Loading
package com.commit451.gitlab
import android.net.Uri
import com.commit451.gitlab.navigation.RoutingNavigator
/**
* Checks counting
*/
class CountingRouter : RoutingNavigator {
var issueRouteCount = 0
var commitRouteCount = 0
var mergeRequestRouteCount = 0
var projectRouteCount = 0
var buildRouteCount = 0
var milestoneRouteCount: Int = 0
var unknownRountCount = 0
override fun onRouteToIssue(projectNamespace: String, projectName: String, issueIid: String) {
issueRouteCount++
}
override fun onRouteToCommit(projectNamespace: String, projectName: String, commitSha: String) {
commitRouteCount++
}
override fun onRouteToMergeRequest(projectNamespace: String, projectName: String, mergeRequestId: String) {
mergeRequestRouteCount++
}
override fun onRouteToProject(namespace: String, projectId: String) {
projectRouteCount++
}
override fun onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String) {
buildRouteCount++
}
override fun onRouteToMilestone(projectNamespace: String, projectName: String, milestoneNumber: String) {
milestoneRouteCount++
}
override fun onRouteUnknown(uri: Uri?) {
unknownRountCount++
}
}
package com.commit451.gitlab
import android.net.Uri
import android.support.test.runner.AndroidJUnit4
import com.commit451.gitlab.navigation.RoutingRouter
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
/**
* Tests account login and basic retrieval stuff
*/
@RunWith(AndroidJUnit4::class)
class RoutingTests {
@Test
fun routeIssues() {
val countingRouter = CountingRouter()
val router = RoutingRouter(countingRouter)
var issueUrl = Uri.parse("https://gitlab.com/Commit451/LabCoat/issues/153")
router.route(issueUrl)
Assert.assertEquals(1, countingRouter.issueRouteCount)
issueUrl = Uri.parse("gitlab.com/Commit451/LabCoat/issues")
router.route(issueUrl)
Assert.assertEquals(1, countingRouter.projectRouteCount)
issueUrl = Uri.parse("http://example.com/wehostourgitlabserverhere/Commit451/LabCoat/issues")
router.route(issueUrl)
Assert.assertEquals(2, countingRouter.projectRouteCount)
}
@Test
fun routeCommits() {
var commitUrl = Uri.parse("https://gitlab.com/Commit451/LabCoat/commit/434fb013607836620819fae09f23a72d88369d3d")
val countingRouter = CountingRouter()
val router = RoutingRouter(countingRouter)
router.route(commitUrl)
Assert.assertEquals(1, countingRouter.commitRouteCount)
commitUrl = Uri.parse("http://gitlab.com/Commit451/LabCoat/commits")
router.route(commitUrl)
Assert.assertEquals(1, countingRouter.projectRouteCount)
//Test for subdomain
commitUrl = Uri.parse("http://example.com/wehostourgitlabserverhere/Commit451/LabCoat/commit/434fb013607836620819fae09f23a72d88369d3d")
router.route(commitUrl)
Assert.assertEquals(2, countingRouter.commitRouteCount)
}
@Test
fun routeMergeRequests() {
var mergeRequestUrl = Uri.parse("https://gitlab.com/Commit451/LabCoat/merge_requests/14")
val countingRouter = CountingRouter()
val router = RoutingRouter(countingRouter)
router.route(mergeRequestUrl)
Assert.assertEquals(1, countingRouter.mergeRequestRouteCount)
mergeRequestUrl = Uri.parse("http://gitlab.com/Commit451/LabCoat/commits")
router.route(mergeRequestUrl)
Assert.assertEquals(1, countingRouter.projectRouteCount)
//Test for subdomain
mergeRequestUrl = Uri.parse("http://example.com/wehostourgitlabserverhere/Commit451/LabCoat/merge_requests/13")
router.route(mergeRequestUrl)
Assert.assertEquals(2, countingRouter.mergeRequestRouteCount)
}
}
\ No newline at end of file
Loading
Loading
@@ -41,7 +41,7 @@ import timber.log.Timber
class AboutActivity : BaseActivity() {
 
companion object {
private val REPO_ID = "473568"
private const val REPO_ID = "473568"
 
fun newIntent(context: Context): Intent {
val intent = Intent(context, AboutActivity::class.java)
Loading
Loading
Loading
Loading
@@ -22,7 +22,7 @@ import com.commit451.gitlab.ssl.CustomKeyManager
class LaunchActivity : BaseActivity() {
 
companion object {
private val REQUEST_DEVICE_AUTH = 123
private const val REQUEST_DEVICE_AUTH = 123
}
 
@BindView(R.id.root)
Loading
Loading
Loading
Loading
@@ -9,8 +9,6 @@ import com.commit451.gitlab.R
import com.commit451.gitlab.data.Prefs
import com.commit451.gitlab.navigation.DeepLinker
import com.commit451.gitlab.navigation.Navigator
import com.commit451.gitlab.navigation.RoutingNavigator
import com.commit451.gitlab.navigation.RoutingRouter
import com.commit451.gitlab.util.IntentUtil
import timber.log.Timber
 
Loading
Loading
@@ -20,10 +18,9 @@ import timber.log.Timber
*/
class RoutingActivity : BaseActivity() {
 
lateinit var router: RoutingRouter
var originalUri: Uri? = null
 
val navigator = object : RoutingNavigator {
val navigator = object : DeepLinker.Callbacks {
override fun onRouteToIssue(projectNamespace: String, projectName: String, issueIid: String) {
Timber.d("Routing to issue")
startActivity(LoadSomeInfoActivity.newIssueIntent(this@RoutingActivity, projectNamespace, projectName, issueIid))
Loading
Loading
@@ -36,15 +33,15 @@ class RoutingActivity : BaseActivity() {
overridePendingTransition(R.anim.fade_in, R.anim.do_nothing)
}
 
override fun onRouteToMergeRequest(projectNamespace: String, projectName: String, mergeRequestId: String) {
override fun onRouteToMergeRequest(projectNamespace: String, projectName: String, mergeRequestIid: String) {
Timber.d("Routing to merge request")
startActivity(LoadSomeInfoActivity.newMergeRequestIntent(this@RoutingActivity, projectNamespace, projectName, mergeRequestId))
startActivity(LoadSomeInfoActivity.newMergeRequestIntent(this@RoutingActivity, projectNamespace, projectName, mergeRequestIid))
overridePendingTransition(R.anim.fade_in, R.anim.do_nothing)
}
 
override fun onRouteToProject(namespace: String, projectId: String) {
override fun onRouteToProject(projectNamespace: String, projectName: String) {
Timber.d("Routing to project")
Navigator.navigateToProject(this@RoutingActivity, namespace, projectId)
Navigator.navigateToProject(this@RoutingActivity, projectNamespace, projectName)
}
 
override fun onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String) {
Loading
Loading
@@ -84,7 +81,7 @@ class RoutingActivity : BaseActivity() {
return true
}
 
fun handleIntent(intent: Intent?) {
private fun handleIntent(intent: Intent?) {
if (intent == null || intent.data == null) {
Timber.e("No url was passed. How did that happen?")
finish()
Loading
Loading
@@ -92,7 +89,7 @@ class RoutingActivity : BaseActivity() {
}
//If it has an original uri, this means that it is an internal deep link and we
//can still fall back to what the original uri was and just show it
originalUri = intent.getParcelableExtra<Uri>(DeepLinker.EXTRA_ORIGINAL_URI)
originalUri = intent.getParcelableExtra(DeepLinker.EXTRA_ORIGINAL_URI)
val link = intent.data
Timber.d("Received deep link %s", link)
Timber.d("Original link was %s", originalUri)
Loading
Loading
@@ -104,8 +101,7 @@ class RoutingActivity : BaseActivity() {
finish()
return
}
router = RoutingRouter(navigator)
router.route(link)
DeepLinker.route(link, navigator)
finish()
}
}
Loading
Loading
Loading
Loading
@@ -50,8 +50,8 @@ object Prefs {
val type = Types.newParameterizedType(List::class.java, Account::class.java)
val adapter = MoshiProvider.moshi.adapter<List<Account>>(type)
val accounts = adapter.fromJson(accountsJson)!!.toMutableList()
Collections.sort(accounts)
Collections.reverse(accounts)
accounts.sort()
accounts.reverse()
return accounts
} catch (e: Exception) {
Timber.e(e)
Loading
Loading
@@ -60,7 +60,7 @@ object Prefs {
return mutableListOf()
}
 
fun setAccounts(accounts: List<Account>) {
private fun setAccounts(accounts: List<Account>) {
try {
val type = Types.newParameterizedType(List::class.java, Account::class.java)
val adapter = MoshiProvider.moshi.adapter<List<Account>>(type)
Loading
Loading
Loading
Loading
@@ -11,7 +11,7 @@ import com.commit451.gitlab.R
*/
object DeepLinker {
 
val EXTRA_ORIGINAL_URI = "original_uri"
const val EXTRA_ORIGINAL_URI = "original_uri"
 
fun generateDeeplinkIntentFromUri(context: Context, originalUri: Uri): Intent {
val uri = originalUri.buildUpon()
Loading
Loading
@@ -20,10 +20,121 @@ object DeepLinker {
return generatePrivateIntent(context, uri, originalUri)
}
 
fun route(link: Uri?, navigator: Callbacks) {
if (link == null) {
navigator.onRouteUnknown(null)
return
}
if (link.path == null) {
navigator.onRouteUnknown(link)
return
}
if (link.path.contains("issues")) {
if (link.lastPathSegment == "issues") {
//this means it was just a link to something like
//gitlab.com/Commit451/LabCoat/issues
val index = link.pathSegments.indexOf("issues")
if (index != -1 && index > 1) {
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)
return
}
} else {
val index = link.pathSegments.indexOf("issues")
//this is good, it means it is a link to an actual issue
if (index != -1 && index > 1 && link.pathSegments.size > index) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val lastSegment = link.pathSegments[index + 1]
//We have to do this cause there can be args on the url, such as
//https://gitlab.com/Commit451/LabCoat/issues/158#note_4560580
val stuff = lastSegment.split("#".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val issueIid = stuff[0]
navigator.onRouteToIssue(projectNamespace, projectName, issueIid)
return
}
}
} else if (link.path.contains("commits")) {
//Order matters here, parse commits first, then commit
val index = link.pathSegments.indexOf("commits")
if (index > 1) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
navigator.onRouteToProject(projectNamespace, projectName)
return
}
} else if (link.path.contains("commit")) {
val index = link.pathSegments.indexOf("commit")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val commitSha = link.pathSegments[index + 1]
navigator.onRouteToCommit(projectNamespace, projectName, commitSha)
return
}
} else if (link.path.contains("compare")) {
val index = link.pathSegments.indexOf("compare")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
//comparing two commit shas
val shas = link.lastPathSegment.split("...".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (shas.size == 2) {
//I believe we want to route to the second one. Should verify this
navigator.onRouteToCommit(projectNamespace, projectName, shas[1])
return
}
}
} else if (link.path.contains("merge_requests")) {
val index = link.pathSegments.indexOf("merge_requests")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val mergeRequestId = link.pathSegments[index + 1]
navigator.onRouteToMergeRequest(projectNamespace, projectName, mergeRequestId)
return
}
} else if (link.path.contains("builds")) {
val index = link.pathSegments.indexOf("builds")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val buildId = link.pathSegments[index + 1]
navigator.onRouteToBuild(projectNamespace, projectName, buildId)
return
}
} else if (link.path.contains("milestones")) {
val index = link.pathSegments.indexOf("milestones")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val milestoneId = link.pathSegments[index + 1]
navigator.onRouteToMilestone(projectNamespace, projectName, milestoneId)
return
}
}
navigator.onRouteUnknown(link)
}
private fun generatePrivateIntent(context: Context, uri: Uri, originalUri: Uri): Intent {
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.putExtra(EXTRA_ORIGINAL_URI, originalUri)
intent.`package` = context.packageName
return intent
}
/**
* Interface called when routing in the Routing activity
*/
interface Callbacks {
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 onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String)
fun onRouteToMilestone(projectNamespace: String, projectName: String, milestoneNumber: String)
fun onRouteUnknown(uri: Uri?)
}
}
package com.commit451.gitlab.navigation
import android.net.Uri
/**
* Interface called when routing in the Routing activity
*/
interface RoutingNavigator {
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 onRouteToBuild(projectNamespace: String, projectName: String, buildNumber: String)
fun onRouteToMilestone(projectNamespace: String, projectName: String, milestoneNumber: String)
fun onRouteUnknown(uri: Uri?)
}
package com.commit451.gitlab.navigation
import android.net.Uri
/**
* Routes things. Could probably be better if it used regex. Maybe one day
*/
class RoutingRouter(private val navigator: RoutingNavigator) {
fun route(link: Uri?) {
if (link == null) {
navigator.onRouteUnknown(null)
return
}
if (link.path == null) {
navigator.onRouteUnknown(link)
return
}
if (link.path.contains("issues")) {
if (link.lastPathSegment == "issues") {
//this means it was just a link to something like
//gitlab.com/Commit451/LabCoat/issues
val index = link.pathSegments.indexOf("issues")
if (index != -1 && index > 1) {
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)
return
}
} else {
val index = link.pathSegments.indexOf("issues")
//this is good, it means it is a link to an actual issue
if (index != -1 && index > 1 && link.pathSegments.size > index) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val lastSegment = link.pathSegments[index + 1]
//We have to do this cause there can be args on the url, such as
//https://gitlab.com/Commit451/LabCoat/issues/158#note_4560580
val stuff = lastSegment.split("#".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val issueIid = stuff[0]
navigator.onRouteToIssue(projectNamespace, projectName, issueIid)
return
}
}
} else if (link.path.contains("commits")) {
//Order matters here, parse commits first, then commit
val index = link.pathSegments.indexOf("commits")
if (index > 1) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
navigator.onRouteToProject(projectNamespace, projectName)
return
}
} else if (link.path.contains("commit")) {
val index = link.pathSegments.indexOf("commit")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val commitSha = link.pathSegments[index + 1]
navigator.onRouteToCommit(projectNamespace, projectName, commitSha)
return
}
} else if (link.path.contains("compare")) {
val index = link.pathSegments.indexOf("compare")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
//comparing two commit shas
val shas = link.lastPathSegment.split("...".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (shas.size == 2) {
//I believe we want to route to the second one. Should verify this
navigator.onRouteToCommit(projectNamespace, projectName, shas[1])
return
}
}
} else if (link.path.contains("merge_requests")) {
val index = link.pathSegments.indexOf("merge_requests")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val mergeRequestId = link.pathSegments[index + 1]
navigator.onRouteToMergeRequest(projectNamespace, projectName, mergeRequestId)
return
}
} else if (link.path.contains("builds")) {
val index = link.pathSegments.indexOf("builds")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val buildId = link.pathSegments[index + 1]
navigator.onRouteToBuild(projectNamespace, projectName, buildId)
return
}
} else if (link.path.contains("milestones")) {
val index = link.pathSegments.indexOf("milestones")
if (index > 1 && index < link.pathSegments.size) {
val projectNamespace = link.pathSegments[index - 2]
val projectName = link.pathSegments[index - 1]
val milestoneId = link.pathSegments[index + 1]
navigator.onRouteToMilestone(projectNamespace, projectName, milestoneId)
return
}
}
navigator.onRouteUnknown(link)
}
}
apply plugin: 'com.github.ben-manes.versions'
apply plugin: 'com.commit451.updatewrapper'
buildscript {
ext.kotlinVersion = '1.2.41'
repositories {
Loading
Loading
@@ -8,10 +7,9 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.android.tools.build:gradle:3.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath 'com.github.ben-manes:gradle-versions-plugin:0.17.0'
classpath 'com.github.Commit451:updatewrapper:1.2.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