BugReportActivity.kt 10.5 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
74
75
76
77
        when (reportType) {
            ReportType.BUG_REPORT -> {
                supportActionBar?.setTitle(R.string.title_activity_bug_report)
                views.bugReportButtonContactMe.isVisible = false
            }
            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
175
176
177
178
179
180
181
182
                                when (reportType) {
                                    ReportType.BUG_REPORT          -> {
                                        Toast.makeText(this@BugReportActivity,
                                                getString(R.string.send_bug_report_failed, reason), Toast.LENGTH_LONG).show()
                                    }
                                    ReportType.SUGGESTION          -> {
                                        Toast.makeText(this@BugReportActivity,
                                                getString(R.string.send_suggestion_failed, reason), Toast.LENGTH_LONG).show()
                                    }
                                    ReportType.SPACE_BETA_FEEDBACK -> {
                                        Toast.makeText(this@BugReportActivity,
                                                getString(R.string.space_feedback_failed, reason), Toast.LENGTH_LONG).show()
                                    }
Benoit Marty's avatar
Benoit Marty committed
183
                                }
184
185
                            }
                        } catch (e: Exception) {
Benoît Marty's avatar
Benoît Marty committed
186
                            Timber.e(e, "## onUploadFailed() : failed to display the toast")
187
188
                        }

189
190
191
192
                        views.bugReportMaskView.isVisible = false
                        views.bugReportProgressView.isVisible = false
                        views.bugReportProgressTextView.isVisible = false
                        views.bugReportScrollview.alpha = 1.0f
193
194
195
196
197
198
199
200
201

                        invalidateOptionsMenu()
                    }

                    override fun onUploadCancelled() {
                        onUploadFailed(null)
                    }

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

204
205
                        views.bugReportProgressView.progress = myProgress
                        views.bugReportProgressTextView.text = getString(R.string.send_bug_report_progress, myProgress.toString())
206
207
208
209
                    }

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

                        try {
                            finish()
                        } catch (e: Exception) {
Benoît Marty's avatar
Benoît Marty committed
228
                            Timber.e(e, "## onUploadSucceed() : failed to dismiss the dialog")
229
230
231
232
233
234
235
236
237
                        }
                    }
                })
    }

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

238
    private fun textChanged() {
239
        views.bugReportTextInputLayout.error = null
240
241
    }

242
243
    private fun onSendScreenshotChanged() {
        views.bugReportScreenshotPreview.isVisible = views.bugReportButtonIncludeScreenshot.isChecked && bugReporter.screenshot != null
244
245
246
247
    }

    override fun onBackPressed() {
        // Ensure there is no crash status remaining, which will be sent later on by mistake
248
        bugReporter.deleteCrashFile(this)
249
250
251

        super.onBackPressed()
    }
Valere's avatar
Valere committed
252
253
254
255
256
257
258
259
260
261

    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)
            }
        }
    }
262
}