Skip to content
Snippets Groups Projects
Commit 4cdc3b24 authored by John Carlson's avatar John Carlson
Browse files

Merge branch 'develop'

parents a5b16b56 3187f690
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 438 additions and 329 deletions
Change Log
==========
 
Version 2.4.11
----------------------------
- Reverse the order of notes on merge requests and issues to make it more logical, like a chat app
- Crash fixes related to viewing a project
- Fix issue with Android Oreo auto-fill
- Adding a comment to a merge request or accepting one was not working. Now it will!
Version 2.4.10
----------------------------
 
Loading
Loading
Loading
Loading
@@ -18,7 +18,7 @@ apply plugin: 'io.fabric'
 
def versionMajor = 2
def versionMinor = 4
def versionPatch = 10
def versionPatch = 11
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
 
android {
Loading
Loading
@@ -98,9 +98,9 @@ android {
}
 
ext {
supportLibVersion = '26.0.1'
supportLibVersion = '26.0.2'
retrofitVersion = '2.3.0'
okHttpVersion = '3.8.1'
okHttpVersion = '3.9.0'
butterknifeVersion = '8.8.1'
parcelerVersion = '1.1.9'
reptarVersion = '2.5.1'
Loading
Loading
@@ -190,7 +190,7 @@ dependencies {
 
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
 
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.1'
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2'
 
implementation 'com.github.Jawnnypoo:PhysicsLayout:2.1.0'
 
Loading
Loading
@@ -213,7 +213,7 @@ dependencies {
exclude group: 'org.json', module: 'json'
}
 
implementation 'com.github.jkwiecien:EasyImage:2.0.2'
implementation 'com.github.jkwiecien:EasyImage:2.0.3'
 
implementation 'com.atlassian.commonmark:commonmark:0.9.0'
 
Loading
Loading
@@ -230,7 +230,7 @@ dependencies {
exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}
 
androidTestImplementation ('com.android.support.test:runner:1.0.0') {
androidTestImplementation ('com.android.support.test:runner:1.0.1') {
exclude group:'com.android.support', module:'support-annotations'
}
}
package com.commit451.gitlab.activity
 
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.design.widget.TabLayout
import android.support.v4.view.ViewPager
import android.support.v7.widget.Toolbar
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import butterknife.BindView
import butterknife.ButterKnife
Loading
Loading
@@ -22,28 +18,20 @@ import com.commit451.addendum.parceler.getParcelerParcelableExtra
import com.commit451.addendum.parceler.putParcelerParcelableExtra
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.adapter.IssueDetailsAdapter
import com.commit451.gitlab.api.response.FileUploadResponse
import com.commit451.gitlab.adapter.IssuePagerAdapter
import com.commit451.gitlab.event.IssueChangedEvent
import com.commit451.gitlab.event.IssueReloadEvent
import com.commit451.gitlab.extension.getUrl
import com.commit451.gitlab.extension.setup
import com.commit451.gitlab.model.api.Issue
import com.commit451.gitlab.model.api.Note
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.navigation.Navigator
import com.commit451.gitlab.rx.CustomCompleteObserver
import com.commit451.gitlab.rx.CustomResponseSingleObserver
import com.commit451.gitlab.rx.CustomSingleObserver
import com.commit451.gitlab.util.IntentUtil
import com.commit451.gitlab.util.LinkHeaderParser
import com.commit451.gitlab.view.SendMessageView
import com.commit451.teleprinter.Teleprinter
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.Subscribe
import retrofit2.Response
import timber.log.Timber
 
/**
Loading
Loading
@@ -55,11 +43,6 @@ class IssueActivity : BaseActivity() {
 
private val EXTRA_PROJECT = "extra_project"
private val EXTRA_SELECTED_ISSUE = "extra_selected_issue"
private val EXTRA_PROJECT_NAMESPACE = "project_namespace"
private val EXTRA_PROJECT_NAME = "project_name"
private val EXTRA_ISSUE_IID = "extra_issue_iid"
private val REQUEST_ATTACH = 1
 
fun newIntent(context: Context, project: Project, issue: Issue): Intent {
val intent = Intent(context, IssueActivity::class.java)
Loading
Loading
@@ -67,53 +50,24 @@ class IssueActivity : BaseActivity() {
intent.putParcelerParcelableExtra(EXTRA_SELECTED_ISSUE, issue)
return intent
}
fun newIntent(context: Context, namespace: String, projectName: String, issueIid: String): Intent {
val intent = Intent(context, IssueActivity::class.java)
intent.putExtra(EXTRA_PROJECT_NAMESPACE, namespace)
intent.putExtra(EXTRA_PROJECT_NAME, projectName)
intent.putExtra(EXTRA_ISSUE_IID, issueIid)
return intent
}
}
 
@BindView(R.id.root) lateinit var root: ViewGroup
@BindView(R.id.toolbar) lateinit var toolbar: Toolbar
@BindView(R.id.issue_title) lateinit var textTitle: TextView
@BindView(R.id.swipe_layout) lateinit var swipeRefreshLayout: SwipeRefreshLayout
@BindView(R.id.list) lateinit var listNotes: RecyclerView
@BindView(R.id.send_message_view) lateinit var sendMessageView: SendMessageView
@BindView(R.id.tabs) lateinit var tabLayout: TabLayout
@BindView(R.id.pager) lateinit var viewPager: ViewPager
@BindView(R.id.progress) lateinit var progress: View
@BindView(R.id.toolbar_title) lateinit var toolbarTitle: TextView
@BindView(R.id.toolbar_subtitle) lateinit var toolbarSubTitle: TextView
 
lateinit var menuItemOpenClose: MenuItem
lateinit var adapterIssueDetails: IssueDetailsAdapter
lateinit var layoutManagerNotes: LinearLayoutManager
lateinit var teleprinter: Teleprinter
 
var project: Project? = null
var issue: Issue? = null
var issueIid: String? = null
var loading: Boolean = false
var nextPageUrl: Uri? = null
val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val visibleItemCount = layoutManagerNotes.childCount
val totalItemCount = layoutManagerNotes.itemCount
val firstVisibleItem = layoutManagerNotes.findFirstVisibleItemPosition()
if (firstVisibleItem + visibleItemCount >= totalItemCount && !loading && nextPageUrl != null) {
loadMoreNotes()
}
}
}
lateinit var project: Project
lateinit var issue: Issue
 
val onMenuItemClickListener = Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_share -> {
IntentUtil.share(root, issue!!.getUrl(project!!))
IntentUtil.share(root, issue.getUrl(project))
return@OnMenuItemClickListener true
}
R.id.action_close -> {
Loading
Loading
@@ -121,7 +75,7 @@ class IssueActivity : BaseActivity() {
return@OnMenuItemClickListener true
}
R.id.action_delete -> {
App.get().gitLab.deleteIssue(project!!.id, issue!!.iid)
App.get().gitLab.deleteIssue(project.id, issue.iid)
.setup(bindToLifecycle())
.subscribe(object : CustomCompleteObserver() {
 
Loading
Loading
@@ -148,9 +102,7 @@ class IssueActivity : BaseActivity() {
fun onEditIssueClick() {
val project = project
val issue = issue
if (project != null && issue != null) {
Navigator.navigateToEditIssue(this@IssueActivity, project, issue)
}
Navigator.navigateToEditIssue(this@IssueActivity, project, issue)
}
 
override fun onCreate(savedInstanceState: Bundle?) {
Loading
Loading
@@ -160,6 +112,9 @@ class IssueActivity : BaseActivity() {
teleprinter = Teleprinter(this)
App.bus().register(this)
 
project = intent.getParcelerParcelableExtra<Project>(EXTRA_PROJECT)!!
issue = intent.getParcelerParcelableExtra<Issue>(EXTRA_SELECTED_ISSUE)!!
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
toolbar.inflateMenu(R.menu.share)
Loading
Loading
@@ -168,83 +123,15 @@ class IssueActivity : BaseActivity() {
menuItemOpenClose = toolbar.menu.findItem(R.id.action_close)
toolbar.setOnMenuItemClickListener(onMenuItemClickListener)
 
layoutManagerNotes = LinearLayoutManager(this)
listNotes.layoutManager = layoutManagerNotes
listNotes.addOnScrollListener(onScrollListener)
sendMessageView.callback = object : SendMessageView.Callback {
override fun onSendClicked(message: String) {
postNote(message)
}
override fun onAttachmentClicked() {
Navigator.navigateToAttach(this@IssueActivity, project!!, REQUEST_ATTACH)
}
}
swipeRefreshLayout.setOnRefreshListener { loadNotes() }
val sectionsPagerAdapter = IssuePagerAdapter(
this,
supportFragmentManager,
project,
issue)
 
if (intent.hasExtra(EXTRA_SELECTED_ISSUE)) {
project = intent.getParcelerParcelableExtra<Project>(EXTRA_PROJECT)
issue = intent.getParcelerParcelableExtra<Issue>(EXTRA_SELECTED_ISSUE)
adapterIssueDetails = IssueDetailsAdapter(issue, project!!)
listNotes.adapter = adapterIssueDetails
bindIssue()
bindProject()
loadNotes()
} else if (intent.hasExtra(EXTRA_ISSUE_IID)) {
issueIid = intent.getStringExtra(EXTRA_ISSUE_IID)
val projectNamespace = intent.getStringExtra(EXTRA_PROJECT_NAMESPACE)
val projectName = intent.getStringExtra(EXTRA_PROJECT_NAME)
swipeRefreshLayout.isRefreshing = true
App.get().gitLab.getProject(projectNamespace, projectName)
.flatMap { project ->
this@IssueActivity.project = project
App.get().gitLab.getIssuesByIid(project.id)
}
.compose(this.bindToLifecycle<List<Issue>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<List<Issue>>() {
override fun error(t: Throwable) {
Timber.e(t)
swipeRefreshLayout.isRefreshing = false
Snackbar.make(root, getString(R.string.failed_to_load), Snackbar.LENGTH_SHORT)
.show()
}
override fun success(issues: List<Issue>) {
if (issues.isEmpty()) {
swipeRefreshLayout.isRefreshing = false
Snackbar.make(root, getString(R.string.failed_to_load), Snackbar.LENGTH_SHORT)
.show()
} else {
issue = issues[0]
adapterIssueDetails = IssueDetailsAdapter(issue, project!!)
listNotes.adapter = adapterIssueDetails
bindIssue()
bindProject()
loadNotes()
}
}
})
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_ATTACH ->
if (resultCode == Activity.RESULT_OK) {
val response = data?.getParcelerParcelableExtra<FileUploadResponse>(AttachActivity.KEY_FILE_UPLOAD_RESPONSE)!!
progress.visibility = View.GONE
sendMessageView.appendText(response.markdown)
} else {
Snackbar.make(root, R.string.failed_to_upload_file, Snackbar.LENGTH_LONG)
.show()
}
}
viewPager.adapter = sectionsPagerAdapter
tabLayout.setupWithViewPager(viewPager)
bindIssue()
}
 
override fun onDestroy() {
Loading
Loading
@@ -252,108 +139,18 @@ class IssueActivity : BaseActivity() {
super.onDestroy()
}
 
fun bindProject() {
toolbarSubTitle.text = project?.nameWithNamespace
}
fun bindIssue() {
setOpenCloseMenuStatus()
textTitle.text = issue?.title
toolbarTitle.text = getString(R.string.issue_number, issue?.iid)
if (issue?.isConfidential!!) {
toolbarTitle.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_visibility_off_white_24dp, 0)
}
adapterIssueDetails.updateIssue(issue!!)
}
fun loadNotes() {
swipeRefreshLayout.isRefreshing = true
loading = true
App.get().gitLab.getIssueNotes(project!!.id, issue!!.iid)
.compose(this.bindToLifecycle<Response<List<Note>>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomResponseSingleObserver<List<Note>>() {
override fun error(t: Throwable) {
loading = false
Timber.e(t)
swipeRefreshLayout.isRefreshing = false
Snackbar.make(root, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show()
}
override fun responseNonNullSuccess(notes: List<Note>) {
loading = false
swipeRefreshLayout.isRefreshing = false
nextPageUrl = LinkHeaderParser.parse(response()).next
adapterIssueDetails.setNotes(notes)
}
})
}
fun loadMoreNotes() {
loading = true
adapterIssueDetails.setLoading(true)
App.get().gitLab.getIssueNotes(nextPageUrl!!.toString())
.compose(this.bindToLifecycle<Response<List<Note>>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomResponseSingleObserver<List<Note>>() {
override fun error(t: Throwable) {
loading = false
Timber.e(t)
adapterIssueDetails.setLoading(false)
}
override fun responseNonNullSuccess(notes: List<Note>) {
loading = false
adapterIssueDetails.setLoading(false)
nextPageUrl = LinkHeaderParser.parse(response()).next
adapterIssueDetails.addNotes(notes)
}
})
}
fun postNote(message: String) {
if (message.isEmpty()) {
return
}
progress.visibility = View.VISIBLE
progress.alpha = 0.0f
progress.animate().alpha(1.0f)
// Clear text & collapse keyboard
teleprinter.hideKeyboard()
sendMessageView.clearText()
App.get().gitLab.addIssueNote(project!!.id, issue!!.iid, message)
.setup(bindToLifecycle())
.subscribe(object : CustomSingleObserver<Note>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.visibility = View.GONE
Snackbar.make(root, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show()
}
override fun success(note: Note) {
progress.visibility = View.GONE
adapterIssueDetails.addNote(note)
listNotes.smoothScrollToPosition(IssueDetailsAdapter.headerCount)
}
})
toolbar.title = getString(R.string.issue_number, issue?.iid)
toolbar.subtitle = project.nameWithNamespace
}
 
fun closeOrOpenIssue() {
progress.visibility = View.VISIBLE
if (issue!!.state == Issue.STATE_CLOSED) {
updateIssueStatus(App.get().gitLab.updateIssueStatus(project!!.id, issue!!.iid, Issue.STATE_REOPEN))
if (issue.state == Issue.STATE_CLOSED) {
updateIssueStatus(App.get().gitLab.updateIssueStatus(project.id, issue.iid, Issue.STATE_REOPEN))
} else {
updateIssueStatus(App.get().gitLab.updateIssueStatus(project!!.id, issue!!.iid, Issue.STATE_CLOSE))
updateIssueStatus(App.get().gitLab.updateIssueStatus(project.id, issue.iid, Issue.STATE_CLOSE))
}
}
 
Loading
Loading
@@ -375,21 +172,19 @@ class IssueActivity : BaseActivity() {
App.bus().post(IssueChangedEvent(this@IssueActivity.issue!!))
App.bus().post(IssueReloadEvent())
setOpenCloseMenuStatus()
loadNotes()
}
})
}
 
fun setOpenCloseMenuStatus() {
menuItemOpenClose.setTitle(if (issue!!.state == Issue.STATE_CLOSED) R.string.reopen else R.string.close)
menuItemOpenClose.setTitle(if (issue.state == Issue.STATE_CLOSED) R.string.reopen else R.string.close)
}
 
@Subscribe
fun onEvent(event: IssueChangedEvent) {
if (issue!!.id == event.issue.id) {
if (issue.id == event.issue.id) {
issue = event.issue
bindIssue()
loadNotes()
}
}
}
Loading
Loading
@@ -31,11 +31,13 @@ class LoadSomeInfoActivity : BaseActivity() {
private val EXTRA_MERGE_REQUEST = "merge_request"
private val EXTRA_BUILD_ID = "build_id"
private val EXTRA_MILESTONE_ID = "milestone_id"
private val EXTRA_ISSUE_ID = "issue_id"
 
private val LOAD_TYPE_DIFF = 0
private val LOAD_TYPE_MERGE_REQUEST = 1
private val LOAD_TYPE_BUILD = 2
private val LOAD_TYPE_MILESTONE = 3
private val LOAD_TYPE_ISSUE = 4
 
fun newIntent(context: Context, namespace: String, projectName: String, commitSha: String): Intent {
val intent = Intent(context, LoadSomeInfoActivity::class.java)
Loading
Loading
@@ -46,6 +48,15 @@ class LoadSomeInfoActivity : BaseActivity() {
return intent
}
 
fun newIssueIntent(context: Context, namespace: String, projectName: String, issueId: String): Intent {
val intent = Intent(context, LoadSomeInfoActivity::class.java)
intent.putExtra(EXTRA_PROJECT_NAMESPACE, namespace)
intent.putExtra(EXTRA_PROJECT_NAME, projectName)
intent.putExtra(EXTRA_ISSUE_ID, issueId)
intent.putExtra(EXTRA_LOAD_TYPE, LOAD_TYPE_ISSUE)
return intent
}
fun newMergeRequestIntent(context: Context, namespace: String, projectName: String, mergeRequestId: String): Intent {
val intent = Intent(context, LoadSomeInfoActivity::class.java)
intent.putExtra(EXTRA_PROJECT_NAMESPACE, namespace)
Loading
Loading
@@ -94,7 +105,7 @@ class LoadSomeInfoActivity : BaseActivity() {
Timber.d("Loading some info type: %d", loadType)
 
when (loadType) {
LOAD_TYPE_DIFF, LOAD_TYPE_MERGE_REQUEST, LOAD_TYPE_BUILD, LOAD_TYPE_MILESTONE -> {
LOAD_TYPE_DIFF, LOAD_TYPE_MERGE_REQUEST, LOAD_TYPE_BUILD, LOAD_TYPE_MILESTONE, LOAD_TYPE_ISSUE -> {
val namespace = intent.getStringExtra(EXTRA_PROJECT_NAMESPACE)
val project = intent.getStringExtra(EXTRA_PROJECT_NAME)
App.get().gitLab.getProject(namespace, project)
Loading
Loading
@@ -122,6 +133,24 @@ class LoadSomeInfoActivity : BaseActivity() {
fun loadNextPart(response: Project) {
project = response
when (loadType) {
LOAD_TYPE_ISSUE -> {
val issueId = intent.getStringExtra(EXTRA_ISSUE_ID)
App.get().gitLab.getIssue(response.id, issueId)
.setup(bindToLifecycle())
.subscribe(object : CustomSingleObserver<Issue>() {
override fun error(t: Throwable) {
Timber.e(t)
this@LoadSomeInfoActivity.onError()
}
override fun success(issue: Issue) {
Navigator.navigateToIssue(this@LoadSomeInfoActivity, project!!, issue)
finish()
}
})
return
}
LOAD_TYPE_DIFF -> {
val sha = intent.getStringExtra(EXTRA_COMMIT_SHA)
App.get().gitLab.getCommit(response.id, sha)
Loading
Loading
Loading
Loading
@@ -307,7 +307,7 @@ class LoginActivity : BaseActivity() {
} else {
textInputLayoutUrl.error = null
}
if (url[url.length - 1] != '/') {
if (!url.endsWith("/")) {
textInputLayoutUrl.error = getString(R.string.please_end_your_url_with_a_slash)
return false
} else {
Loading
Loading
@@ -392,9 +392,9 @@ class LoginActivity : BaseActivity() {
d.findViewById<TextView>(android.R.id.message).movementMethod = LinkMovementMethod.getInstance()
} else if (t is SSLPeerUnverifiedException && t.message?.toLowerCase()!!.contains("hostname")) {
account.trustedHostname = null
val hostNameVerifier = gitLab?.client?.hostnameVerifier() as CustomHostnameVerifier
val finalHostname = hostNameVerifier.lastFailedHostname
val d = AlertDialog.Builder(this)
val hostNameVerifier = gitLab?.client?.hostnameVerifier() as? CustomHostnameVerifier
val finalHostname = hostNameVerifier?.lastFailedHostname
val dialog = AlertDialog.Builder(this)
.setTitle(R.string.hostname_title)
.setMessage(R.string.hostname_message)
.setPositiveButton(R.string.ok_button) { dialog, _ ->
Loading
Loading
@@ -408,7 +408,7 @@ class LoginActivity : BaseActivity() {
.setNegativeButton(R.string.cancel_button) { dialog, _ -> dialog.dismiss() }
.show()
 
d.findViewById<TextView>(android.R.id.message).movementMethod = LinkMovementMethod.getInstance()
dialog.findViewById<TextView>(android.R.id.message).movementMethod = LinkMovementMethod.getInstance()
} else if (t is ConnectException) {
Snackbar.make(root, t.message!!, Snackbar.LENGTH_LONG)
.show()
Loading
Loading
Loading
Loading
@@ -87,7 +87,7 @@ class MergeRequestActivity : BaseActivity() {
 
fun merge() {
progress.visibility = View.VISIBLE
App.get().gitLab.acceptMergeRequest(project.id, mergeRequest.id)
App.get().gitLab.acceptMergeRequest(project.id, mergeRequest.iid)
.setup(bindToLifecycle())
.subscribe(object : CustomResponseSingleObserver<MergeRequest>() {
 
Loading
Loading
Loading
Loading
@@ -26,7 +26,8 @@ class RoutingActivity : BaseActivity() {
val navigator = object : RoutingNavigator {
override fun onRouteToIssue(projectNamespace: String, projectName: String, issueIid: String) {
Timber.d("Routing to issue")
Navigator.navigateToIssue(this@RoutingActivity, projectNamespace, projectName, issueIid)
startActivity(LoadSomeInfoActivity.newIssueIntent(this@RoutingActivity, projectNamespace, projectName, issueIid))
overridePendingTransition(R.anim.fade_in, R.anim.do_nothing)
}
 
override fun onRouteToCommit(projectNamespace: String, projectName: String, commitSha: String) {
Loading
Loading
Loading
Loading
@@ -32,7 +32,7 @@ class IssueLabelsAdapter(private val listener: IssueLabelsAdapter.Listener) : Re
return values.size
}
 
fun setLabels(labels: Collection<String>) {
fun setLabels(labels: Collection<String>?) {
values.clear()
addLabels(labels)
}
Loading
Loading
package com.commit451.gitlab.adapter
import android.content.Context
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
import com.commit451.gitlab.R
import com.commit451.gitlab.fragment.IssueDetailsFragment
import com.commit451.gitlab.fragment.IssueDiscussionFragment
import com.commit451.gitlab.model.api.Issue
import com.commit451.gitlab.model.api.Project
/**
* Issue Pager Adapter
*/
class IssuePagerAdapter(context: Context, fm: FragmentManager, private val project: Project, private val issue: Issue) : FragmentPagerAdapter(fm) {
private val titles: Array<String> = context.resources.getStringArray(R.array.issue_tabs)
override fun getItem(position: Int): Fragment {
when (position) {
0 -> return IssueDetailsFragment.newInstance(project, issue)
1 -> return IssueDiscussionFragment.newInstance(project, issue)
}
throw IllegalStateException("Position exceeded on view pager")
}
override fun getCount(): Int {
return titles.size
}
override fun getPageTitle(position: Int): CharSequence {
return titles[position]
}
}
\ No newline at end of file
Loading
Loading
@@ -7,6 +7,7 @@ import android.support.v4.app.FragmentPagerAdapter
 
import com.commit451.gitlab.R
import com.commit451.gitlab.fragment.MergeRequestCommitsFragment
import com.commit451.gitlab.fragment.MergeRequestDetailsFragment
import com.commit451.gitlab.fragment.MergeRequestDiscussionFragment
import com.commit451.gitlab.model.api.MergeRequest
import com.commit451.gitlab.model.api.Project
Loading
Loading
@@ -20,8 +21,9 @@ class MergeRequestSectionsPagerAdapter(context: Context, fm: FragmentManager, pr
override fun getItem(position: Int): Fragment {
 
when (position) {
0 -> return MergeRequestDiscussionFragment.newInstance(project, mergeRequest)
1 -> return MergeRequestCommitsFragment.newInstance(project, mergeRequest)
0 -> return MergeRequestDetailsFragment.newInstance(project, mergeRequest)
1 -> return MergeRequestDiscussionFragment.newInstance(project, mergeRequest)
2 -> return MergeRequestCommitsFragment.newInstance(project, mergeRequest)
}
 
throw IllegalStateException("Position exceeded on view pager")
Loading
Loading
Loading
Loading
@@ -2,11 +2,8 @@ package com.commit451.gitlab.adapter
 
import android.support.v7.widget.RecyclerView
import android.view.ViewGroup
import com.commit451.gitlab.model.api.Issue
import com.commit451.gitlab.model.api.Note
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.viewHolder.IssueHeaderViewHolder
import com.commit451.gitlab.viewHolder.IssueLabelsViewHolder
import com.commit451.gitlab.viewHolder.LoadingFooterViewHolder
import com.commit451.gitlab.viewHolder.NoteViewHolder
import java.util.*
Loading
Loading
@@ -14,16 +11,13 @@ import java.util.*
/**
* Nice notes
*/
class IssueDetailsAdapter(private var issue: Issue?, private val project: Project) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
class NotesAdapter(private val project: Project) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 
companion object {
 
private val TYPE_HEADER = 0
private val TYPE_HEADER_LABEL = 1
private val TYPE_COMMENT = 2
private val TYPE_FOOTER = 3
 
val headerCount = 2
private val FOOTER_COUNT = 1
}
 
Loading
Loading
@@ -31,11 +25,7 @@ class IssueDetailsAdapter(private var issue: Issue?, private val project: Projec
private var loading = false
 
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == TYPE_HEADER) {
return IssueHeaderViewHolder.inflate(parent)
} else if (viewType == TYPE_HEADER_LABEL) {
return IssueLabelsViewHolder.inflate(parent)
} else if (viewType == TYPE_COMMENT) {
if (viewType == TYPE_COMMENT) {
return NoteViewHolder.inflate(parent)
} else if (viewType == TYPE_FOOTER) {
return LoadingFooterViewHolder.inflate(parent)
Loading
Loading
@@ -44,11 +34,7 @@ class IssueDetailsAdapter(private var issue: Issue?, private val project: Projec
}
 
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is IssueHeaderViewHolder) {
holder.bind(issue!!, project)
} else if (holder is IssueLabelsViewHolder) {
holder.bind(issue!!.labels!!)
} else if (holder is NoteViewHolder) {
if (holder is NoteViewHolder) {
val note = getNoteAt(position)
holder.bind(note, project)
} else if (holder is LoadingFooterViewHolder) {
Loading
Loading
@@ -57,15 +43,11 @@ class IssueDetailsAdapter(private var issue: Issue?, private val project: Projec
}
 
override fun getItemCount(): Int {
return notes.size + headerCount + FOOTER_COUNT
return notes.size + FOOTER_COUNT
}
 
override fun getItemViewType(position: Int): Int {
if (position == 0) {
return TYPE_HEADER
} else if (position == 1) {
return TYPE_HEADER_LABEL
} else if (position == headerCount + notes.size) {
if (position == notes.size) {
return TYPE_FOOTER
} else {
return TYPE_COMMENT
Loading
Loading
@@ -73,7 +55,7 @@ class IssueDetailsAdapter(private var issue: Issue?, private val project: Projec
}
 
fun getNoteAt(position: Int): Note {
return notes[position - headerCount]
return notes[position]
}
 
fun setNotes(notes: List<Note>) {
Loading
Loading
@@ -84,26 +66,17 @@ class IssueDetailsAdapter(private var issue: Issue?, private val project: Projec
fun addNotes(notes: List<Note>) {
if (!notes.isEmpty()) {
this.notes.addAll(notes)
notifyItemRangeChanged(headerCount, headerCount + this.notes.size)
notifyItemRangeChanged(0, this.notes.size)
}
}
 
fun addNote(note: Note) {
notes.addFirst(note)
notifyItemInserted(headerCount)
}
fun updateIssue(issue: Issue) {
val oldLabels = this.issue!!.labels
this.issue = issue
notifyItemChanged(0)
if (oldLabels!!.size != this.issue!!.labels!!.size) {
notifyItemChanged(1)
}
notifyItemInserted(0)
}
 
fun setLoading(loading: Boolean) {
this.loading = loading
notifyItemChanged(notes.size + headerCount)
notifyItemChanged(notes.size)
}
}
Loading
Loading
@@ -238,9 +238,6 @@ interface GitLabService {
fun getIssue(@Path("id") projectId: Long,
@Path("issue_id") issueId: String): Single<Issue>
 
@GET(API_VERSION + "/projects/{id}/issues")
fun getIssuesByIid(@Path("id") projectId: Long): Single<List<Issue>>
@FormUrlEncoded
@POST(API_VERSION + "/projects/{id}/issues")
fun createIssue(@Path("id") projectId: Long,
Loading
Loading
Loading
Loading
@@ -10,7 +10,7 @@ object MoshiProvider {
val moshi: Moshi by lazy {
Moshi.Builder()
.add(DashDateAdapter())
.add(Date::class.java, Rfc3339DateJsonAdapter())
.add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe())
.build()
}
}
\ No newline at end of file
Loading
Loading
@@ -20,8 +20,7 @@ object OkHttpClientFactory {
* @return a configured [okhttp3.OkHttpClient.Builder]
*/
fun create(account: Account, includeSignInAuthenticator: Boolean = true): OkHttpClient.Builder {
// Do we even need a custom trust manager?
// Yep. Otherwise SSL won't work properly with some configurations :) -Michi
// A custom trust manager, otherwise SSL won't work properly with some configurations
val customTrustManager = CustomTrustManager()
customTrustManager.setTrustedCertificate(account.trustedCertificate)
customTrustManager.setTrustedHostname(account.trustedHostname)
Loading
Loading
Loading
Loading
@@ -134,7 +134,7 @@ class BuildsFragment : ButterKnifeFragment() {
nextPageUrl = null
loading = true
App.get().gitLab.getBuilds(project!!.id, scope)
.setup(bindUntilEvent(FragmentEvent.DESTROY_VIEW))
.setup(bindUntilEvent(FragmentEvent.STOP))
.subscribe(object : CustomResponseSingleObserver<List<Build>>() {
 
override fun error(e: Throwable) {
Loading
Loading
Loading
Loading
@@ -2,6 +2,7 @@ package com.commit451.gitlab.fragment
 
import android.net.Uri
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
Loading
Loading
@@ -64,7 +65,12 @@ class FeedFragment : ButterKnifeFragment() {
 
adapterFeed = FeedAdapter(object : FeedAdapter.Listener {
override fun onFeedEntryClicked(entry: Entry) {
Navigator.navigateToUrl(activity, entry.link.href, App.get().getAccount())
if (entry.link.href.isEmpty()) {
Snackbar.make(swipeRefreshLayout, R.string.not_a_valid_url, Snackbar.LENGTH_SHORT)
.show()
} else {
Navigator.navigateToUrl(activity, entry.link.href, App.get().getAccount())
}
}
})
listEntries.layoutManager = LinearLayoutManager(activity)
Loading
Loading
Loading
Loading
@@ -52,7 +52,7 @@ class FilesFragment : ButterKnifeFragment() {
lateinit var adapterBreadcrumb: BreadcrumbAdapter
 
var project: Project? = null
lateinit var ref: String
var ref: String? = null
var currentPath = ""
 
val filesAdapterListener = object : FileAdapter.Listener {
Loading
Loading
@@ -62,30 +62,30 @@ class FilesFragment : ButterKnifeFragment() {
 
override fun onFileClicked(treeItem: RepositoryTreeObject) {
val path = currentPath + treeItem.name
Navigator.navigateToFile(activity, project!!.id, path, ref)
Navigator.navigateToFile(activity, project!!.id, path, ref!!)
}
 
override fun onCopyClicked(treeItem: RepositoryTreeObject) {
val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
 
// Creates a new text clip to put on the clipboard
val clip = ClipData.newPlainText(treeItem.name, treeItem.getUrl(project!!, ref, currentPath).toString())
val clip = ClipData.newPlainText(treeItem.name, treeItem.getUrl(project!!, ref!!, currentPath).toString())
clipboard.primaryClip = clip
Snackbar.make(root, R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT)
.show()
}
 
override fun onShareClicked(treeItem: RepositoryTreeObject) {
IntentUtil.share(view!!, treeItem.getUrl(project!!, ref, currentPath))
IntentUtil.share(view!!, treeItem.getUrl(project!!, ref!!, currentPath))
}
 
override fun onOpenInBrowserClicked(treeItem: RepositoryTreeObject) {
IntentUtil.openPage(activity as BaseActivity, treeItem.getUrl(project!!, ref, currentPath).toString(), App.get().currentAccount)
IntentUtil.openPage(activity as BaseActivity, treeItem.getUrl(project!!, ref!!, currentPath).toString(), App.get().currentAccount)
}
}
 
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_files, container, false)
return inflater?.inflate(R.layout.fragment_files, container, false)
}
 
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
Loading
Loading
@@ -104,7 +104,7 @@ class FilesFragment : ButterKnifeFragment() {
 
if (activity is ProjectActivity) {
project = (activity as ProjectActivity).project
ref = (activity as ProjectActivity).getRefRef()!!
ref = (activity as ProjectActivity).getRefRef()
loadData("")
} else {
throw IllegalStateException("Incorrect parent activity")
Loading
Loading
package com.commit451.gitlab.viewHolder
package com.commit451.gitlab.fragment
 
import android.support.v7.widget.RecyclerView
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import com.commit451.adapterflowlayout.AdapterFlowLayout
import com.commit451.addendum.parceler.getParcelerParcelable
import com.commit451.addendum.parceler.putParcelerParcelable
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.adapter.IssueLabelsAdapter
import com.commit451.gitlab.event.IssueChangedEvent
import com.commit451.gitlab.extension.setMarkdownText
import com.commit451.gitlab.model.api.Issue
import com.commit451.gitlab.model.api.Project
Loading
Loading
@@ -17,29 +21,70 @@ import com.commit451.gitlab.transformation.CircleTransformation
import com.commit451.gitlab.util.DateUtil
import com.commit451.gitlab.util.ImageUtil
import com.commit451.gitlab.util.InternalLinkMovementMethod
import com.commit451.gitlab.viewHolder.IssueLabelViewHolder
import org.greenrobot.eventbus.Subscribe
 
/**
* Header for an issue
* Shows the discussion of an issue
*/
class IssueHeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
class IssueDetailsFragment : ButterKnifeFragment() {
 
companion object {
 
fun inflate(parent: ViewGroup): IssueHeaderViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.header_issue, parent, false)
return IssueHeaderViewHolder(view)
private val KEY_PROJECT = "project"
private val KEY_ISSUE = "issue"
fun newInstance(project: Project, issue: Issue): IssueDetailsFragment {
val fragment = IssueDetailsFragment()
val args = Bundle()
args.putParcelerParcelable(KEY_PROJECT, project)
args.putParcelerParcelable(KEY_ISSUE, issue)
fragment.arguments = args
return fragment
}
}
 
@BindView(R.id.description) lateinit var textDescription: TextView
@BindView(R.id.root) lateinit var root: ViewGroup
@BindView(R.id.text_description) lateinit var textDescription: TextView
@BindView(R.id.author_image) lateinit var imageAuthor: ImageView
@BindView(R.id.author) lateinit var textAuthor: TextView
@BindView(R.id.milestone_root) lateinit var rootMilestone: ViewGroup
@BindView(R.id.milestone_text) lateinit var textMilestone: TextView
@BindView(R.id.list_labels) lateinit var listLabels: AdapterFlowLayout
lateinit var adapterLabels: IssueLabelsAdapter
lateinit var project: Project
lateinit var issue: Issue
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
project = arguments.getParcelerParcelable<Project>(KEY_PROJECT)!!
issue = arguments.getParcelerParcelable<Issue>(KEY_ISSUE)!!
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater?.inflate(R.layout.fragment_issue_details, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
 
init {
ButterKnife.bind(this, view)
adapterLabels = IssueLabelsAdapter(object : IssueLabelsAdapter.Listener {
override fun onLabelClicked(label: String, viewHolder: IssueLabelViewHolder) {
}
})
listLabels.adapter = adapterLabels
bind(issue, project)
App.bus().register(this)
}
override fun onDestroyView() {
App.bus().unregister(this)
super.onDestroyView()
}
 
fun bind(issue: Issue, project: Project) {
Loading
Loading
@@ -53,7 +98,7 @@ class IssueHeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
}
 
App.get().picasso
.load(ImageUtil.getAvatarUrl(issue.author, itemView.resources.getDimensionPixelSize(R.dimen.image_size)))
.load(ImageUtil.getAvatarUrl(issue.author, resources.getDimensionPixelSize(R.dimen.image_size)))
.transform(CircleTransformation())
.into(imageAuthor)
 
Loading
Loading
@@ -61,9 +106,9 @@ class IssueHeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
if (issue.author != null) {
author = issue.author!!.name + " "
}
author += itemView.resources.getString(R.string.created_issue)
author += resources.getString(R.string.created_issue)
if (issue.createdAt != null) {
author = author + " " + DateUtil.getRelativeTimeSpanString(itemView.context, issue.createdAt)
author = author + " " + DateUtil.getRelativeTimeSpanString(context, issue.createdAt)
}
textAuthor.text = author
if (issue.milestone != null) {
Loading
Loading
@@ -72,5 +117,14 @@ class IssueHeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
} else {
rootMilestone.visibility = View.GONE
}
adapterLabels.setLabels(issue.labels)
}
@Subscribe
fun onEvent(event: IssueChangedEvent) {
if (issue.iid == event.issue.iid) {
issue = event.issue
bind(issue, project)
}
}
}
\ No newline at end of file
Loading
Loading
@@ -18,11 +18,13 @@ import com.commit451.addendum.parceler.putParcelerParcelable
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.activity.AttachActivity
import com.commit451.gitlab.adapter.MergeRequestDetailAdapter
import com.commit451.gitlab.adapter.NotesAdapter
import com.commit451.gitlab.api.response.FileUploadResponse
import com.commit451.gitlab.event.MergeRequestChangedEvent
import com.commit451.gitlab.event.IssueChangedEvent
import com.commit451.gitlab.extension.setup
import com.commit451.gitlab.model.api.*
import com.commit451.gitlab.model.api.Issue
import com.commit451.gitlab.model.api.Note
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.navigation.TransitionFactory
import com.commit451.gitlab.rx.CustomResponseSingleObserver
import com.commit451.gitlab.rx.CustomSingleObserver
Loading
Loading
@@ -41,15 +43,15 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
companion object {
 
private val KEY_PROJECT = "project"
private val KEY_MERGE_REQUEST = "merge_request"
private val KEY_ISSUE = "issue"
 
private val REQUEST_ATTACH = 1
 
fun newInstance(project: Project, issue: Issue): IssueDiscussionFragment{
fun newInstance(project: Project, issue: Issue): IssueDiscussionFragment {
val fragment = IssueDiscussionFragment()
val args = Bundle()
args.putParcelerParcelable(KEY_PROJECT, project)
args.putParcelerParcelable(KEY_MERGE_REQUEST, issue)
args.putParcelerParcelable(KEY_ISSUE, issue)
fragment.arguments = args
return fragment
}
Loading
Loading
@@ -61,12 +63,12 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
@BindView(R.id.send_message_view) lateinit var sendMessageView: SendMessageView
@BindView(R.id.progress) lateinit var progress: View
 
lateinit var adapterMergeRequestDetail: MergeRequestDetailAdapter
lateinit var adapter: NotesAdapter
lateinit var layoutManagerNotes: LinearLayoutManager
lateinit var teleprinter: Teleprinter
 
lateinit var project: Project
lateinit var mergeRequest: MergeRequest
lateinit var issue: Issue
var nextPageUrl: Uri? = null
var loading: Boolean = false
 
Loading
Loading
@@ -85,21 +87,21 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
project = arguments.getParcelerParcelable<Project>(KEY_PROJECT)!!
mergeRequest = arguments.getParcelerParcelable<MergeRequest>(KEY_MERGE_REQUEST)!!
issue = arguments.getParcelerParcelable<Issue>(KEY_ISSUE)!!
}
 
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_merge_request_discussion, container, false)
return inflater?.inflate(R.layout.fragment_merge_request_discussion, container, false)
}
 
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
teleprinter = Teleprinter(activity)
 
adapterMergeRequestDetail = MergeRequestDetailAdapter(activity, mergeRequest, project)
layoutManagerNotes = LinearLayoutManager(activity)
adapter = NotesAdapter(project)
layoutManagerNotes = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
listNotes.layoutManager = layoutManagerNotes
listNotes.adapter = adapterMergeRequestDetail
listNotes.adapter = adapter
listNotes.addOnScrollListener(onScrollListener)
 
sendMessageView.callback = object : SendMessageView.Callback {
Loading
Loading
@@ -123,7 +125,7 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_ATTACH -> {
REQUEST_ATTACH -> {
if (resultCode == RESULT_OK) {
val response = data!!.getParcelerParcelableExtra<FileUploadResponse>(AttachActivity.KEY_FILE_UPLOAD_RESPONSE)!!
progress.visibility = View.GONE
Loading
Loading
@@ -143,7 +145,7 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
 
fun loadNotes() {
swipeRefreshLayout.isRefreshing = true
App.get().gitLab.getMergeRequestNotes(project.id, mergeRequest.iid)
App.get().gitLab.getIssueNotes(project.id, issue.iid)
.setup(bindUntilEvent(FragmentEvent.DESTROY_VIEW))
.subscribe(object : CustomResponseSingleObserver<List<Note>>() {
 
Loading
Loading
@@ -159,37 +161,37 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
swipeRefreshLayout.isRefreshing = false
loading = false
nextPageUrl = LinkHeaderParser.parse(response()).next
adapterMergeRequestDetail.setNotes(notes)
adapter.setNotes(notes)
}
})
}
 
fun loadMoreNotes() {
adapterMergeRequestDetail.setLoading(true)
App.get().gitLab.getMergeRequestNotes(nextPageUrl!!.toString())
adapter.setLoading(true)
App.get().gitLab.getIssueNotes(nextPageUrl!!.toString())
.setup(bindUntilEvent(FragmentEvent.DESTROY_VIEW))
.subscribe(object : CustomResponseSingleObserver<List<Note>>() {
 
override fun error(e: Throwable) {
loading = false
Timber.e(e)
adapterMergeRequestDetail.setLoading(false)
adapter.setLoading(false)
Snackbar.make(root, getString(R.string.connection_error), Snackbar.LENGTH_SHORT)
.show()
}
 
override fun responseNonNullSuccess(notes: List<Note>) {
adapterMergeRequestDetail.setLoading(false)
adapter.setLoading(false)
loading = false
nextPageUrl = LinkHeaderParser.parse(response()).next
adapterMergeRequestDetail.addNotes(notes)
adapter.addNotes(notes)
}
})
}
 
fun postNote(message: String) {
 
if (message.isNullOrBlank()) {
if (message.isBlank()) {
return
}
 
Loading
Loading
@@ -200,7 +202,7 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
teleprinter.hideKeyboard()
sendMessageView.clearText()
 
App.get().gitLab.addMergeRequestNote(project.id, mergeRequest.id, message)
App.get().gitLab.addIssueNote(project.id, issue.iid, message)
.setup(bindUntilEvent(FragmentEvent.DESTROY_VIEW))
.subscribe(object : CustomSingleObserver<Note>() {
 
Loading
Loading
@@ -213,16 +215,16 @@ class IssueDiscussionFragment : ButterKnifeFragment() {
 
override fun success(note: Note) {
progress.visibility = View.GONE
adapterMergeRequestDetail.addNote(note)
listNotes.smoothScrollToPosition(MergeRequestDetailAdapter.headerCount)
adapter.addNote(note)
listNotes.smoothScrollToPosition(0)
}
})
}
 
@Subscribe
fun onMergeRequestChangedEvent(event: MergeRequestChangedEvent) {
if (mergeRequest.id == event.mergeRequest.id) {
mergeRequest = event.mergeRequest
fun onEvent(event: IssueChangedEvent) {
if (issue.iid == event.issue.iid) {
issue = event.issue
loadNotes()
}
}
Loading
Loading
package com.commit451.gitlab.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import butterknife.BindView
import com.commit451.adapterflowlayout.AdapterFlowLayout
import com.commit451.addendum.parceler.getParcelerParcelable
import com.commit451.addendum.parceler.putParcelerParcelable
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.adapter.IssueLabelsAdapter
import com.commit451.gitlab.event.MergeRequestChangedEvent
import com.commit451.gitlab.extension.setMarkdownText
import com.commit451.gitlab.model.api.MergeRequest
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.transformation.CircleTransformation
import com.commit451.gitlab.util.DateUtil
import com.commit451.gitlab.util.ImageUtil
import com.commit451.gitlab.util.InternalLinkMovementMethod
import com.commit451.gitlab.viewHolder.IssueLabelViewHolder
import org.greenrobot.eventbus.Subscribe
/**
* Shows the discussion of an issue
*/
class MergeRequestDetailsFragment : ButterKnifeFragment() {
companion object {
private val KEY_PROJECT = "project"
private val KEY_MERGE_REQUEST = "merge_request"
fun newInstance(project: Project, mergeRequest: MergeRequest): MergeRequestDetailsFragment {
val fragment = MergeRequestDetailsFragment()
val args = Bundle()
args.putParcelerParcelable(KEY_PROJECT, project)
args.putParcelerParcelable(KEY_MERGE_REQUEST, mergeRequest)
fragment.arguments = args
return fragment
}
}
@BindView(R.id.root) lateinit var root: ViewGroup
@BindView(R.id.text_description) lateinit var textDescription: TextView
@BindView(R.id.author_image) lateinit var imageAuthor: ImageView
@BindView(R.id.author) lateinit var textAuthor: TextView
@BindView(R.id.milestone_root) lateinit var rootMilestone: ViewGroup
@BindView(R.id.milestone_text) lateinit var textMilestone: TextView
@BindView(R.id.list_labels) lateinit var listLabels: AdapterFlowLayout
lateinit var adapterLabels: IssueLabelsAdapter
lateinit var project: Project
lateinit var mergeRequest: MergeRequest
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
project = arguments.getParcelerParcelable<Project>(KEY_PROJECT)!!
mergeRequest = arguments.getParcelerParcelable<MergeRequest>(KEY_MERGE_REQUEST)!!
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater?.inflate(R.layout.fragment_issue_details, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapterLabels = IssueLabelsAdapter(object : IssueLabelsAdapter.Listener {
override fun onLabelClicked(label: String, viewHolder: IssueLabelViewHolder) {
}
})
listLabels.adapter = adapterLabels
bind(mergeRequest, project)
App.bus().register(this)
}
override fun onDestroyView() {
App.bus().unregister(this)
super.onDestroyView()
}
fun bind(mergeRequest: MergeRequest, project: Project) {
if (mergeRequest.description.isNullOrEmpty()) {
textDescription.visibility = View.GONE
} else {
textDescription.visibility = View.VISIBLE
textDescription.setMarkdownText(mergeRequest.description!!, project)
textDescription.movementMethod = InternalLinkMovementMethod(App.get().getAccount().serverUrl!!)
}
App.get().picasso
.load(ImageUtil.getAvatarUrl(mergeRequest.author, resources.getDimensionPixelSize(R.dimen.image_size)))
.transform(CircleTransformation())
.into(imageAuthor)
var author = ""
if (mergeRequest.author != null) {
author = mergeRequest.author!!.name + " "
}
author += resources.getString(R.string.created_issue)
if (mergeRequest.createdAt != null) {
author = author + " " + DateUtil.getRelativeTimeSpanString(context, mergeRequest.createdAt)
}
textAuthor.text = author
if (mergeRequest.milestone != null) {
rootMilestone.visibility = View.VISIBLE
textMilestone.text = mergeRequest.milestone!!.title
} else {
rootMilestone.visibility = View.GONE
}
adapterLabels.setLabels(mergeRequest.labels)
}
@Subscribe
fun onEvent(event: MergeRequestChangedEvent) {
if (mergeRequest.iid == event.mergeRequest.iid) {
mergeRequest = event.mergeRequest
bind(mergeRequest, project)
}
}
}
\ No newline at end of file
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