@@ -22,12 +22,14 @@ import androidx.annotation.ColorInt
2222import androidx.annotation.RequiresApi
2323import androidx.core.content.ContextCompat
2424import androidx.core.content.FileProvider
25+ import androidx.core.net.toUri
2526import androidx.documentfile.provider.DocumentFile
2627import androidx.fragment.app.Fragment
2728import androidx.lifecycle.LifecycleOwner
2829import androidx.lifecycle.LiveData
2930import androidx.lifecycle.MediatorLiveData
3031import androidx.lifecycle.Observer
32+ import com.google.android.material.dialog.MaterialAlertDialogBuilder
3133import com.philkes.notallyx.BuildConfig
3234import com.philkes.notallyx.R
3335import com.philkes.notallyx.data.model.BaseNote
@@ -36,8 +38,10 @@ import com.philkes.notallyx.data.model.toText
3638import com.philkes.notallyx.presentation.activity.note.EditActivity.Companion.EXTRA_SELECTED_BASE_NOTE
3739import com.philkes.notallyx.presentation.activity.note.EditListActivity
3840import com.philkes.notallyx.presentation.activity.note.EditNoteActivity
41+ import com.philkes.notallyx.presentation.setCancelButton
3942import com.philkes.notallyx.presentation.showToast
4043import com.philkes.notallyx.presentation.view.misc.NotNullLiveData
44+ import com.philkes.notallyx.presentation.viewmodel.ExportMimeType
4145import java.io.BufferedReader
4246import java.io.File
4347import java.io.InputStreamReader
@@ -148,7 +152,14 @@ fun ContextWrapper.log(
148152) {
149153 val folder = getLogsDir()
150154 folder.mkdir()
151- logToFile(tag, DocumentFile .fromFile(folder), APP_LOG_FILE_NAME , msg, throwable, stackTrace)
155+ logToFile(
156+ tag,
157+ DocumentFile .fromFile(folder),
158+ " $APP_LOG_FILE_NAME .txt" ,
159+ msg,
160+ throwable,
161+ stackTrace,
162+ )
152163}
153164
154165fun ContextWrapper.getLastExceptionLog (): String? {
@@ -159,9 +170,21 @@ fun ContextWrapper.getLastExceptionLog(): String? {
159170 return null
160171}
161172
173+ fun ContextWrapper.viewLogs () {
174+ val logFile = getLogFile()
175+ if (logFile.exists()) {
176+ viewFile(getUriForFile(logFile), ExportMimeType .TXT .mimeType)
177+ } else {
178+ showToast(getString(R .string.not_exists, logFile.name))
179+ }
180+ }
181+
182+ fun ContextWrapper.getLogFileUri () =
183+ getLogFile().let { if (it.exists()) getUriForFile(it) else null }
184+
162185private const val MAX_LOGS_FILE_SIZE_KB : Long = 2048
163186
164- fun Context.logToFile (
187+ private fun Context.logToFile (
165188 tag : String ,
166189 folder : DocumentFile ,
167190 fileName : String ,
@@ -233,12 +256,6 @@ fun Context.logToFile(
233256 } ? : Log .e(tag, " Error: log file could not be found or created" )
234257}
235258
236- fun Fragment.reportBug (stackTrace : String? ) {
237- requireContext().catchNoBrowserInstalled {
238- startActivity(requireContext().createReportBugIntent(stackTrace))
239- }
240- }
241-
242259fun Fragment.getExtraBooleanFromBundleOrIntent (
243260 bundle : Bundle ? ,
244261 key : String ,
@@ -250,8 +267,29 @@ fun Fragment.getExtraBooleanFromBundleOrIntent(
250267 )
251268}
252269
270+ private fun Context.showConfirmCrashLogTooLong () {
271+ MaterialAlertDialogBuilder (this )
272+ .setMessage(
273+ getString(R .string.report_bug_stacktrace_too_long, getString(R .string.continue_))
274+ )
275+ .setPositiveButton(R .string.continue_) { _, _ -> reportBug(" <PASTE CRASH LOGS HERE>" ) }
276+ .setCancelButton()
277+ .show()
278+ }
279+
253280fun Context.reportBug (stackTrace : String? ) {
254- catchNoBrowserInstalled { startActivity(createReportBugIntent(stackTrace)) }
281+ catchNoBrowserInstalled {
282+ try {
283+ startActivity(createReportBugIntent(stackTrace))
284+ } catch (_: IllegalArgumentException ) {
285+ copyToClipBoard(stackTrace!! )
286+ showConfirmCrashLogTooLong()
287+ }
288+ }
289+ }
290+
291+ fun Fragment.reportBug (stackTrace : String? ) {
292+ requireContext().reportBug(stackTrace)
255293}
256294
257295fun Context.catchNoBrowserInstalled (callback : () -> Unit ) {
@@ -270,20 +308,30 @@ fun Context.createReportBugIntent(
270308 fun String?.asQueryParam (paramName : String ): String {
271309 return this ?.let { " &$paramName =${URLEncoder .encode(this , " UTF-8" )} " } ? : " "
272310 }
273- return Intent (
274- Intent .ACTION_VIEW ,
275- Uri .parse(
276- " https://github.com/PhilKes/NotallyX/issues/new?labels=bug&projects=&template=bug_report.yml${
277- title.asQueryParam(" title" )
278- } &version=${BuildConfig .VERSION_NAME } &android-version=${Build .VERSION .SDK_INT }${
279- stackTrace.asQueryParam(" logs" )
280- }${
281- body.asQueryParam(" what-happened" )
282- } "
283- .take(2000 )
284- ),
285- )
286- .wrapWithChooser(this )
311+
312+ val url =
313+ " https://github.com/PhilKes/NotallyX/issues/new?labels=bug&projects=&template=bug_report.yml${
314+ title.asQueryParam(" title" )
315+ } &version=${BuildConfig .VERSION_NAME } &android-version=${Build .VERSION .SDK_INT }${
316+ stackTrace.asQueryParam(" logs" )
317+ }${
318+ body.asQueryParam(" what-happened" )
319+ } "
320+ if (url.length > 2000 ) {
321+ throw IllegalArgumentException (" Given stacktrace is too long to build a valid URL!" )
322+ }
323+ return Intent (Intent .ACTION_VIEW , url.toUri()).wrapWithChooser(this )
324+ }
325+
326+ fun Context.viewFile (uri : Uri , mimeType : String ) {
327+ val intent =
328+ Intent (Intent .ACTION_VIEW )
329+ .apply {
330+ setDataAndType(uri, mimeType)
331+ flags = Intent .FLAG_GRANT_READ_URI_PERMISSION
332+ }
333+ .wrapWithChooser(this )
334+ startActivity(intent)
287335}
288336
289337fun ContextWrapper.shareNote (note : BaseNote ) {
@@ -393,9 +441,14 @@ fun DocumentFolder.createFileSafe(
393441 fileName : String ,
394442 fileExtension : String ,
395443): DocumentFile {
396- return requireNotNull(
397- createFile(mimeType, fileName + fileExtension) ? : createFile(mimeType, fileName)
398- ) {
444+ var createdFile = createFile(mimeType, fileName)
445+ if (createdFile == null ) {
446+ createdFile = createFile(mimeType, fileName + fileExtension)
447+ } else if (createdFile.name?.endsWith(fileExtension) == false ) {
448+ createdFile.delete()
449+ createdFile = createFile(mimeType, fileName + fileExtension)
450+ }
451+ return requireNotNull(createdFile) {
399452 " Could not create '$fileName$fileExtension ' in Folder '$name ' (uri: '$uri ')"
400453 }
401454}
0 commit comments