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.ATHUtil
|
|
|
|
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
|
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
|
2020-02-26 16:49:24 +00:00
|
|
|
import kotlinx.android.synthetic.main.activity_bug_report.*
|
|
|
|
import kotlinx.android.synthetic.main.bug_report_card_device_info.*
|
|
|
|
import kotlinx.android.synthetic.main.bug_report_card_report.*
|
2018-12-06 10:23:03 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
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() {
|
|
|
|
|
2019-12-08 14:35:03 +00:00
|
|
|
private var deviceInfo: DeviceInfo? = null
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
setDrawUnderStatusBar()
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
setContentView(R.layout.activity_bug_report)
|
|
|
|
setStatusbarColorAuto()
|
|
|
|
setNavigationbarColorAuto()
|
|
|
|
setTaskDescriptionColorAuto()
|
|
|
|
|
|
|
|
initViews()
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
|
|
|
|
|
|
|
|
deviceInfo = DeviceInfo(this)
|
|
|
|
airTextDeviceInfo.text = deviceInfo.toString()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun initViews() {
|
|
|
|
val accentColor = ThemeStore.accentColor(this)
|
|
|
|
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
|
|
|
|
toolbar.setBackgroundColor(primaryColor)
|
|
|
|
setSupportActionBar(toolbar)
|
|
|
|
ToolbarContentTintHelper.colorBackButton(toolbar)
|
|
|
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
|
|
TintHelper.setTintAuto(optionUseAccount, accentColor, false)
|
|
|
|
optionUseAccount?.setOnClickListener {
|
|
|
|
inputTitle.isEnabled = true
|
|
|
|
inputDescription.isEnabled = true
|
|
|
|
inputUsername.isEnabled = true
|
|
|
|
inputPassword.isEnabled = true
|
|
|
|
|
|
|
|
optionAnonymous.isChecked = false
|
|
|
|
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
|
|
|
|
override fun onHidden(fab: FloatingActionButton?) {
|
|
|
|
super.onHidden(fab)
|
2020-07-19 21:00:30 +00:00
|
|
|
sendFab.setImageResource(R.drawable.ic_send)
|
2019-12-08 14:35:03 +00:00
|
|
|
sendFab.show()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
TintHelper.setTintAuto(optionAnonymous, accentColor, false)
|
|
|
|
optionAnonymous.setOnClickListener {
|
|
|
|
inputTitle.isEnabled = false
|
|
|
|
inputDescription.isEnabled = false
|
|
|
|
inputUsername.isEnabled = false
|
|
|
|
inputPassword.isEnabled = false
|
|
|
|
|
|
|
|
optionUseAccount.isChecked = false
|
|
|
|
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
|
|
|
|
override fun onHidden(fab: FloatingActionButton?) {
|
|
|
|
super.onHidden(fab)
|
2020-07-19 21:00:30 +00:00
|
|
|
sendFab.setImageResource(R.drawable.ic_open_in_browser)
|
2019-12-08 14:35:03 +00:00
|
|
|
sendFab.show()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
inputPassword.setOnEditorActionListener { _, actionId, _ ->
|
|
|
|
if (actionId == EditorInfo.IME_ACTION_SEND) {
|
|
|
|
reportIssue()
|
|
|
|
return@setOnEditorActionListener true
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
|
|
|
|
|
|
|
|
TintHelper.setTintAuto(sendFab, accentColor, true)
|
|
|
|
sendFab.setOnClickListener { reportIssue() }
|
|
|
|
|
|
|
|
MaterialUtil.setTint(inputLayoutTitle, false)
|
|
|
|
MaterialUtil.setTint(inputLayoutDescription, false)
|
|
|
|
MaterialUtil.setTint(inputLayoutUsername, false)
|
|
|
|
MaterialUtil.setTint(inputLayoutPassword, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun reportIssue() {
|
|
|
|
if (optionUseAccount.isChecked) {
|
|
|
|
if (!validateInput()) return
|
|
|
|
val username = inputUsername.text.toString()
|
|
|
|
val password = inputPassword.text.toString()
|
|
|
|
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 (optionUseAccount.isChecked) {
|
|
|
|
if (TextUtils.isEmpty(inputUsername.text)) {
|
|
|
|
setError(inputLayoutUsername, R.string.bug_report_no_username)
|
|
|
|
hasErrors = true
|
|
|
|
} else {
|
|
|
|
removeError(inputLayoutUsername)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(inputPassword.text)) {
|
|
|
|
setError(inputLayoutPassword, R.string.bug_report_no_password)
|
|
|
|
hasErrors = true
|
|
|
|
} else {
|
|
|
|
removeError(inputLayoutPassword)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(inputTitle.text)) {
|
|
|
|
setError(inputLayoutTitle, R.string.bug_report_no_title)
|
|
|
|
hasErrors = true
|
|
|
|
} else {
|
|
|
|
removeError(inputLayoutTitle)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TextUtils.isEmpty(inputDescription.text)) {
|
|
|
|
setError(inputLayoutDescription, R.string.bug_report_no_description)
|
|
|
|
hasErrors = true
|
|
|
|
} else {
|
|
|
|
removeError(inputLayoutDescription)
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = inputTitle.text.toString()
|
|
|
|
val bugDescription = inputDescription.text.toString()
|
|
|
|
|
|
|
|
val extraInfo = ExtraInfo()
|
|
|
|
onSaveExtraInfo()
|
|
|
|
|
|
|
|
val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
|
|
|
|
val target = GithubTarget("h4h13", "RetroMusicPlayer")
|
|
|
|
|
|
|
|
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)
|
|
|
|
.setPositiveButton(android.R.string.ok, null)
|
|
|
|
.show()
|
|
|
|
RESULT_INVALID_TOKEN -> MaterialAlertDialogBuilder(context)
|
|
|
|
.setTitle(R.string.bug_report_failed)
|
|
|
|
.setMessage(R.string.bug_report_failed_invalid_token)
|
|
|
|
.setPositiveButton(android.R.string.ok, null).show()
|
|
|
|
RESULT_ISSUES_NOT_ENABLED -> MaterialAlertDialogBuilder(context)
|
|
|
|
.setTitle(R.string.bug_report_failed)
|
|
|
|
.setMessage(R.string.bug_report_failed_issues_not_available)
|
|
|
|
.setPositiveButton(android.R.string.ok, null)
|
|
|
|
|
|
|
|
else -> MaterialAlertDialogBuilder(context)
|
|
|
|
.setTitle(R.string.bug_report_failed)
|
|
|
|
.setMessage(R.string.bug_report_failed_unknown)
|
|
|
|
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
|
|
|
|
.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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-24 18:04:50 +00:00
|
|
|
|
2019-12-08 14:35:03 +00:00
|
|
|
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
|
|
|
|
private const val ISSUE_TRACKER_LINK = "https://github.com/h4h13/RetroMusicPlayer"
|
|
|
|
}
|
2018-12-06 10:23:03 +00:00
|
|
|
}
|