diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java new file mode 100644 index 0000000..5e0e3ad --- /dev/null +++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Constants.java @@ -0,0 +1,25 @@ +package com.wbrawner.simplemarkdown.utility; + +@SuppressWarnings("WeakerAccess") +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; + + // Extras + public static final String EXTRA_FILE = "EXTRA_FILE"; + public static final String EXTRA_FILE_PATH = "EXTRA_FILE_PATH"; + public static final String EXTRA_REQUEST_CODE = "EXTRA_REQUEST_CODE"; + public static final String EXTRA_EXPLORER = "EXTRA_EXPLORER"; + + // Settings keys + public static final String KEY_AUTOSAVE = "autosave"; + public static final String KEY_DOCS_PATH = "defaultRootDir"; + + // Settings values + public static final String VALUE_EDIT_VIEW = "0"; + public static final String VALUE_FILE_VIEW = "1"; + +} 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 2267821..a9412f7 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/utility/Utils.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/Utils.java @@ -5,10 +5,12 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; import android.preference.PreferenceManager; import android.support.v4.content.ContextCompat; -import com.wbrawner.simplemarkdown.view.activity.SettingsActivity; +import com.crashlytics.android.Crashlytics; import java.io.Closeable; import java.io.File; @@ -22,7 +24,7 @@ public class Utils { public static String getDocsPath(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); return prefs.getString( - SettingsActivity.KEY_DOCS_PATH, + Constants.KEY_DOCS_PATH, Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DOCUMENTS + "/" ); @@ -74,7 +76,7 @@ public class Utils { public static boolean isAutosaveEnabled(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); return prefs.getBoolean( - SettingsActivity.KEY_AUTOSAVE, + Constants.KEY_AUTOSAVE, true ); } @@ -95,4 +97,16 @@ public class Utils { Manifest.permission.WRITE_EXTERNAL_STORAGE ) == PackageManager.PERMISSION_GRANTED; } + + + @SuppressWarnings("SameParameterValue") + public static Handler createSafeHandler(String name) { + HandlerThread handlerThread = new HandlerThread(name); + handlerThread.start(); + handlerThread.setUncaughtExceptionHandler((t, e) -> { + Crashlytics.logException(e); + t.interrupt(); + }); + return new Handler(handlerThread.getLooper()); + } } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/ExplorerActivity.java b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/ExplorerActivity.java index 950a09b..0b2cd12 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/ExplorerActivity.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/ExplorerActivity.java @@ -16,6 +16,7 @@ import android.widget.ListView; import android.widget.SimpleAdapter; import com.wbrawner.simplemarkdown.R; +import com.wbrawner.simplemarkdown.utility.Constants; import com.wbrawner.simplemarkdown.utility.Utils; import java.io.File; @@ -24,14 +25,16 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicReference; public class ExplorerActivity extends AppCompatActivity { - private Handler fileHandler = new Handler(); + private Handler fileHandler = Utils.createSafeHandler("ExplorerThread"); private ListView listView; private File[] mounts; private String docsDirPath; - private String filePath; - private boolean isSave = false; + private AtomicReference filePath = new AtomicReference<>(""); + private volatile boolean isSave = false; + private volatile boolean showFiles = true; private EditText fileName; @SuppressLint("SetTextI18n") @@ -43,23 +46,26 @@ public class ExplorerActivity extends AppCompatActivity { setSupportActionBar(toolbar); Intent intent = getIntent(); - if (intent == null || !intent.hasExtra(MainActivity.EXTRA_REQUEST_CODE)) { + if (intent == null || !intent.hasExtra(Constants.EXTRA_REQUEST_CODE)) { finish(); return; } docsDirPath = Utils.getDocsPath(this); - int requestCode = intent.getIntExtra(MainActivity.EXTRA_REQUEST_CODE, -1); + int requestCode = intent.getIntExtra(Constants.EXTRA_REQUEST_CODE, -1); switch (requestCode) { - case MainActivity.OPEN_FILE_REQUEST: + case Constants.REQUEST_OPEN_FILE: break; - case MainActivity.SAVE_FILE_REQUEST: + case Constants.REQUEST_ROOT_DIR: + showFiles = false; + break; + case Constants.REQUEST_SAVE_FILE: isSave = true; fileName = findViewById(R.id.file_name); fileName.setVisibility(View.VISIBLE); - if (intent.hasExtra(MainActivity.EXTRA_FILE)) { - File file = (File) intent.getSerializableExtra(MainActivity.EXTRA_FILE); + if (intent.hasExtra(Constants.EXTRA_FILE)) { + File file = (File) intent.getSerializableExtra(Constants.EXTRA_FILE); if (file.exists() && file.canWrite()) { docsDirPath = file.getParentFile().getAbsolutePath(); fileName.setText(file.getName()); @@ -74,10 +80,10 @@ public class ExplorerActivity extends AppCompatActivity { String absolutePath = String.format( Locale.ENGLISH, "%s/%s", - filePath, + filePath.get(), fileName.getText().toString() ); - fileIntent.putExtra(MainActivity.EXTRA_FILE_PATH, absolutePath); + fileIntent.putExtra(Constants.EXTRA_FILE_PATH, absolutePath); setResult(RESULT_OK, fileIntent); finish(); }); @@ -103,14 +109,20 @@ public class ExplorerActivity extends AppCompatActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_explorer, menu); + + if (!showFiles) { + menu.findItem(R.id.action_select).setVisible(true); + } + if (hasRemovableStorage()) { - getMenuInflater().inflate(R.menu.menu_explorer, menu); - if (filePath.contains(mounts[1].getAbsolutePath())) { + menu.findItem(R.id.action_use_sdcard).setVisible(true); + if (filePath.get().contains(mounts[1].getAbsolutePath())) { menu.findItem(R.id.action_use_sdcard).setChecked(true); } - return true; } - return false; + + return true; } @Override @@ -127,6 +139,10 @@ public class ExplorerActivity extends AppCompatActivity { } else { updateListView(new File(docsDirPath)); } + break; + case R.id.action_select: + replyWithFile(new File(filePath.get())); + break; } return true; } @@ -161,9 +177,10 @@ public class ExplorerActivity extends AppCompatActivity { dirs.add(fileHashMap); continue; } - if (!file.getName().endsWith("md") - && !file.getName().endsWith("markdown") - && !file.getName().endsWith("text")) { + if (!showFiles || + (!file.getName().endsWith("md") + && !file.getName().endsWith("markdown") + && !file.getName().endsWith("text"))) { continue; } HashMap fileHashMap = new HashMap<>(); @@ -181,7 +198,7 @@ public class ExplorerActivity extends AppCompatActivity { private void updateListView(File filesDir) { setTitle(filesDir.getName()); - filePath = filesDir.getAbsolutePath(); + filePath.set(filesDir.getAbsolutePath()); fileHandler.post(() -> { List> files = loadFiles(filesDir); @@ -210,10 +227,14 @@ public class ExplorerActivity extends AppCompatActivity { fileName.setText(file.getName()); } } else { - Intent fileIntent = new Intent(); - fileIntent.putExtra(MainActivity.EXTRA_FILE, file); - setResult(RESULT_OK, fileIntent); - finish(); + replyWithFile(file); } } + + private void replyWithFile(File file) { + Intent fileIntent = new Intent(); + fileIntent.putExtra(Constants.EXTRA_FILE, file); + setResult(RESULT_OK, fileIntent); + finish(); + } } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.java b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.java index 4ca2f87..83f68ac 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.java @@ -10,7 +10,6 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.TabLayout; import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; @@ -20,6 +19,7 @@ import android.widget.Toast; 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.Utils; import com.wbrawner.simplemarkdown.view.DisableableViewPager; import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter; @@ -35,14 +35,6 @@ import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback { - static final int WRITE_PERMISSION_REQUEST = 0; - static final int OPEN_FILE_REQUEST = 1; - static final int SAVE_FILE_REQUEST = 2; - static final String EXTRA_FILE = "EXTRA_FILE"; - static final String EXTRA_FILE_PATH = "EXTRA_FILE_PATH"; - static final String EXTRA_REQUEST_CODE = "EXTRA_REQUEST_CODE"; - static final String EXTRA_EXPLORER = "EXTRA_EXPLORER"; - @Inject MarkdownPresenter presenter; @@ -60,7 +52,6 @@ public class MainActivity extends AppCompatActivity ((MarkdownApplication) getApplication()).getComponent().inject(this); ButterKnife.bind(this); - presenter.setRootDir(Utils.getDocsPath(this)); pager.setAdapter( new EditPagerAdapter(getSupportFragmentManager(), MainActivity.this) ); @@ -71,8 +62,8 @@ public class MainActivity extends AppCompatActivity tabLayout.setVisibility(View.GONE); } newFileHandler = new NewFileHandler(); - if (getIntent().getBooleanExtra(EXTRA_EXPLORER, false)) { - requestFileOp(OPEN_FILE_REQUEST); + if (getIntent().getBooleanExtra(Constants.EXTRA_EXPLORER, false)) { + requestFileOp(Constants.REQUEST_OPEN_FILE); } } @@ -103,7 +94,7 @@ public class MainActivity extends AppCompatActivity public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_save: - requestFileOp(SAVE_FILE_REQUEST); + requestFileOp(Constants.REQUEST_SAVE_FILE); break; case R.id.action_share: Intent shareIntent = new Intent(Intent.ACTION_SEND); @@ -115,7 +106,7 @@ public class MainActivity extends AppCompatActivity )); break; case R.id.action_load: - requestFileOp(OPEN_FILE_REQUEST); + requestFileOp(Constants.REQUEST_OPEN_FILE); break; case R.id.action_new: presenter.saveMarkdown(newFileHandler, null); @@ -184,8 +175,8 @@ public class MainActivity extends AppCompatActivity @NonNull int[] grantResults ) { switch (requestCode) { - case SAVE_FILE_REQUEST: - case OPEN_FILE_REQUEST: { + case Constants.REQUEST_SAVE_FILE: + case Constants.REQUEST_OPEN_FILE: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { @@ -212,22 +203,22 @@ public class MainActivity extends AppCompatActivity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { - case OPEN_FILE_REQUEST: - if (resultCode != RESULT_OK || data == null || !data.hasExtra(EXTRA_FILE)) { + case Constants.REQUEST_OPEN_FILE: + if (resultCode != RESULT_OK || data == null || !data.hasExtra(Constants.EXTRA_FILE)) { break; } - File markdownFile = (File) data.getSerializableExtra(EXTRA_FILE); + File markdownFile = (File) data.getSerializableExtra(Constants.EXTRA_FILE); presenter.loadMarkdown(markdownFile); break; - case SAVE_FILE_REQUEST: + case Constants.REQUEST_SAVE_FILE: if (resultCode != RESULT_OK || data == null - || !data.hasExtra(EXTRA_FILE_PATH) - || data.getStringExtra(EXTRA_FILE_PATH).isEmpty()) { + || !data.hasExtra(Constants.EXTRA_FILE_PATH) + || data.getStringExtra(Constants.EXTRA_FILE_PATH).isEmpty()) { break; } - String path = data.getStringExtra(EXTRA_FILE_PATH); + String path = data.getStringExtra(Constants.EXTRA_FILE_PATH); presenter.saveMarkdown(null, path); break; } @@ -237,8 +228,8 @@ public class MainActivity extends AppCompatActivity private void requestFileOp(int requestType) { if (Utils.canAccessFiles(MainActivity.this)) { Intent intent = new Intent(MainActivity.this, ExplorerActivity.class); - intent.putExtra(EXTRA_REQUEST_CODE, requestType); - intent.putExtra(EXTRA_FILE, presenter.getFile()); + intent.putExtra(Constants.EXTRA_REQUEST_CODE, requestType); + intent.putExtra(Constants.EXTRA_FILE, presenter.getFile()); startActivityForResult( intent, requestType 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 e930be8..a6efcfa 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 @@ -9,11 +9,6 @@ import com.wbrawner.simplemarkdown.R; public class SettingsActivity extends AppCompatActivity { - public static final String KEY_AUTOSAVE = "autosave"; - public static final String KEY_DOCS_PATH = "defaultRootDir"; - public static final String EDIT_VIEW = "0"; - public static final String FILE_VIEW = "1"; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); 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 ed6285f..1e321f3 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 @@ -1,6 +1,7 @@ package com.wbrawner.simplemarkdown.view.activity; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; @@ -9,6 +10,7 @@ import android.support.v7.app.AppCompatActivity; 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.Utils; import javax.inject.Inject; @@ -32,15 +34,20 @@ public class SplashActivity extends AppCompatActivity { presenter.setFileName(defaultName); } + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + String defaultRootDir = + sharedPreferences.getString(Constants.KEY_DOCS_PATH, Utils.getDocsPath(this)); + presenter.setRootDir(defaultRootDir); + Intent startIntent = new Intent(this, MainActivity.class); String startScreen = PreferenceManager.getDefaultSharedPreferences(this) .getString( getString(R.string.key_default_view), - SettingsActivity.EDIT_VIEW + Constants.VALUE_EDIT_VIEW ); switch (startScreen) { - case SettingsActivity.FILE_VIEW: - startIntent.putExtra(MainActivity.EXTRA_EXPLORER, true); + case Constants.VALUE_FILE_VIEW: + startIntent.putExtra(Constants.EXTRA_EXPLORER, true); break; } startActivity(startIntent); diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.java b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.java index aee145c..066849a 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.java @@ -61,18 +61,24 @@ public class PreviewFragment extends Fragment implements MarkdownPreviewView { } - @Override public void updatePreview(String html) { - if (markdownPreview != null) { - markdownPreview.post(() -> markdownPreview.loadDataWithBaseURL( + if (markdownPreview == null) { + return; + } + markdownPreview.post(() -> { + if (markdownPreview == null) { + return; + } + + markdownPreview.loadDataWithBaseURL( null, style + html, "text/html", "UTF-8", null - )); - } + ); + }); } @Override diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/SettingsFragment.java b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/SettingsFragment.java index 839ff7a..1663694 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/SettingsFragment.java +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/SettingsFragment.java @@ -1,5 +1,6 @@ package com.wbrawner.simplemarkdown.view.fragment; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.ListPreference; @@ -7,8 +8,17 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.support.annotation.Nullable; +import android.util.Log; +import com.crashlytics.android.Crashlytics; import com.wbrawner.simplemarkdown.R; +import com.wbrawner.simplemarkdown.utility.Constants; +import com.wbrawner.simplemarkdown.utility.Utils; +import com.wbrawner.simplemarkdown.view.activity.ExplorerActivity; + +import java.io.File; + +import static android.app.Activity.RESULT_OK; public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -23,6 +33,14 @@ public class SettingsFragment extends PreferenceFragment sharedPreferences, findPreference(getString(R.string.key_default_view)) ); + Preference defaultRoot = findPreference(Constants.KEY_DOCS_PATH); + defaultRoot.setSummary(Utils.getDocsPath(getActivity())); + defaultRoot.setOnPreferenceClickListener((preference) -> { + Intent intent = new Intent(getActivity(), ExplorerActivity.class); + intent.putExtra(Constants.EXTRA_REQUEST_CODE, Constants.REQUEST_ROOT_DIR); + startActivityForResult(intent, Constants.REQUEST_ROOT_DIR); + return true; + }); } @Override @@ -40,8 +58,38 @@ public class SettingsFragment extends PreferenceFragment if (storedValue.isEmpty()) { return; } - int index = Integer.valueOf(storedValue); + int index = 0; + try { + index = Integer.valueOf(storedValue); + } catch (NumberFormatException e) { + Log.e("SimpleMarkdown", "Unable to parse " + storedValue + " to integer"); + Crashlytics.logException(e); + } String summary = listPreference.getEntries()[index].toString(); preference.setSummary(summary); } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode != RESULT_OK || data == null) { + // If the user cancelled the request, then we don't care about the response + return; + } + + switch (requestCode) { + case Constants.REQUEST_ROOT_DIR: + File root = (File) data.getSerializableExtra(Constants.EXTRA_FILE); + if (root == null) { + Crashlytics.logException(new RuntimeException("Got null/empty response from setting default root dir")); + return; + } + Preference defaultRoot = findPreference(Constants.KEY_DOCS_PATH); + defaultRoot.setSummary(root.getAbsolutePath()); + PreferenceManager.getDefaultSharedPreferences(getActivity()) + .edit() + .putString(Constants.KEY_DOCS_PATH, root.getAbsolutePath()) + .apply(); + break; + } + } } diff --git a/app/src/main/res/drawable/ic_action_select.xml b/app/src/main/res/drawable/ic_action_select.xml new file mode 100644 index 0000000..599bf75 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_select.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/menu_explorer.xml b/app/src/main/res/menu/menu_explorer.xml index 12c5026..b94358b 100644 --- a/app/src/main/res/menu/menu_explorer.xml +++ b/app/src/main/res/menu/menu_explorer.xml @@ -2,8 +2,15 @@ + + android:checkable="true" + android:title="@string/action_use_sdcard" + android:visible="false" + app:showAsAction="never" /> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dd0d040..87900e7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -38,6 +38,8 @@ Default View Edit View File Explorer View + Default Root Directory + Select @string/value_edit_view @string/value_explorer_view diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml index f7e7fed..0a3ff1c 100644 --- a/app/src/main/res/xml/pref_general.xml +++ b/app/src/main/res/xml/pref_general.xml @@ -6,10 +6,13 @@ android:summary="@string/pref_description_autosave" android:title="@string/pref_title_autosave" /> +