BugReportActivity.kt 10 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * Copyright 2018 New Vector Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17
package im.vector.app.features.rageshake
18

Valere's avatar
Valere committed
19
20
import android.content.Context
import android.content.Intent
21
22
import android.view.Menu
import android.view.MenuItem
23
import android.widget.Toast
24
import androidx.core.view.isVisible
25
import androidx.core.widget.doOnTextChanged
26
27
import com.airbnb.mvrx.viewModel
import com.airbnb.mvrx.withState
28
29
30
import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.platform.VectorBaseActivity
31
import im.vector.app.databinding.ActivityBugReportBinding
Valere's avatar
Valere committed
32
import org.matrix.android.sdk.api.extensions.tryOrNull
33

34
import timber.log.Timber
35
import javax.inject.Inject
36
37
38
39

/**
 * Form to send a bug report
 */
40
class BugReportActivity : VectorBaseActivity<ActivityBugReportBinding>() {
41

42
43
44
45
    override fun injectWith(injector: ScreenComponent) {
        injector.inject(this)
    }

46
    override fun getBinding() = ActivityBugReportBinding.inflate(layoutInflater)
47

48
49
50
51
    @Inject lateinit var bugReportViewModelFactory: BugReportViewModel.Factory

    private val viewModel: BugReportViewModel by viewModel()

Valere's avatar
Valere committed
52
    private var reportType: ReportType = ReportType.BUG_REPORT
Benoit Marty's avatar
Benoit Marty committed
53

54
    override fun initUiAndData() {
55
        configureToolbar(views.bugReportToolbar)
56
        setupViews()
57

58
        if (bugReporter.screenshot != null) {
59
            views.bugReportScreenshotPreview.setImageBitmap(bugReporter.screenshot)
60
        } else {
61
62
63
            views.bugReportScreenshotPreview.isVisible = false
            views.bugReportButtonIncludeScreenshot.isChecked = false
            views.bugReportButtonIncludeScreenshot.isEnabled = false
64
        }
Benoit Marty's avatar
Benoit Marty committed
65

Valere's avatar
Valere committed
66
67
68
        reportType = intent.getStringExtra(REPORT_TYPE_EXTRA)?.let {
            tryOrNull { ReportType.valueOf(it) }
        } ?: ReportType.BUG_REPORT
Benoit Marty's avatar
Benoit Marty committed
69
70

        // Default screen is for bug report, so modify it for suggestion
Valere's avatar
Valere committed
71
72
73
        when (reportType) {
            ReportType.BUG_REPORT -> {
                supportActionBar?.setTitle(R.string.title_activity_bug_report)
Valere's avatar
Valere committed
74
                views.bugReportButtonContactMe.isVisible = true
Valere's avatar
Valere committed
75
76
77
            }
            ReportType.SUGGESTION -> {
                supportActionBar?.setTitle(R.string.send_suggestion)
Benoit Marty's avatar
Benoit Marty committed
78

Valere's avatar
Valere committed
79
80
81
82
83
84
85
86
                views.bugReportFirstText.setText(R.string.send_suggestion_content)
                views.bugReportTextInputLayout.hint = getString(R.string.send_suggestion_report_placeholder)
                views.bugReportButtonContactMe.isVisible = true

                hideBugReportOptions()
            }
            ReportType.SPACE_BETA_FEEDBACK -> {
                supportActionBar?.setTitle(R.string.send_feedback_space_title)
Benoit Marty's avatar
Benoit Marty committed
87

Valere's avatar
Valere committed
88
89
90
                views.bugReportFirstText.setText(R.string.send_feedback_space_info)
                views.bugReportTextInputLayout.hint = getString(R.string.feedback)
                views.bugReportButtonContactMe.isVisible = true
Benoit Marty's avatar
Benoit Marty committed
91

Valere's avatar
Valere committed
92
93
94
95
                hideBugReportOptions()
            }
        }
    }
Benoit Marty's avatar
Benoit Marty committed
96

Valere's avatar
Valere committed
97
98
    private fun hideBugReportOptions() {
        views.bugReportLogsDescription.isVisible = false
Benoit Marty's avatar
Benoit Marty committed
99

Valere's avatar
Valere committed
100
101
        views.bugReportButtonIncludeLogs.isChecked = false
        views.bugReportButtonIncludeLogs.isVisible = false
102

Valere's avatar
Valere committed
103
104
105
106
107
        views.bugReportButtonIncludeCrashLogs.isChecked = false
        views.bugReportButtonIncludeCrashLogs.isVisible = false

        views.bugReportButtonIncludeKeyShareHistory.isChecked = false
        views.bugReportButtonIncludeKeyShareHistory.isVisible = false
108
109
    }

110
    private fun setupViews() {
111
112
        views.bugReportEditText.doOnTextChanged { _, _, _, _ -> textChanged() }
        views.bugReportButtonIncludeScreenshot.setOnCheckedChangeListener { _, _ -> onSendScreenshotChanged() }
113
114
    }

115
116
117
118
    override fun getMenuRes() = R.menu.bug_report

    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
        menu.findItem(R.id.ic_action_send_bug_report)?.let {
119
            val isValid = !views.bugReportMaskView.isVisible
120
121
122
123
124
125
126
127
128
129
130

            it.isEnabled = isValid
            it.icon.alpha = if (isValid) 255 else 100
        }

        return super.onPrepareOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.ic_action_send_bug_report -> {
131
                if (views.bugReportEditText.text.toString().trim().length >= 10) {
132
133
                    sendBugReport()
                } else {
134
                    views.bugReportTextInputLayout.error = getString(R.string.bug_report_error_too_short)
135
                }
136
137
138
139
140
141
142
143
144
                return true
            }
        }
        return super.onOptionsItemSelected(item)
    }

    /**
     * Send the bug report
     */
