Use built-in file explorer instead of OEM implementation

This commit is contained in:
William Brawner 2017-12-23 22:27:38 -06:00 committed by William Brawner
parent 8de320bd48
commit 8c2f32dd97
15 changed files with 532 additions and 53 deletions

View file

@ -4,6 +4,7 @@ buildscript {
} }
dependencies { dependencies {
//noinspection GradleDynamicVersion
classpath 'io.fabric.tools:gradle:1.+' classpath 'io.fabric.tools:gradle:1.+'
} }
} }
@ -25,7 +26,7 @@ android {
exclude 'META-INF/LICENSE' exclude 'META-INF/LICENSE'
exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/DEPENDENCIES'
} }
compileSdkVersion 26 compileSdkVersion 27
buildToolsVersion "26.0.2" buildToolsVersion "26.0.2"
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -34,9 +35,9 @@ android {
defaultConfig { defaultConfig {
applicationId "com.wbrawner.simplemarkdown" applicationId "com.wbrawner.simplemarkdown"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 26 targetSdkVersion 27
versionCode 2 versionCode 3
versionName "0.1.1" versionName "0.1.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
@ -50,15 +51,19 @@ android {
} }
} }
ext {
support_version = "27.0.2"
}
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
}) })
compile 'com.android.support:appcompat-v7:26.0.0' compile "com.android.support:appcompat-v7:$support_version"
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:26.0.0' compile "com.android.support:design:$support_version"
compile 'com.android.support:support-v13:26.0.0' compile "com.android.support:support-v13:$support_version"
compile 'com.commonsware.cwac:anddown:0.3.0' compile 'com.commonsware.cwac:anddown:0.3.0'
compile 'com.google.dagger:dagger:2.11' compile 'com.google.dagger:dagger:2.11'
compile 'com.jakewharton:butterknife:8.7.0' compile 'com.jakewharton:butterknife:8.7.0'
@ -67,9 +72,12 @@ dependencies {
compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0' compile 'io.reactivex.rxjava2:rxjava:2.1.0'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.1'
androidTestCompile 'com.android.support.test:runner:1.0.1'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11' annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
compile('com.crashlytics.sdk.android:crashlytics:2.8.0@aar') { compile('com.crashlytics.sdk.android:crashlytics:2.8.0@aar') {
transitive = true; transitive = true
} }
} }

View file

