diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/AppComponent.java b/app/src/main/java/com/wbrawner/simplemarkdown/AppComponent.java index 60f9ae7..56892bb 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/AppComponent.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/AppComponent.java @@ -1,5 +1,7 @@ package com.wbrawner.simplemarkdown; +import android.content.Context; + import com.wbrawner.simplemarkdown.view.activity.MainActivity; import com.wbrawner.simplemarkdown.view.activity.SplashActivity; import com.wbrawner.simplemarkdown.view.fragment.EditFragment; @@ -7,6 +9,7 @@ import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment; import javax.inject.Singleton; +import dagger.BindsInstance; import dagger.Component; /** @@ -21,4 +24,12 @@ public interface AppComponent { void inject(SplashActivity activity); void inject(EditFragment fragment); void inject(PreviewFragment fragment); + + @Component.Builder + abstract class Builder { + @BindsInstance + abstract Builder context(Context context); + + abstract AppComponent build(); + } } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/AppModule.java b/app/src/main/java/com/wbrawner/simplemarkdown/AppModule.java index 8c553df..6085a49 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/AppModule.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/AppModule.java @@ -1,10 +1,9 @@ package com.wbrawner.simplemarkdown; -import android.content.Context; - -import com.wbrawner.simplemarkdown.model.MarkdownFile; import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter; import com.wbrawner.simplemarkdown.presentation.MarkdownPresenterImpl; +import com.wbrawner.simplemarkdown.utility.CrashlyticsErrorHandler; +import com.wbrawner.simplemarkdown.utility.ErrorHandler; import javax.inject.Singleton; @@ -17,18 +16,14 @@ import dagger.Provides; @Module public class AppModule { - private final Context context; - - public AppModule(Context context) { - this.context = context; - } - @Provides - public MarkdownFile provideMarkdownFile() { - return new MarkdownFile(); - } - @Provides @Singleton - public MarkdownPresenter provideMarkdownPresenter(MarkdownFile file) { - return new MarkdownPresenterImpl(context.getApplicationContext(), file); + public MarkdownPresenter provideMarkdownPresenter(ErrorHandler errorHandler) { + return new MarkdownPresenterImpl(errorHandler); + } + + @Provides + @Singleton + ErrorHandler provideErrorHandler() { + return new CrashlyticsErrorHandler(); } } \ No newline at end of file diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.java b/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.java index 08c7970..965c9e4 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.java @@ -10,7 +10,7 @@ public class MarkdownApplication extends MultiDexApplication { public void onCreate() { super.onCreate(); component = DaggerAppComponent.builder() - .appModule(new AppModule(this)) + .context(this) .build(); } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/model/MarkdownFile.java b/app/src/main/java/com/wbrawner/simplemarkdown/model/MarkdownFile.java index 8a43e15..9a42f73 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/model/MarkdownFile.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/model/MarkdownFile.java @@ -1,6 +1,6 @@ package com.wbrawner.simplemarkdown.model; -import com.crashlytics.android.Crashlytics; +import com.wbrawner.simplemarkdown.utility.ErrorHandler; import com.wbrawner.simplemarkdown.utility.Utils; import java.io.BufferedReader; @@ -17,14 +17,17 @@ import java.io.OutputStreamWriter; public class MarkdownFile { private String name; private String content; + private final ErrorHandler errorHandler; - public MarkdownFile(String name, String content) { + public MarkdownFile(ErrorHandler errorHandler, String name, String content) { + this.errorHandler = errorHandler; this.name = name; this.content = content; } - public MarkdownFile() { + public MarkdownFile(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; this.name = "Untitled.md"; this.content = ""; } @@ -57,8 +60,7 @@ public class MarkdownFile { this.name = name; this.content = sb.toString(); return true; - } catch (IOException e) { - Crashlytics.logException(e); + } catch (IOException ignored) { return false; } finally { Utils.closeQuietly(reader); @@ -71,17 +73,10 @@ public class MarkdownFile { writer = new OutputStreamWriter(outputStream); writer.write(this.content); this.name = name; - } catch (IOException e) { - Crashlytics.logException(e); + } catch (IOException ignored) { return false; } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - Crashlytics.logException(e); - } - } + Utils.closeQuietly(writer); } return true; } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/presentation/MarkdownPresenterImpl.java b/app/src/main/java/com/wbrawner/simplemarkdown/presentation/MarkdownPresenterImpl.java index 69c018c..20aa5cd 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/presentation/MarkdownPresenterImpl.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/presentation/MarkdownPresenterImpl.java @@ -7,8 +7,8 @@ import android.os.Handler; import android.provider.OpenableColumns; import com.commonsware.cwac.anddown.AndDown; -import com.crashlytics.android.Crashlytics; import com.wbrawner.simplemarkdown.model.MarkdownFile; +import com.wbrawner.simplemarkdown.utility.ErrorHandler; import com.wbrawner.simplemarkdown.utility.Utils; import com.wbrawner.simplemarkdown.view.MarkdownEditView; import com.wbrawner.simplemarkdown.view.MarkdownPreviewView; @@ -16,16 +16,23 @@ import com.wbrawner.simplemarkdown.view.MarkdownPreviewView; import java.io.InputStream; import java.io.OutputStream; +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton public class MarkdownPresenterImpl implements MarkdownPresenter { private final Object fileLock = new Object(); private MarkdownFile file; private volatile MarkdownEditView editView; private volatile MarkdownPreviewView previewView; private Handler fileHandler = new Handler(); + private final ErrorHandler errorHandler; - public MarkdownPresenterImpl(Context context, MarkdownFile file) { + @Inject + public MarkdownPresenterImpl(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; synchronized (fileLock) { - this.file = file; + this.file = new MarkdownFile(errorHandler); } } @@ -41,7 +48,7 @@ public class MarkdownPresenterImpl implements MarkdownPresenter { final OnTempFileLoadedListener listener ) { Runnable fileLoader = () -> { - MarkdownFile tmpFile = new MarkdownFile(); + MarkdownFile tmpFile = new MarkdownFile(errorHandler); if (tmpFile.load(fileName, in)) { if (listener != null) { String html = generateHTML(tmpFile.getContent()); @@ -76,7 +83,7 @@ public class MarkdownPresenterImpl implements MarkdownPresenter { currentEditView.setTitle(newName); currentEditView.setMarkdown(""); } - file = new MarkdownFile(newName, ""); + file = new MarkdownFile(errorHandler, newName, ""); } } @@ -194,7 +201,7 @@ public class MarkdownPresenterImpl implements MarkdownPresenter { } loadMarkdown(fileName, in); } catch (Exception e) { - Crashlytics.logException(e); + errorHandler.reportException(e); MarkdownEditView currentEditView = editView; if (currentEditView != null) { currentEditView.onFileLoaded(false); diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java index 5e0e3ad..14b4b5b 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java @@ -6,7 +6,7 @@ public class Constants { // Request codes public static final int REQUEST_OPEN_FILE = 1; public static final int REQUEST_SAVE_FILE = 2; - public static final int REQUEST_ROOT_DIR = 1000; + public static final int REQUEST_DARK_MODE = 3; // Extras public static final String EXTRA_FILE = "EXTRA_FILE"; diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt b/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt new file mode 100644 index 0000000..c83c53a --- /dev/null +++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt @@ -0,0 +1,27 @@ +package com.wbrawner.simplemarkdown.utility + +import android.content.Context +import com.crashlytics.android.Crashlytics +import io.fabric.sdk.android.BuildConfig +import io.fabric.sdk.android.Fabric +import java.util.concurrent.atomic.AtomicBoolean + +interface ErrorHandler { + fun init(context: Context) + fun reportException(t: Throwable) +} + +class CrashlyticsErrorHandler : ErrorHandler { + private val isInitialized = AtomicBoolean(false) + + override fun init(context: Context) { + if (!isInitialized.getAndSet(true)) { + Fabric.with(context, Crashlytics()) + } + } + + override fun reportException(t: Throwable) { + if (!isInitialized.get() || BuildConfig.DEBUG) return + Crashlytics.logException(t) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/Utils.java b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Utils.java index 122135d..89315d5 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/utility/Utils.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Utils.java @@ -11,8 +11,6 @@ import android.preference.PreferenceManager; import androidx.core.content.ContextCompat; -import com.crashlytics.android.Crashlytics; - import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -101,11 +99,11 @@ public class Utils { @SuppressWarnings("SameParameterValue") - public static Handler createSafeHandler(String name) { + public static Handler createSafeHandler(ErrorHandler errorHandler, String name) { HandlerThread handlerThread = new HandlerThread(name); handlerThread.start(); handlerThread.setUncaughtExceptionHandler((t, e) -> { - Crashlytics.logException(e); + errorHandler.reportException(e); t.interrupt(); }); return new Handler(handlerThread.getLooper()); diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt index e337714..9ad9fd6 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt @@ -11,14 +11,16 @@ import android.provider.OpenableColumns import android.view.Menu import android.view.MenuItem import android.view.View +import android.webkit.MimeTypeMap import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat -import com.crashlytics.android.Crashlytics import com.wbrawner.simplemarkdown.MarkdownApplication import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter import com.wbrawner.simplemarkdown.utility.Constants +import com.wbrawner.simplemarkdown.utility.Constants.REQUEST_DARK_MODE +import com.wbrawner.simplemarkdown.utility.ErrorHandler import com.wbrawner.simplemarkdown.utility.Utils import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter import kotlinx.android.synthetic.main.activity_main.* @@ -30,7 +32,8 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes @Inject lateinit var presenter: MarkdownPresenter - + @Inject + lateinit var errorHandler: ErrorHandler private var shouldAutoSave = true private var newFileHandler: NewFileHandler? = null @@ -54,9 +57,6 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes tabLayout!!.visibility = View.GONE } newFileHandler = NewFileHandler() - if (intent.getBooleanExtra(Constants.EXTRA_EXPLORER, false)) { - requestFileOp(Constants.REQUEST_OPEN_FILE) - } } override fun onUserLeaveHint() { @@ -100,7 +100,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes R.id.action_help -> showInfoActivity(R.id.action_help) R.id.action_settings -> { val settingsIntent = Intent(this@MainActivity, SettingsActivity::class.java) - startActivity(settingsIntent) + startActivityForResult(settingsIntent, REQUEST_DARK_MODE) } R.id.action_libraries -> showInfoActivity(R.id.action_libraries) R.id.action_privacy -> showInfoActivity(R.id.action_privacy) @@ -145,7 +145,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes } }) } catch (e: Exception) { - Crashlytics.logException(e) + errorHandler.reportException(e) Toast.makeText(this@MainActivity, R.string.file_load_error, Toast.LENGTH_SHORT).show() } @@ -185,10 +185,6 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes return } - val mimeType: String? = data.data?.let { returnUri -> - contentResolver.getType(returnUri) - } - val fileName = contentResolver.query(data.data!!, null, null, null, null) ?.use { cursor -> val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) @@ -220,6 +216,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes contentResolver.openOutputStream(data.data!!) ) } + REQUEST_DARK_MODE -> recreate() } super.onActivityResult(requestCode, resultCode, data) } @@ -245,7 +242,11 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes Constants.REQUEST_OPEN_FILE -> { Intent(Intent.ACTION_OPEN_DOCUMENT).apply { type = "*/*" - putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/plain", "text/markdown")) + if (MimeTypeMap.getSingleton().hasMimeType("md")) { + // If the device doesn't recognize markdown files then we're not going to be + // able to open them at all, so there's no sense in filtering them out. + putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/plain", "text/markdown")) + } } } else -> null diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SettingsActivity.java b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SettingsActivity.java index 225f0b5..3d61fd5 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SettingsActivity.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SettingsActivity.java @@ -14,6 +14,7 @@ public class SettingsActivity extends AppCompatActivity { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); + setSupportActionBar(findViewById(R.id.toolbar)); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @@ -21,11 +22,9 @@ public class SettingsActivity extends AppCompatActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); + // The only menu item is the back button + setResult(RESULT_OK); + finish(); + return true; } } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.java b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.java index 2c42837..3d8824c 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.java @@ -10,31 +10,30 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; -import com.crashlytics.android.Crashlytics; -import com.wbrawner.simplemarkdown.BuildConfig; import com.wbrawner.simplemarkdown.MarkdownApplication; import com.wbrawner.simplemarkdown.R; import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter; +import com.wbrawner.simplemarkdown.utility.ErrorHandler; import com.wbrawner.simplemarkdown.utility.Utils; import javax.inject.Inject; -import io.fabric.sdk.android.Fabric; - public class SplashActivity extends AppCompatActivity { @Inject MarkdownPresenter presenter; + @Inject + ErrorHandler errorHandler; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - if (sharedPreferences.getBoolean(getString(R.string.error_reports_enabled), true) - && !BuildConfig.DEBUG) { - Fabric.with(this, new Crashlytics()); - } ((MarkdownApplication) getApplication()).getComponent().inject(this); + if (sharedPreferences.getBoolean(getString(R.string.error_reports_enabled), true)) { + errorHandler.init(this); + } String darkModeValue = sharedPreferences.getString( getString(R.string.pref_key_dark_mode), diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt index cd9fb2f..d18d67b 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt @@ -9,6 +9,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.webkit.WebView +import androidx.appcompat.app.AppCompatDelegate import androidx.fragment.app.Fragment import com.wbrawner.simplemarkdown.BuildConfig import com.wbrawner.simplemarkdown.MarkdownApplication @@ -51,7 +52,9 @@ class PreviewFragment : Fragment(), MarkdownPreviewView { return@post } - val isNightMode = context!!.resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES + val isNightMode = AppCompatDelegate.getDefaultNightMode() == + AppCompatDelegate.MODE_NIGHT_YES + || context!!.resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES val defaultCssId = if (isNightMode) { R.string.pref_custom_css_default_dark } else { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ce72f4d..0ac7899 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -14,44 +14,61 @@ android:clipChildren="false" android:fitsSystemWindows="true" android:clipToPadding="false" + android:paddingBottom="90dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/tabLayout" /> + app:layout_constraintBottom_toBottomOf="parent" /> - + app:layout_constraintBottom_toBottomOf="parent"> - + android:paddingBottom="16dp"> - - + - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index e64a999..1a8b362 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -1,12 +1,38 @@ - + + android:layout_marginBottom="90dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - \ No newline at end of file + + + + + + \ No newline at end of file