PlayerAndroid/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt

338 lines
13 KiB
Kotlin
Raw Normal View History

2020-10-06 08:46:04 +00:00
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
2019-04-20 05:29:45 +00:00
package code.name.monkey.retromusic.activities.bugreport
2018-12-06 10:23:03 +00:00
2019-12-01 15:27:01 +00:00
import android.app.Activity
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
2018-12-06 10:23:03 +00:00
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.view.MenuItem
import android.view.inputmethod.EditorInfo
import android.widget.Toast
2019-12-01 15:27:01 +00:00
import androidx.annotation.StringDef
import androidx.annotation.StringRes
2019-02-19 10:38:51 +00:00
import androidx.appcompat.app.AlertDialog
2018-12-06 10:23:03 +00:00
import code.name.monkey.appthemehelper.ThemeStore
2019-12-01 15:27:01 +00:00
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
2018-12-06 10:23:03 +00:00
import code.name.monkey.retromusic.R
2019-04-20 05:29:45 +00:00
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
2019-12-01 15:27:01 +00:00
import code.name.monkey.retromusic.activities.bugreport.model.DeviceInfo
import code.name.monkey.retromusic.activities.bugreport.model.Report
import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubLogin
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubTarget
import code.name.monkey.retromusic.databinding.ActivityBugReportBinding
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
2019-07-31 11:56:46 +00:00
import code.name.monkey.retromusic.misc.DialogAsyncTask
2020-05-24 18:04:50 +00:00
import com.google.android.material.dialog.MaterialAlertDialogBuilder
2018-12-06 10:23:03 +00:00
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputLayout
import org.eclipse.egit.github.core.Issue
2019-12-01 15:27:01 +00:00
import org.eclipse.egit.github.core.client.GitHubClient
import org.eclipse.egit.github.core.client.RequestException
2018-12-06 10:23:03 +00:00
import org.eclipse.egit.github.core.service.IssueService
import java.io.IOException
2018-12-06 10:23:03 +00:00
private const val RESULT_SUCCESS = "RESULT_OK"
private const val RESULT_BAD_CREDENTIALS = "RESULT_BAD_CREDENTIALS"
private const val RESULT_INVALID_TOKEN = "RESULT_INVALID_TOKEN"
private const val RESULT_ISSUES_NOT_ENABLED = "RESULT_ISSUES_NOT_ENABLED"
private const val RESULT_UNKNOWN = "RESULT_UNKNOWN"
2019-11-15 17:44:42 +00:00
@StringDef(
2019-12-30 11:01:50 +00:00
RESULT_SUCCESS,
RESULT_BAD_CREDENTIALS,
RESULT_INVALID_TOKEN,
RESULT_ISSUES_NOT_ENABLED,
RESULT_UNKNOWN
2019-11-15 17:44:42 +00:00
)
2018-12-06 10:23:03 +00:00
@Retention(AnnotationRetention.SOURCE)
private annotation class Result
open class BugReportActivity : AbsThemeActivity() {
private lateinit var binding: ActivityBugReportBinding
2019-12-08 14:35:03 +00:00
private var deviceInfo: DeviceInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBugReportBinding.inflate(layoutInflater)
setContentView(binding.root)
2019-12-08 14:35:03 +00:00
setTaskDescriptionColorAuto()
initViews()
if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
deviceInfo = DeviceInfo(this)
binding.cardDeviceInfo.airTextDeviceInfo.text = deviceInfo.toString()
2019-12-08 14:35:03 +00:00
}
private fun initViews() {
val accentColor = ThemeStore.accentColor(this)
setSupportActionBar(binding.toolbar)
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
2019-12-08 14:35:03 +00:00
supportActionBar?.setDisplayHomeAsUpEnabled(true)
TintHelper.setTintAuto(binding.cardReport.optionUseAccount, accentColor, false)
binding.cardReport.optionUseAccount.setOnClickListener {
binding.cardReport.inputTitle.isEnabled = true
binding.cardReport.inputDescription.isEnabled = true
binding.cardReport.inputUsername.isEnabled = true
binding.cardReport.inputPassword.isEnabled = true
binding.cardReport.optionAnonymous.isChecked = false
binding.sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
2019-12-08 14:35:03 +00:00
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
binding.sendFab.setImageResource(R.drawable.ic_send)
binding.sendFab.show()
2019-12-08 14:35:03 +00:00
}
})
}
TintHelper.setTintAuto(binding.cardReport.optionAnonymous, accentColor, false)
binding.cardReport.optionAnonymous.setOnClickListener {
binding.cardReport.inputTitle.isEnabled = false
binding.cardReport.inputDescription.isEnabled = false
binding.cardReport.inputUsername.isEnabled = false
binding.cardReport.inputPassword.isEnabled = false
binding.cardReport.optionUseAccount.isChecked = false
binding.sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
2019-12-08 14:35:03 +00:00
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
binding.sendFab.setImageResource(R.drawable.ic_open_in_browser)
binding.sendFab.show()
2019-12-08 14:35:03 +00:00
}
})
}
binding.cardReport.inputPassword.setOnEditorActionListener { _, actionId, _ ->
2019-12-08 14:35:03 +00:00
if (actionId == EditorInfo.IME_ACTION_SEND) {
reportIssue()
return@setOnEditorActionListener true
}
false
}
binding.cardDeviceInfo.airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
2019-12-08 14:35:03 +00:00
TintHelper.setTintAuto(binding.sendFab, accentColor, true)
binding.sendFab.setOnClickListener { reportIssue() }
2019-12-08 14:35:03 +00:00
MaterialUtil.setTint(binding.cardReport.inputLayoutTitle, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutDescription, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutUsername, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutPassword, false)
2019-12-08 14:35:03 +00:00
}
private fun reportIssue() {
if (binding.cardReport.optionUseAccount.isChecked) {
2019-12-08 14:35:03 +00:00
if (!validateInput()) return
val username = binding.cardReport.inputUsername.text.toString()
val password = binding.cardReport.inputPassword.text.toString()
2019-12-08 14:35:03 +00:00
sendBugReport(GithubLogin(username, password))
} else {
copyDeviceInfoToClipBoard()
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(ISSUE_TRACKER_LINK)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
}
private fun copyDeviceInfoToClipBoard() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
clipboard.setPrimaryClip(clip)
Toast.makeText(
2019-12-30 11:01:50 +00:00
this@BugReportActivity,
R.string.copied_device_info_to_clipboard,
Toast.LENGTH_LONG
2019-12-08 14:35:03 +00:00
).show()
}
private fun validateInput(): Boolean {
var hasErrors = false
if (binding.cardReport.optionUseAccount.isChecked) {
if (TextUtils.isEmpty(binding.cardReport.inputUsername.text)) {
setError(binding.cardReport.inputLayoutUsername, R.string.bug_report_no_username)
2019-12-08 14:35:03 +00:00
hasErrors = true
} else {
removeError(binding.cardReport.inputLayoutUsername)
2019-12-08 14:35:03 +00:00
}
if (TextUtils.isEmpty(binding.cardReport.inputPassword.text)) {
setError(binding.cardReport.inputLayoutPassword, R.string.bug_report_no_password)
2019-12-08 14:35:03 +00:00
hasErrors = true
} else {
removeError(binding.cardReport.inputLayoutPassword)
2019-12-08 14:35:03 +00:00
}
}
if (TextUtils.isEmpty(binding.cardReport.inputTitle.text)) {
setError(binding.cardReport.inputLayoutTitle, R.string.bug_report_no_title)
2019-12-08 14:35:03 +00:00
hasErrors = true
} else {
removeError(binding.cardReport.inputLayoutTitle)
2019-12-08 14:35:03 +00:00
}
if (TextUtils.isEmpty(binding.cardReport.inputDescription.text)) {
setError(binding.cardReport.inputLayoutDescription, R.string.bug_report_no_description)
2019-12-08 14:35:03 +00:00
hasErrors = true
} else {
removeError(binding.cardReport.inputLayoutDescription)
2019-12-08 14:35:03 +00:00
}
return !hasErrors
}
private fun setError(editTextLayout: TextInputLayout, @StringRes errorRes: Int) {
editTextLayout.error = getString(errorRes)
}
private fun removeError(editTextLayout: TextInputLayout) {
editTextLayout.error = null
}
private fun sendBugReport(login: GithubLogin) {
if (!validateInput()) return
val bugTitle = binding.cardReport.inputTitle.text.toString()
val bugDescription = binding.cardReport.inputDescription.text.toString()
2019-12-08 14:35:03 +00:00
val extraInfo = ExtraInfo()
onSaveExtraInfo()
val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
2021-07-10 01:18:35 +00:00
val target = GithubTarget("RetroMusicPlayer", "RetroMusicPlayer")
2019-12-08 14:35:03 +00:00
ReportIssueAsyncTask.report(this, report, target, login)
}
private fun onSaveExtraInfo() {}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
private class ReportIssueAsyncTask private constructor(
2019-12-30 11:01:50 +00:00
activity: Activity,
private val report: Report,
private val target: GithubTarget,
private val login: GithubLogin
2019-12-08 14:35:03 +00:00
) : DialogAsyncTask<Void, Void, String>(activity) {
2019-12-30 11:01:50 +00:00
2019-12-08 14:35:03 +00:00
override fun createDialog(context: Context): Dialog {
return AlertDialog.Builder(context).show()
}
@Result
override fun doInBackground(vararg params: Void): String {
val client: GitHubClient = if (login.shouldUseApiToken()) {
GitHubClient().setOAuth2Token(login.apiToken)
} else {
GitHubClient().setCredentials(login.username, login.password)
}
val issue = Issue().setTitle(report.title).setBody(report.description)
try {
IssueService(client).createIssue(target.username, target.repository, issue)
return RESULT_SUCCESS
} catch (e: RequestException) {
return when (e.status) {
STATUS_BAD_CREDENTIALS -> {
if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS
}
STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED
else -> {
e.printStackTrace()
RESULT_UNKNOWN
}
}
} catch (e: IOException) {
e.printStackTrace()
return RESULT_UNKNOWN
}
}
override fun onPostExecute(@Result result: String) {
super.onPostExecute(result)
val context = context ?: return
when (result) {
RESULT_SUCCESS -> tryToFinishActivity()
2020-05-24 18:04:50 +00:00
RESULT_BAD_CREDENTIALS -> MaterialAlertDialogBuilder(context)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_wrong_credentials)
2020-09-09 12:37:25 +00:00
.setPositiveButton(android.R.string.ok, null)
2020-05-24 18:04:50 +00:00
.show()
RESULT_INVALID_TOKEN -> MaterialAlertDialogBuilder(context)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_invalid_token)
2020-09-09 12:37:25 +00:00
.setPositiveButton(android.R.string.ok, null).show()
2020-05-24 18:04:50 +00:00
RESULT_ISSUES_NOT_ENABLED -> MaterialAlertDialogBuilder(context)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_issues_not_available)
2020-09-09 12:37:25 +00:00
.setPositiveButton(android.R.string.ok, null)
2020-05-24 18:04:50 +00:00
else -> MaterialAlertDialogBuilder(context)
.setTitle(R.string.bug_report_failed)
.setMessage(R.string.bug_report_failed_unknown)
2020-09-09 12:37:25 +00:00
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
2020-08-21 18:01:52 +00:00
.setNegativeButton(android.R.string.cancel) { _, _ -> tryToFinishActivity() }
2019-12-08 14:35:03 +00:00
}
}
private fun tryToFinishActivity() {
val context = context
if (context is Activity && !context.isFinishing) {
context.finish()
}
}
companion object {
fun report(
2019-12-30 11:01:50 +00:00
activity: Activity,
report: Report,
target: GithubTarget,
login: GithubLogin
2019-12-08 14:35:03 +00:00
) {
ReportIssueAsyncTask(activity, report, target, login).execute()
}
}
}
companion object {
private const val STATUS_BAD_CREDENTIALS = 401
private const val STATUS_ISSUES_NOT_ENABLED = 410
2021-07-10 01:18:35 +00:00
private const val ISSUE_TRACKER_LINK = "https://github.com/RetroMusicPlayer/RetroMusicPlayer"
2019-12-08 14:35:03 +00:00
}
2018-12-06 10:23:03 +00:00
}