@ -0,0 +1,71 @@
package com.wbrawner.simplemarkdown;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import com.wbrawner.simplemarkdown.view.activity.MainActivity;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.junit.Assert.assertEquals;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class MainActivityTests {
@Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule(MainActivity.class);
@Before
public void setup() {
mActivityRule.getActivity()
.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void openAppTest() throws Exception {
UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
mDevice.pressHome();
// Bring up the default launcher by searching for a UI component
// that matches the content description for the launcher button.
UiObject allAppsButton = mDevice
.findObject(new UiSelector().description("Apps"));
// Perform a click on the button to load the launcher.
allAppsButton.clickAndWaitForNewWindow();
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.wbrawner.simplemarkdown", appContext.getPackageName());
UiScrollable appView = new UiScrollable(new UiSelector().scrollable(true));
UiSelector simpleMarkdownSelector = new UiSelector().text("Simple Markdown");
appView.scrollIntoView(simpleMarkdownSelector);
mDevice.findObject(simpleMarkdownSelector).clickAndWaitForNewWindow();
}
@Test
public void openFileWithoutFilesTest() {
openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
onView(withText("Open")).perform(click());
}
}

View file

@ -13,7 +13,8 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name=".view.activity.SplashActivity" <activity
android:name=".view.activity.SplashActivity"
android:theme="@style/AppTheme.Splash"> android:theme="@style/AppTheme.Splash">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -37,7 +38,7 @@
<data android:host="*" /> <data android:host="*" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".view.activity.MainActivity"></activity> <activity android:name=".view.activity.MainActivity" />
<provider <provider
android:name="android.support.v4.content.FileProvider" android:name="android.support.v4.content.FileProvider"
@ -54,6 +55,10 @@
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".view.activity.MainActivity" /> android:value=".view.activity.MainActivity" />
</activity> </activity>
<activity
android:name=".view.activity.ExplorerActivity"
android:label="@string/title_activity_explorer"
android:theme="@style/AppTheme.NoActionBar"></activity>
</application> </application>
</manifest> </manifest>

View file

@ -1,10 +1,7 @@
package com.wbrawner.simplemarkdown.model; package com.wbrawner.simplemarkdown.model;
import android.util.Log;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
@ -100,14 +97,16 @@ public class MarkdownFile {
} }
public int load(String path) { public int load(String path) {
Log.d(TAG, path); return load(new File(path));
}
public int load(File markdownFile) {
int code; int code;
File markdownFile = new File(path);
if (markdownFile.exists() && markdownFile.canRead()) { if (markdownFile.exists() && markdownFile.canRead()) {
BufferedReader reader = null; BufferedReader reader = null;
try { try {
this.name = markdownFile.getName(); this.name = markdownFile.getName();
this.path = markdownFile.getPath(); this.path = markdownFile.getParentFile().getAbsolutePath();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
String line; String line;
reader = new BufferedReader(new FileReader(markdownFile)); reader = new BufferedReader(new FileReader(markdownFile));
@ -171,6 +170,8 @@ public class MarkdownFile {
} else { } else {
code = WRITE_ERROR; code = WRITE_ERROR;
} }
this.name = markdownFile.getName();
this.path = markdownFile.getParentFile().getAbsolutePath();
return code; return code;
} }

View file

@ -6,6 +6,7 @@ import android.net.Uri;
import com.wbrawner.simplemarkdown.view.MarkdownEditView; import com.wbrawner.simplemarkdown.view.MarkdownEditView;
import com.wbrawner.simplemarkdown.view.MarkdownPreviewView; import com.wbrawner.simplemarkdown.view.MarkdownPreviewView;
import java.io.File;
import java.io.InputStream; import java.io.InputStream;
/** /**
@ -13,8 +14,10 @@ import java.io.InputStream;
*/ */
public interface MarkdownPresenter extends LifecyclePresenter { public interface MarkdownPresenter extends LifecyclePresenter {
File getFile();
void loadMarkdown(String filePath); void loadMarkdown(String filePath);
void loadMarkdown(InputStream in); void loadMarkdown(InputStream in);
void loadMarkdown(File file);
void loadFromUri(Context context, Uri fileUri); void loadFromUri(Context context, Uri fileUri);
void loadTempMarkdown(InputStream in, OnTempFileLoadedListener listener); void loadTempMarkdown(InputStream in, OnTempFileLoadedListener listener);
void setEditView(MarkdownEditView editView); void setEditView(MarkdownEditView editView);

View file

@ -10,6 +10,7 @@ import com.wbrawner.simplemarkdown.model.MarkdownFile;
import com.wbrawner.simplemarkdown.view.MarkdownEditView; import com.wbrawner.simplemarkdown.view.MarkdownEditView;
import com.wbrawner.simplemarkdown.view.MarkdownPreviewView; import com.wbrawner.simplemarkdown.view.MarkdownPreviewView;
import java.io.File;
import java.io.InputStream; import java.io.InputStream;
/** /**
@ -41,8 +42,19 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
@Override @Override
public void loadMarkdown(String filePath) { public void loadMarkdown(String filePath) {
File markdownFile = new File(filePath);
loadMarkdown(markdownFile);
}
@Override
public File getFile() {
return new File(file.getFullPath());
}
@Override
public void loadMarkdown(File file) {
Runnable fileLoader = () -> { Runnable fileLoader = () -> {
int result = file.load(filePath); int result = this.file.load(file);
if (editView != null) { if (editView != null) {
if (result == MarkdownFile.SUCCESS) { if (result == MarkdownFile.SUCCESS) {
editView.setMarkdown(getMarkdown()); editView.setMarkdown(getMarkdown());
@ -82,7 +94,6 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
} else { } else {
listener.onError(result); listener.onError(result);
} }
tmpFile = null;
}; };
fileLoader.run(); fileLoader.run();
} }

View file

@ -0,0 +1,221 @@
package com.wbrawner.simplemarkdown.view.activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.wbrawner.simplemarkdown.R;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.TreeSet;
public class ExplorerActivity extends AppCompatActivity {
private Handler fileHandler = new Handler();
private ListView listView;
private File[] mounts;
private String docsDirPath;
private String defaultDocsDirPath;
private int requestCode;
private String filePath;
private boolean isSave = false;
private EditText fileName;
private Button saveButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_explorer);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Intent intent = getIntent();
if (intent == null || !intent.hasExtra(MainActivity.EXTRA_REQUEST_CODE)) {
finish();
return;
}
defaultDocsDirPath = Environment.getExternalStorageDirectory() + "/" +
Environment.DIRECTORY_DOCUMENTS;
docsDirPath = defaultDocsDirPath;
requestCode = intent.getIntExtra(MainActivity.EXTRA_REQUEST_CODE, -1);
switch (requestCode) {
case MainActivity.OPEN_FILE_REQUEST:
break;
case MainActivity.SAVE_FILE_REQUEST:
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 (file.exists() && file.canWrite()) {
docsDirPath = file.getParentFile().getAbsolutePath();
fileName.setText(file.getName());
} else {
fileName.setText("Untitled.md");
}
}
saveButton = findViewById(R.id.button_save);
saveButton.setVisibility(View.VISIBLE);
saveButton.setOnClickListener((v) -> {
Intent fileIntent = new Intent();
String absolutePath = String.format(
Locale.ENGLISH,
"%s/%s",
filePath,
fileName.getText().toString()
);
fileIntent.putExtra(MainActivity.EXTRA_FILE_PATH, absolutePath);
setResult(RESULT_OK, fileIntent);
finish();
});
break;
default:
finish();
return;
}
// FloatingActionButton fab = findViewById(R.id.fab);
// fab.setOnClickListener(view ->
// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
// .setAction("Action", null)
// .show()
// );
listView = findViewById(R.id.file_list);
File docsDir = new File(docsDirPath);
if (!docsDir.exists()) {
docsDir = Environment.getExternalStorageDirectory();
}
updateListView(docsDir);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (hasRemovableStorage()) {
getMenuInflater().inflate(R.menu.menu_explorer, menu);
if (filePath.contains(mounts[1].getAbsolutePath())) {
menu.findItem(R.id.action_use_sdcard).setChecked(true);
}
return true;
}
return false;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_use_sdcard:
if (!hasRemovableStorage()) {
// We shouldn't get here to begin with but better safe than sorry
break;
}
item.setChecked(!item.isChecked());
if (item.isChecked()) {
updateListView(mounts[1]);
} else {
updateListView(new File(defaultDocsDirPath));
}
}
return true;
}
private boolean hasRemovableStorage() {
mounts = getExternalFilesDirs(Environment.DIRECTORY_DOCUMENTS);
return mounts.length > 1;
}
private List<HashMap<String, Object>> loadFiles(File docsDir) {
TreeSet files = new TreeSet<HashMap<String, Object>>((o1, o2) ->
((String) o1.get("name")).compareToIgnoreCase((String) o2.get("name"))) {
};
TreeSet dirs = new TreeSet<HashMap<String, Object>>((o1, o2) ->
((String) o1.get("name")).compareToIgnoreCase((String) o2.get("name"))) {
};
if (docsDir.getParentFile() != null && docsDir.getParentFile().canRead()) {
HashMap<String, Object> fileHashMap = new HashMap<>();
fileHashMap.put("name", "..");
fileHashMap.put("file", docsDir.getParentFile());
dirs.add(fileHashMap);
}
if (docsDir.listFiles() != null) {
for (File file : docsDir.listFiles()) {
if (file.isDirectory()) {
HashMap<String, Object> fileHashMap = new HashMap<>();
fileHashMap.put("name", file.getName());
fileHashMap.put("file", file);
dirs.add(fileHashMap);
continue;
}
if (!file.getName().endsWith("md")
&& !file.getName().endsWith("markdown")
&& !file.getName().endsWith("text")) {
continue;
}
HashMap<String, Object> fileHashMap = new HashMap<>();
fileHashMap.put("name", file.getName());
fileHashMap.put("file", file);
files.add(fileHashMap);
}
}
List<HashMap<String, Object>> sortedFiles = new ArrayList<>(dirs);
sortedFiles.addAll(files);
return sortedFiles;
}
private void updateListView(File filesDir) {
setTitle(filesDir.getName());
filePath = filesDir.getAbsolutePath();
fileHandler.post(() -> {
List<HashMap<String, Object>> files = loadFiles(filesDir);
listView.setAdapter(new SimpleAdapter(
this,
files,
android.R.layout.simple_list_item_1,
new String[]{"name"},
new int[]{android.R.id.text1}
));
listView.setOnItemClickListener((parent, view, position, id) -> {
File clickedFile = (File) files.get(position).get("file");
if (clickedFile.isFile()) {
handleFileClick(clickedFile);
} else if (clickedFile.isDirectory()) {
updateListView(clickedFile);
}
});
});
}
void handleFileClick(File file) {
if (isSave) {
if (fileName != null) {
fileName.setText(file.getName());
}
} else {
Intent fileIntent = new Intent();
fileIntent.putExtra(MainActivity.EXTRA_FILE, file);
setResult(RESULT_OK, fileIntent);
finish();
}
}
}

View file

@ -1,15 +1,11 @@
package com.wbrawner.simplemarkdown.view.activity; package com.wbrawner.simplemarkdown.view.activity;
import android.Manifest; import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.provider.OpenableColumns;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
@ -28,6 +24,8 @@ import com.wbrawner.simplemarkdown.MarkdownApplication;
import com.wbrawner.simplemarkdown.R; import com.wbrawner.simplemarkdown.R;
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter; import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter;
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter; import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter;
import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import javax.inject.Inject; import javax.inject.Inject;
@ -38,8 +36,12 @@ import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity public class MainActivity extends AppCompatActivity
implements ActivityCompat.OnRequestPermissionsResultCallback { implements ActivityCompat.OnRequestPermissionsResultCallback {
public static final int WRITE_PERMISSION_REQUEST = 0; static final int WRITE_PERMISSION_REQUEST = 0;
private static final int OPEN_FILE_REQUEST = 1; 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";
public static final String AUTHORITY = "com.wbrawner.simplemarkdown.fileprovider"; public static final String AUTHORITY = "com.wbrawner.simplemarkdown.fileprovider";
@Inject @Inject
@ -93,11 +95,11 @@ public class MainActivity extends AppCompatActivity
MainActivity.this, MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED) ) == PackageManager.PERMISSION_GRANTED)
showSaveDialog(); requestSave();
else { else {
if (Build.VERSION.SDK_INT >= 23) { if (Build.VERSION.SDK_INT >= 23) {
requestPermissions( requestPermissions(
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
WRITE_PERMISSION_REQUEST WRITE_PERMISSION_REQUEST
); );
} }
@ -113,7 +115,21 @@ public class MainActivity extends AppCompatActivity
)); ));
break; break;
case R.id.action_load: case R.id.action_load:
requestOpen(); if (ContextCompat.checkSelfPermission(
MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED)
requestOpen();
else {
if (Build.VERSION.SDK_INT >= 23) {
requestPermissions(
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
OPEN_FILE_REQUEST
);
}
}
break;
case R.id.action_new:
break; break;
case R.id.action_help: case R.id.action_help:
showInfoActivity(R.id.action_help); showInfoActivity(R.id.action_help);
@ -181,10 +197,6 @@ public class MainActivity extends AppCompatActivity
if (input.getText().length() > 0) { if (input.getText().length() > 0) {
presenter.setFileName(input.getText().toString()); presenter.setFileName(input.getText().toString());
setTitle(presenter.getFileName()); setTitle(presenter.getFileName());
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = getDocsPath() + input.getText();
presenter.saveMarkdown(path);
}
} }
}); });
builder.setNegativeButton("Cancel", (dialog, which) -> { builder.setNegativeButton("Cancel", (dialog, which) -> {
@ -195,8 +207,8 @@ public class MainActivity extends AppCompatActivity
} }
public String getDocsPath() { public String getDocsPath() {
return Environment.getExternalStorageDirectory() + "/" + return Environment.getExternalStorageDirectory() + "/" +
Environment.DIRECTORY_DOCUMENTS + "/"; Environment.DIRECTORY_DOCUMENTS + "/";
} }
@Override @Override
@ -214,7 +226,19 @@ public class MainActivity extends AppCompatActivity
Toast.makeText(MainActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT) Toast.makeText(MainActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT)
.show(); .show();
} }
return; break;
}
case OPEN_FILE_REQUEST: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, open file save dialog
requestOpen();
} else {
// Permission denied, do nothing
Toast.makeText(MainActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT)
.show();
}
break;
} }
} }
} }
@ -231,29 +255,44 @@ public class MainActivity extends AppCompatActivity
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { switch (requestCode) {
case OPEN_FILE_REQUEST: case OPEN_FILE_REQUEST:
if (resultCode == RESULT_OK) { if (resultCode != RESULT_OK || data == null || !data.hasExtra(EXTRA_FILE)) {
presenter.loadFromUri(MainActivity.this, data.getData()); break;
} }
presenter.loadMarkdown((File) data.getSerializableExtra(EXTRA_FILE));
break;
case SAVE_FILE_REQUEST:
if (resultCode != RESULT_OK
|| data == null
|| !data.hasExtra(EXTRA_FILE_PATH)
|| data.getStringExtra(EXTRA_FILE_PATH).isEmpty()) {
break;
}
String path = data.getStringExtra(EXTRA_FILE_PATH);
presenter.saveMarkdown(path);
setTitle(presenter.getFileName());
break;
} }
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
} }
private void requestOpen() { private void requestOpen() {
Intent openIntent = new Intent(Intent.ACTION_GET_CONTENT); Intent intent = new Intent(MainActivity.this, ExplorerActivity.class);
openIntent.setType("text/*"); intent.putExtra(EXTRA_REQUEST_CODE, OPEN_FILE_REQUEST);
openIntent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(
try { intent,
startActivityForResult( OPEN_FILE_REQUEST
Intent.createChooser( );
openIntent, }
getString(R.string.open_file)
), private void requestSave() {
OPEN_FILE_REQUEST Intent intent = new Intent(MainActivity.this, ExplorerActivity.class);
); intent.putExtra(EXTRA_REQUEST_CODE, SAVE_FILE_REQUEST);
} catch (ActivityNotFoundException e) { intent.putExtra(EXTRA_FILE, presenter.getFile());
Toast.makeText(MainActivity.this, R.string.no_filebrowser, Toast.LENGTH_SHORT) startActivityForResult(
.show(); intent,
} SAVE_FILE_REQUEST
);
} }
@Override @Override

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.wbrawner.simplemarkdown.view.activity.ExplorerActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/toolbarContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include
android:id="@+id/file_list_container"
layout="@layout/content_explorer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/file_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbarContainer" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/file_name"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_input_add" />
<EditText
android:id="@+id/file_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button_save"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button_save"
style="@style/ButtonRed"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:text="@string/action_save"
android:textAllCaps="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.wbrawner.simplemarkdown.view.activity.ExplorerActivity"
tools:showIn="@layout/activity_explorer">
<ListView
android:id="@+id/file_list"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

View file

@ -14,7 +14,13 @@
<item <item
android:id="@+id/action_load" android:id="@+id/action_load"
android:orderInCategory="100" android:orderInCategory="100"
android:title="@string/action_load" android:title="@string/action_open"
app:showAsAction="never" />
<item
android:id="@+id/action_new"
android:visible="false"
android:orderInCategory="150"
android:title="@string/action_new"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/action_help" android:id="@+id/action_help"

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:title="@string/action_use_sdcard"
android:id="@+id/action_use_sdcard"
app:showAsAction="never"
android:checkable="true" />
</menu>

View file

@ -2,5 +2,5 @@
<resources> <resources>
<color name="colorPrimary">#d32f2f</color> <color name="colorPrimary">#d32f2f</color>
<color name="colorPrimaryDark">#b71c1c</color> <color name="colorPrimaryDark">#b71c1c</color>
<color name="colorAccent">#ef9a9a</color> <color name="colorAccent">#d32f2f</color>
</resources> </resources>

View file

@ -24,4 +24,9 @@
<string name="error_write">An error occurred while writing the file</string> <string name="error_write">An error occurred while writing the file</string>
<string name="file_load_error">An error occurred while opening the file</string> <string name="file_load_error">An error occurred while opening the file</string>
<string name="action_libraries">Libraries</string> <string name="action_libraries">Libraries</string>
<string name="title_activity_explorer">ExplorerActivity</string>
<string name="action_new">New</string>
<string name="action_use_sdcard">Use SD Card</string>
<string name="action_done">Done</string>
<string name="action_open">Open</string>
</resources> </resources>

View file

@ -21,4 +21,9 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="ButtonRed">
<item name="android:background">@color/colorAccent</item>
<item name="android:textColor">#FFFFFF</item>
</style>
</resources> </resources>