145
    private fun sendBugReport() = withState(viewModel) { state ->
146
147
        views.bugReportScrollview.alpha = 0.3f
        views.bugReportMaskView.isVisible = true
148
149
150

        invalidateOptionsMenu()

151
152
        views.bugReportProgressTextView.isVisible = true
        views.bugReportProgressTextView.text = getString(R.string.send_bug_report_progress, "0")
153

154
155
        views.bugReportProgressView.isVisible = true
        views.bugReportProgressView.progress = 0
156

157
        bugReporter.sendBugReport(this,
Valere's avatar
Valere committed
158
                reportType,
159
160
161
162
163
                views.bugReportButtonIncludeLogs.isChecked,
                views.bugReportButtonIncludeCrashLogs.isChecked,
                views.bugReportButtonIncludeKeyShareHistory.isChecked,
                views.bugReportButtonIncludeScreenshot.isChecked,
                views.bugReportEditText.text.toString(),
164
                state.serverVersion,
Valere's avatar
Valere committed
165
                views.bugReportButtonContactMe.isChecked,
166
167
168
                object : BugReporter.IMXBugReportListener {
                    override fun onUploadFailed(reason: String?) {
                        try {
Dominic Fischer's avatar
Dominic Fischer committed
169
                            if (!reason.isNullOrEmpty()) {
Valere's avatar
Valere committed
170
171
172
173
174
                                when (reportType) {
                                    ReportType.BUG_REPORT          -> {
                                        Toast.makeText(this@BugReportActivity,
                                                getString(R.string.send_bug_report_failed, reason), Toast.LENGTH_LONG).show()
                                    }
Valere's avatar
Valere committed
175
                                    ReportType.SUGGESTION,
Valere's avatar
Valere committed
176
177
                                    ReportType.SPACE_BETA_FEEDBACK -> {
                                        Toast.makeText(this@BugReportActivity,
Valere's avatar
Valere committed
178
                                                getString(R.string.feedback_failed, reason), Toast.LENGTH_LONG).show()
Valere's avatar
Valere committed
179
                                    }
Benoit Marty's avatar
Benoit Marty committed
180
                                }
181
182
                            }
                        } catch (e: Exception) {
Benoît Marty's avatar
Benoît Marty committed
183
                            Timber.e(e, "## onUploadFailed() : failed to display the toast")
184
185
                        }

186
187
188
189
                        views.bugReportMaskView.isVisible = false
                        views.bugReportProgressView.isVisible = false
                        views.bugReportProgressTextView.isVisible = false
                        views.bugReportScrollview.alpha = 1.0f
190
191
192
193
194
195
196
197
198

                        invalidateOptionsMenu()
                    }

                    override fun onUploadCancelled() {
                        onUploadFailed(null)
                    }

                    override fun onProgress(progress: Int) {
199
                        val myProgress = progress.coerceIn(0, 100)
200

201
202
                        views.bugReportProgressView.progress = myProgress
                        views.bugReportProgressTextView.text = getString(R.string.send_bug_report_progress, myProgress.toString())
203
204
205
206
                    }

                    override fun onUploadSucceed() {
                        try {
Valere's avatar
Valere committed
207
208
209
210
                            when (reportType) {
                                ReportType.BUG_REPORT          -> {
                                    Toast.makeText(this@BugReportActivity, R.string.send_bug_report_sent, Toast.LENGTH_LONG).show()
                                }
Valere's avatar
Valere committed
211
                                ReportType.SUGGESTION,
Valere's avatar
Valere committed
212
                                ReportType.SPACE_BETA_FEEDBACK -> {
Valere's avatar
Valere committed
213
                                    Toast.makeText(this@BugReportActivity, R.string.feedback_sent, Toast.LENGTH_LONG).show()
Valere's avatar
Valere committed
214
                                }
Benoit Marty's avatar
Benoit Marty committed
215
                            }
216
                        } catch (e: Exception) {
Benoît Marty's avatar
Benoît Marty committed
217
                            Timber.e(e, "## onUploadSucceed() : failed to dismiss the toast")
218
219
220
221
222
                        }

                        try {
                            finish()
                        } catch (e: Exception) {
Benoît Marty's avatar
Benoît Marty committed
223
                            Timber.e(e, "## onUploadSucceed() : failed to dismiss the dialog")
224
225
226
227
228
229
230
231
232
                        }
                    }
                })
    }

    /* ==========================================================================================
     * UI Event
     * ========================================================================================== */

233
    private fun textChanged() {
234
        views.bugReportTextInputLayout.error = null
235
236
    }

237
238
    private fun onSendScreenshotChanged() {
        views.bugReportScreenshotPreview.isVisible = views.bugReportButtonIncludeScreenshot.isChecked && bugReporter.screenshot != null
239
240
241
242
    }

    override fun onBackPressed() {
        // Ensure there is no crash status remaining, which will be sent later on by mistake
243
        bugReporter.deleteCrashFile(this)
244
245
246

        super.onBackPressed()
    }
Valere's avatar
Valere committed
247
248
249
250
251
252
253
254
255
256

    companion object {
        private const val REPORT_TYPE_EXTRA = "REPORT_TYPE_EXTRA"

        fun intent(context: Context, reportType: ReportType): Intent {
            return Intent(context, BugReportActivity::class.java).apply {
                putExtra(REPORT_TYPE_EXTRA, reportType.name)
            }
        }
    }
257
}