MVP implementation
This commit is contained in:
parent
e4ba6d39bc
commit
6369d29e1d
24 changed files with 953 additions and 478 deletions
|
@ -2,6 +2,9 @@ apply plugin: 'com.android.application'
|
||||||
apply plugin: 'me.tatarka.retrolambda'
|
apply plugin: 'me.tatarka.retrolambda'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
configurations.all {
|
||||||
|
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
|
||||||
|
}
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/LICENSE-LGPL-2.1.txt'
|
exclude 'META-INF/LICENSE-LGPL-2.1.txt'
|
||||||
exclude 'META-INF/LICENSE-LGPL-3.txt'
|
exclude 'META-INF/LICENSE-LGPL-3.txt'
|
||||||
|
@ -49,9 +52,8 @@ dependencies {
|
||||||
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
|
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
|
||||||
compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
|
compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
|
||||||
compile 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
|
compile 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
|
||||||
compile "android.arch.lifecycle:runtime:1.0.0-alpha5"
|
compile 'com.google.dagger:dagger:2.11'
|
||||||
compile "android.arch.lifecycle:extensions:1.0.0-alpha5"
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha5"
|
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
|
android:name="com.wbrawner.simplemarkdown.MarkdownApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
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=".MainActivity">
|
<activity android:name=".view.activity.MainActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"></action>
|
<action android:name="android.intent.action.MAIN"></action>
|
||||||
<category android:name="android.intent.category.LAUNCHER"></category>
|
<category android:name="android.intent.category.LAUNCHER"></category>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.wbrawner.simplemarkdown;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.view.activity.MainActivity;
|
||||||
|
import com.wbrawner.simplemarkdown.view.fragment.EditFragment;
|
||||||
|
import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = { AppModule.class })
|
||||||
|
public interface AppComponent {
|
||||||
|
void inject(MarkdownApplication application);
|
||||||
|
void inject(MainActivity activity);
|
||||||
|
void inject(EditFragment fragment);
|
||||||
|
void inject(PreviewFragment fragment);
|
||||||
|
}
|
27
app/src/main/java/com/wbrawner/simplemarkdown/AppModule.java
Normal file
27
app/src/main/java/com/wbrawner/simplemarkdown/AppModule.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package com.wbrawner.simplemarkdown;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.model.MarkdownFile;
|
||||||
|
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter;
|
||||||
|
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenterImpl;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AppModule {
|
||||||
|
@Provides
|
||||||
|
public MarkdownFile provideMarkdownFile() {
|
||||||
|
return new MarkdownFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides @Singleton
|
||||||
|
public MarkdownPresenter provideMarkdownPresenter(MarkdownFile file) {
|
||||||
|
return new MarkdownPresenterImpl(file);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,74 +0,0 @@
|
||||||
package com.wbrawner.simplemarkdown;
|
|
||||||
|
|
||||||
import android.arch.lifecycle.ViewModelProvider;
|
|
||||||
import android.arch.lifecycle.ViewModelProviders;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
|
||||||
import android.support.v4.content.FileProvider;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.Layout;
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.jakewharton.rxbinding2.widget.RxTextView;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.Scheduler;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
|
|
||||||
import static android.content.ContentValues.TAG;
|
|
||||||
|
|
||||||
|
|
||||||
public class EditFragment extends Fragment {
|
|
||||||
public static final String SAVE_ACTION = "com.wbrawner.simplemarkdown.ACTION_SAVE";
|
|
||||||
public static final String LOAD_ACTION = "com.wbrawner.simplemarkdown.ACTION_LOAD";
|
|
||||||
private MarkdownViewModel markdownViewModel;
|
|
||||||
|
|
||||||
@BindView(R.id.markdown_edit)
|
|
||||||
EditText markdownEditor;
|
|
||||||
|
|
||||||
public EditFragment() {
|
|
||||||
// Required empty public constructor
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
View view = inflater.inflate(R.layout.fragment_edit, container, false);
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
markdownViewModel = ViewModelProviders.of(getActivity()).get(MarkdownViewModel.class);
|
|
||||||
Observable<String> obs = RxTextView.textChanges(markdownEditor)
|
|
||||||
.debounce(50, TimeUnit.MILLISECONDS).map(editable -> editable.toString());
|
|
||||||
obs.subscribeOn(Schedulers.io());
|
|
||||||
obs.observeOn(AndroidSchedulers.mainThread());
|
|
||||||
obs.subscribe(data -> {
|
|
||||||
markdownViewModel.updateMarkdown(data);
|
|
||||||
});
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package com.wbrawner.simplemarkdown;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by billy on 7/27/2017.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class FileUtils {
|
|
||||||
|
|
||||||
public static final int WRITE_PERMISSION_REQUEST = 0;
|
|
||||||
public static final int OPEN_FILE_REQUEST = 1;
|
|
||||||
|
|
||||||
private Activity mContext;
|
|
||||||
|
|
||||||
public FileUtils(Activity context) {
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExternalStorageWritable() {
|
|
||||||
String state = Environment.getExternalStorageState();
|
|
||||||
if (Environment.MEDIA_MOUNTED.equals(state)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExternalStorageReadable() {
|
|
||||||
String state = Environment.getExternalStorageState();
|
|
||||||
if (Environment.MEDIA_MOUNTED.equals(state) ||
|
|
||||||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExternalStorageWriteable() {
|
|
||||||
String state = Environment.getExternalStorageState();
|
|
||||||
if (Environment.MEDIA_MOUNTED.equals(state) && checkWritePermission()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkWritePermission() {
|
|
||||||
return (ContextCompat.checkSelfPermission(
|
|
||||||
mContext,
|
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
) == PackageManager.PERMISSION_GRANTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestWritePermissions() {
|
|
||||||
ActivityCompat.requestPermissions(
|
|
||||||
mContext,
|
|
||||||
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
|
||||||
WRITE_PERMISSION_REQUEST
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
package com.wbrawner.simplemarkdown;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.ClipData;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.VisibleForTesting;
|
|
||||||
import android.support.design.widget.TabLayout;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v4.content.FileProvider;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
import android.support.v4.os.EnvironmentCompat;
|
|
||||||
import android.support.v4.view.ViewPager;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.InputType;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.SearchEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.webkit.MimeTypeMap;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity
|
|
||||||
implements ActivityCompat.OnRequestPermissionsResultCallback {
|
|
||||||
|
|
||||||
public static final String AUTHORITY = "com.wbrawner.simplemarkdown.fileprovider";
|
|
||||||
private static final int REQUEST_WRITE_STORAGE = 0;
|
|
||||||
private static File mFilesDir;
|
|
||||||
public static final int FRAGMENT_EDIT = 0;
|
|
||||||
public static final int FRAGMENT_PREVIEW = 1;
|
|
||||||
public static final int NUM_PAGES = 2;
|
|
||||||
|
|
||||||
@BindView(R.id.pager)
|
|
||||||
ViewPager pager;
|
|
||||||
@BindView(R.id.layout_tab)
|
|
||||||
TabLayout tabLayout;
|
|
||||||
|
|
||||||
private static final String TAG = MainActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
getWindow().setBackgroundDrawable(new ColorDrawable(0xFFFFFFFF));
|
|
||||||
ButterKnife.bind(this);
|
|
||||||
pager.setAdapter(
|
|
||||||
new EditPagerAdapter(getSupportFragmentManager(), MainActivity.this)
|
|
||||||
);
|
|
||||||
pager.setPageMargin(1);
|
|
||||||
pager.setPageMarginDrawable(R.color.colorAccent);
|
|
||||||
mFilesDir = getFilesDir();
|
|
||||||
Intent intent = getIntent();
|
|
||||||
if (intent != null && !intent.getAction().equals(Intent.ACTION_MAIN) && intent.getData() != null) {
|
|
||||||
Intent loadIntent = new Intent(EditFragment.LOAD_ACTION);
|
|
||||||
loadIntent.putExtra("fileUri", intent.getData().toString());
|
|
||||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
|
||||||
.sendBroadcast(loadIntent);
|
|
||||||
}
|
|
||||||
if (getResources().getConfiguration().orientation
|
|
||||||
== Configuration.ORIENTATION_LANDSCAPE) {
|
|
||||||
tabLayout.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
super.onConfigurationChanged(newConfig);
|
|
||||||
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
|
|
||||||
tabLayout.setVisibility(View.GONE);
|
|
||||||
else
|
|
||||||
tabLayout.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.menu_edit, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
// switch (item.getItemId()) {
|
|
||||||
// case R.id.action_save:
|
|
||||||
// //TODO: Create popup for file name
|
|
||||||
// AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
// builder.setTitle(R.string.action_save);
|
|
||||||
//
|
|
||||||
// final EditText input = new EditText(this);
|
|
||||||
// input.setInputType(InputType.TYPE_CLASS_TEXT);
|
|
||||||
// input.setHint(R.string.hint_filename);
|
|
||||||
// input.setText(getFileName());
|
|
||||||
// builder.setView(input);
|
|
||||||
//
|
|
||||||
// builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onClick(DialogInterface dialog, int which) {
|
|
||||||
// if (input.getText().length() > 0) {
|
|
||||||
// setFileName(input.getText().toString());
|
|
||||||
// requestSave(input.getText().toString());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onClick(DialogInterface dialog, int which) {
|
|
||||||
// dialog.cancel();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// builder.show();
|
|
||||||
// break;
|
|
||||||
// case R.id.action_share:
|
|
||||||
// //TODO: Fix this
|
|
||||||
// File tmpFile = new File(getTempFilePath() + getFileName());
|
|
||||||
// if (!tmpFile.exists()) {
|
|
||||||
// Intent saveIntent = new Intent(EditFragment.SAVE_ACTION);
|
|
||||||
// saveIntent.putExtra("fileName", getTempFilePath() + getFileName());
|
|
||||||
// LocalBroadcastManager.getInstance(getApplicationContext())
|
|
||||||
// .sendBroadcast(saveIntent);
|
|
||||||
// }
|
|
||||||
// Uri fileUri = FileProvider.getUriForFile(MainActivity.this, AUTHORITY, tmpFile);
|
|
||||||
// if (fileUri != null) {
|
|
||||||
// try {
|
|
||||||
// Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
|
||||||
// shareIntent.setDataAndType(
|
|
||||||
// fileUri,
|
|
||||||
// getContentResolver().getType(fileUri)
|
|
||||||
// );
|
|
||||||
// shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
|
||||||
// shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
// startActivity(
|
|
||||||
// Intent.createChooser(
|
|
||||||
// shareIntent,
|
|
||||||
// getString(R.string.share_file)
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// } catch (ActivityNotFoundException e) {
|
|
||||||
// Log.e(TAG, "Error sharing file", e);
|
|
||||||
// Toast.makeText(
|
|
||||||
// MainActivity.this,
|
|
||||||
// R.string.no_shareable_apps,
|
|
||||||
// Toast.LENGTH_SHORT
|
|
||||||
// ).show();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// case R.id.action_load:
|
|
||||||
// requestOpen();
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// return super.onOptionsItemSelected(item);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private void requestSave(String text) {
|
|
||||||
Intent saveIntent = new Intent(EditFragment.SAVE_ACTION);
|
|
||||||
saveIntent.putExtra("fileName", text);
|
|
||||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
|
||||||
.sendBroadcast(saveIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestOpen() {
|
|
||||||
Intent openIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
||||||
openIntent.setType("*/*");
|
|
||||||
openIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
||||||
try {
|
|
||||||
startActivityForResult(
|
|
||||||
Intent.createChooser(
|
|
||||||
openIntent,
|
|
||||||
getString(R.string.open_file)
|
|
||||||
),
|
|
||||||
FileUtils.OPEN_FILE_REQUEST
|
|
||||||
);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Toast.makeText(MainActivity.this, R.string.no_filebrowser, Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onRequestPermissionsResult(int requestCode,
|
|
||||||
// String permissions[], int[] grantResults) {
|
|
||||||
// switch (requestCode) {
|
|
||||||
// case FileUtils.WRITE_PERMISSION_REQUEST: {
|
|
||||||
// // If request is cancelled, the result arrays are empty.
|
|
||||||
// if (grantResults.length > 0
|
|
||||||
// && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// // Permission granted, open file chooser dialog
|
|
||||||
// requestSave(getFileName());
|
|
||||||
// } else {
|
|
||||||
// // Permission denied, do nothing
|
|
||||||
// Toast.makeText(MainActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT)
|
|
||||||
// .show();
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
if (pager.getCurrentItem() == FRAGMENT_EDIT)
|
|
||||||
super.onBackPressed();
|
|
||||||
else
|
|
||||||
pager.setCurrentItem(FRAGMENT_EDIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
switch (requestCode) {
|
|
||||||
case FileUtils.OPEN_FILE_REQUEST:
|
|
||||||
if (resultCode == RESULT_OK) {
|
|
||||||
Uri fileUri = data.getData();
|
|
||||||
Intent loadIntent = new Intent(EditFragment.LOAD_ACTION);
|
|
||||||
loadIntent.putExtra("fileUri", fileUri.toString());
|
|
||||||
LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(loadIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.wbrawner.simplemarkdown;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MarkdownApplication extends Application {
|
||||||
|
|
||||||
|
private AppComponent component;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
component = DaggerAppComponent.builder()
|
||||||
|
.appModule(new AppModule())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppComponent getComponent() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,10 @@
|
||||||
package com.wbrawner.simplemarkdown;
|
package com.wbrawner.simplemarkdown;
|
||||||
|
|
||||||
import android.arch.lifecycle.LiveData;
|
public class MarkdownViewModel {
|
||||||
import android.arch.lifecycle.MutableLiveData;
|
/*
|
||||||
import android.arch.lifecycle.ViewModel;
|
private static final String TAG = MarkdownViewModel.class.getSimpleName();
|
||||||
|
private File file;
|
||||||
import com.commonsware.cwac.anddown.AndDown;
|
public MutableLiveData<String> markdownLiveData;
|
||||||
|
|
||||||
public class MarkdownViewModel extends ViewModel {
|
|
||||||
|
|
||||||
private MutableLiveData<String> markdownLiveData;
|
|
||||||
private MutableLiveData<String> htmlLiveData = new MutableLiveData<>();;
|
private MutableLiveData<String> htmlLiveData = new MutableLiveData<>();;
|
||||||
|
|
||||||
public MarkdownViewModel() {
|
public MarkdownViewModel() {
|
||||||
|
@ -34,4 +30,47 @@ public class MarkdownViewModel extends ViewModel {
|
||||||
public LiveData<String> getHtml() {
|
public LiveData<String> getHtml() {
|
||||||
return htmlLiveData;
|
return htmlLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void openFile(String filePath) {
|
||||||
|
file = new File(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
if (file == null || file.getName().isEmpty())
|
||||||
|
return "Untitled.md";
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean saveFile(String filePath, @Nullable String fileName) {
|
||||||
|
if (fileName == null) {
|
||||||
|
if (file != null)
|
||||||
|
fileName = file.getName();
|
||||||
|
else
|
||||||
|
fileName = "Untitled.md";
|
||||||
|
}
|
||||||
|
if (!filePath.endsWith("/"))
|
||||||
|
filePath += "/";
|
||||||
|
final boolean result;
|
||||||
|
new AsyncTask<String, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(String... strings) {
|
||||||
|
try {
|
||||||
|
PrintWriter writer = new PrintWriter(strings[0], "UTF-8");
|
||||||
|
writer.write(markdownLiveData.getValue());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Error saving file: ", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute(filePath + fileName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestSave(String s) {
|
||||||
|
// Do something to save the file?
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMarkdown() {
|
||||||
|
return markdownLiveData.getValue();
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
package com.wbrawner.simplemarkdown;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.arch.lifecycle.LifecycleFragment;
|
|
||||||
import android.arch.lifecycle.Observer;
|
|
||||||
import android.arch.lifecycle.ViewModelProviders;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
|
|
||||||
import com.commonsware.cwac.anddown.AndDown;
|
|
||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
|
||||||
import org.reactivestreams.Subscription;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.processors.PublishProcessor;
|
|
||||||
import io.reactivex.subjects.PublishSubject;
|
|
||||||
import io.reactivex.subjects.Subject;
|
|
||||||
|
|
||||||
public class PreviewFragment extends LifecycleFragment {
|
|
||||||
private static final String TAG = PreviewFragment.class.getSimpleName();
|
|
||||||
private static final int INTERNET_REQUEST = 0;
|
|
||||||
private MarkdownViewModel markdownViewModel;
|
|
||||||
|
|
||||||
@BindView(R.id.markdown_view)
|
|
||||||
WebView markdownView;
|
|
||||||
|
|
||||||
public static final String SCROLL_ACTION = "com.wbrawner.simplemarkdown.scroll";
|
|
||||||
public static final String PREVIEW_ACTION = "com.wbrawner.simplemarkdown.preview";
|
|
||||||
|
|
||||||
public PreviewFragment() {
|
|
||||||
// Required empty public constructor
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
View view = inflater.inflate(R.layout.fragment_preview, container, false);
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
markdownViewModel = ViewModelProviders.of(getActivity()).get(MarkdownViewModel.class);
|
|
||||||
markdownViewModel.getHtml().observe(this, s -> markdownView.loadData(s, "text/html", "UTF-8"));
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
||||||
WebView.setWebContentsDebuggingEnabled(true);
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
package com.wbrawner.simplemarkdown.model;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import static android.content.ContentValues.TAG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MarkdownFile {
|
||||||
|
public static final int SUCCESS = 0;
|
||||||
|
public static final int FILE_EXISTS = 1;
|
||||||
|
public static final int FILE_NOT_EXISTS = 2;
|
||||||
|
public static final int READ_ERROR = 3;
|
||||||
|
public static final int WRITE_ERROR = 4;
|
||||||
|
public static final int PARAMETERS_MISSING = 5;
|
||||||
|
private String name;
|
||||||
|
private String path;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public MarkdownFile(String name, String path, String content) {
|
||||||
|
this.name = name;
|
||||||
|
this.path = path;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarkdownFile(String path) {
|
||||||
|
int code = load(path);
|
||||||
|
if (code != SUCCESS) {
|
||||||
|
this.name = path.substring(
|
||||||
|
path.lastIndexOf("/") + 1
|
||||||
|
);
|
||||||
|
this.path = path.substring(
|
||||||
|
0,
|
||||||
|
path.lastIndexOf("/")
|
||||||
|
);
|
||||||
|
this.content = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarkdownFile() {
|
||||||
|
this.name = "Untitled.md";
|
||||||
|
this.path = "";
|
||||||
|
this.content = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullPath() {
|
||||||
|
String fullPath;
|
||||||
|
if (!this.path.endsWith("/"))
|
||||||
|
fullPath = this.path + "/";
|
||||||
|
else
|
||||||
|
fullPath = this.path;
|
||||||
|
return fullPath + this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int load(InputStream in) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Scanner s = new java.util.Scanner(in).useDelimiter("\\n");
|
||||||
|
while(s.hasNext()) {
|
||||||
|
sb.append(s.next() + "\n");
|
||||||
|
}
|
||||||
|
this.content = sb.toString();
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int load(String path) {
|
||||||
|
Log.d(TAG, path);
|
||||||
|
int code;
|
||||||
|
File markdownFile = new File(path);
|
||||||
|
if (markdownFile.exists() && markdownFile.canRead()) {
|
||||||
|
BufferedReader reader = null;
|
||||||
|
try {
|
||||||
|
this.name = markdownFile.getName();
|
||||||
|
this.path = markdownFile.getPath();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
reader = new BufferedReader(new FileReader(markdownFile));
|
||||||
|
while ((line = reader.readLine()) != null)
|
||||||
|
sb.append(line + "\n");
|
||||||
|
this.content = sb.toString();
|
||||||
|
code = SUCCESS;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
code = FILE_NOT_EXISTS;
|
||||||
|
} catch (IOException e) {
|
||||||
|
code = READ_ERROR;
|
||||||
|
}
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// closing the reader failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code = READ_ERROR;
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int load() {
|
||||||
|
if (!parametersOk())
|
||||||
|
return PARAMETERS_MISSING;
|
||||||
|
return load(getFullPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int save(String path) {
|
||||||
|
int code;
|
||||||
|
File markdownFile = new File(path);
|
||||||
|
if (!markdownFile.exists()) {
|
||||||
|
try {
|
||||||
|
markdownFile.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return WRITE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (markdownFile.canWrite()) {
|
||||||
|
OutputStreamWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new OutputStreamWriter(
|
||||||
|
new FileOutputStream(markdownFile)
|
||||||
|
);
|
||||||
|
writer.write(this.content);
|
||||||
|
code = SUCCESS;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
code = WRITE_ERROR;
|
||||||
|
}
|
||||||
|
if (writer != null) {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// closing the reader failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code = WRITE_ERROR;
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int save() {
|
||||||
|
if (!parametersOk())
|
||||||
|
return PARAMETERS_MISSING;
|
||||||
|
return save(this.getFullPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fileExists(String path) {
|
||||||
|
if (new File(path).exists())
|
||||||
|
return FILE_EXISTS;
|
||||||
|
return FILE_NOT_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fileExists() {
|
||||||
|
if (parametersOk())
|
||||||
|
return fileExists(getFullPath());
|
||||||
|
return PARAMETERS_MISSING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parametersOk() {
|
||||||
|
return !this.name.isEmpty() && !this.path.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.wbrawner.simplemarkdown.presentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface LifecyclePresenter {
|
||||||
|
void resume();
|
||||||
|
void pause();
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.wbrawner.simplemarkdown.presentation;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.view.MarkdownEditView;
|
||||||
|
import com.wbrawner.simplemarkdown.view.MarkdownPreviewView;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface MarkdownPresenter extends LifecyclePresenter {
|
||||||
|
void loadMarkdown(String filePath);
|
||||||
|
void loadMarkdown(InputStream in);
|
||||||
|
void setEditView(MarkdownEditView editView);
|
||||||
|
void setPreviewView(MarkdownPreviewView previewView);
|
||||||
|
void saveMarkdown(String filePath);
|
||||||
|
void onMarkdownEdited();
|
||||||
|
void onMarkdownEdited(String markdown);
|
||||||
|
String getFileName();
|
||||||
|
void setFileName(String name);
|
||||||
|
String getMarkdown();
|
||||||
|
void setMarkdown(String markdown);
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package com.wbrawner.simplemarkdown.presentation;
|
||||||
|
|
||||||
|
import com.commonsware.cwac.anddown.AndDown;
|
||||||
|
import com.wbrawner.simplemarkdown.model.MarkdownFile;
|
||||||
|
import com.wbrawner.simplemarkdown.view.MarkdownEditView;
|
||||||
|
import com.wbrawner.simplemarkdown.view.MarkdownPreviewView;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MarkdownPresenterImpl implements MarkdownPresenter {
|
||||||
|
private MarkdownFile file;
|
||||||
|
private MarkdownEditView editView;
|
||||||
|
private MarkdownPreviewView previewView;
|
||||||
|
private String TAG = MarkdownPresenterImpl.class.getSimpleName();
|
||||||
|
|
||||||
|
public MarkdownPresenterImpl(MarkdownFile file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
saveMarkdown("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMarkdown(String filePath) {
|
||||||
|
Runnable fileLoader = () -> {
|
||||||
|
int result = file.load(filePath);
|
||||||
|
if (result == MarkdownFile.SUCCESS) {
|
||||||
|
editView.setMarkdown(getMarkdown());
|
||||||
|
onMarkdownEdited();
|
||||||
|
} else {
|
||||||
|
editView.showFileLoadeddError(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileLoader.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMarkdown(InputStream in) {
|
||||||
|
Runnable fileLoader = () -> {
|
||||||
|
int result = file.load(in);
|
||||||
|
if (result == MarkdownFile.SUCCESS) {
|
||||||
|
editView.setMarkdown(getMarkdown());
|
||||||
|
onMarkdownEdited();
|
||||||
|
} else {
|
||||||
|
editView.showFileLoadeddError(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileLoader.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEditView(MarkdownEditView editView) {
|
||||||
|
this.editView = editView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreviewView(MarkdownPreviewView previewView) {
|
||||||
|
this.previewView = previewView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveMarkdown(String filePath) {
|
||||||
|
Runnable fileSaver = () -> {
|
||||||
|
int code;
|
||||||
|
code = file.save(filePath);
|
||||||
|
if (code == MarkdownFile.SUCCESS) {
|
||||||
|
editView.showFileSavedMessage();
|
||||||
|
} else {
|
||||||
|
editView.showFileSavedError(code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileSaver.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMarkdownEdited(String markdown) {
|
||||||
|
Runnable generateMarkdown = () -> {
|
||||||
|
AndDown andDown = new AndDown();
|
||||||
|
int hoedownFlags =
|
||||||
|
AndDown.HOEDOWN_EXT_STRIKETHROUGH | AndDown.HOEDOWN_EXT_TABLES |
|
||||||
|
AndDown.HOEDOWN_EXT_UNDERLINE | AndDown.HOEDOWN_EXT_SUPERSCRIPT |
|
||||||
|
AndDown.HOEDOWN_EXT_FENCED_CODE;
|
||||||
|
if (previewView != null)
|
||||||
|
previewView.updatePreview(andDown.markdownToHtml(markdown, hoedownFlags, 0));
|
||||||
|
};
|
||||||
|
generateMarkdown.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMarkdownEdited() {
|
||||||
|
onMarkdownEdited(getMarkdown());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFileName() {
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFileName(String name) {
|
||||||
|
file.setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMarkdown() {
|
||||||
|
return file.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMarkdown(String markdown) {
|
||||||
|
file.setContent(markdown);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.wbrawner.simplemarkdown.view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface MarkdownEditView {
|
||||||
|
String getMarkdown();
|
||||||
|
void setMarkdown(String markdown);
|
||||||
|
|
||||||
|
void showFileSavedMessage();
|
||||||
|
void showFileSavedError(int code);
|
||||||
|
void showFileLoadedMessage();
|
||||||
|
void showFileLoadeddError(int code);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.wbrawner.simplemarkdown.view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by billy on 8/22/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface MarkdownPreviewView {
|
||||||
|
void updatePreview(String html);
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
package com.wbrawner.simplemarkdown.view.activity;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
import android.support.design.widget.TabLayout;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.InputType;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.MarkdownApplication;
|
||||||
|
import com.wbrawner.simplemarkdown.R;
|
||||||
|
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter;
|
||||||
|
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity
|
||||||
|
implements ActivityCompat.OnRequestPermissionsResultCallback {
|
||||||
|
|
||||||
|
public static final int WRITE_PERMISSION_REQUEST = 0;
|
||||||
|
private static final int OPEN_FILE_REQUEST = 1;
|
||||||
|
public static final String AUTHORITY = "com.wbrawner.simplemarkdown.fileprovider";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MarkdownPresenter presenter;
|
||||||
|
|
||||||
|
@BindView(R.id.pager)
|
||||||
|
ViewPager pager;
|
||||||
|
@BindView(R.id.layout_tab)
|
||||||
|
TabLayout tabLayout;
|
||||||
|
|
||||||
|
private static final String TAG = MainActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
((MarkdownApplication) getApplication()).getComponent().inject(this);
|
||||||
|
|
||||||
|
// Reset the background color
|
||||||
|
getWindow().setBackgroundDrawable(new ColorDrawable(0xFFFFFFFF));
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
pager.setAdapter(
|
||||||
|
new EditPagerAdapter(getSupportFragmentManager(), MainActivity.this)
|
||||||
|
);
|
||||||
|
pager.setPageMargin(1);
|
||||||
|
pager.setPageMarginDrawable(R.color.colorAccent);
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (intent != null && !intent.getAction().equals(Intent.ACTION_MAIN) && intent.getData() != null) {
|
||||||
|
loadFromUri(intent.getData());
|
||||||
|
}
|
||||||
|
if (getResources().getConfiguration().orientation
|
||||||
|
== Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
|
tabLayout.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
|
||||||
|
tabLayout.setVisibility(View.GONE);
|
||||||
|
else
|
||||||
|
tabLayout.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.menu_edit, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.action_save:
|
||||||
|
if (ContextCompat.checkSelfPermission(
|
||||||
|
MainActivity.this,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
) == PackageManager.PERMISSION_GRANTED)
|
||||||
|
showSaveDialog();
|
||||||
|
else {
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
requestPermissions(
|
||||||
|
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||||
|
WRITE_PERMISSION_REQUEST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R.id.action_share:
|
||||||
|
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_TEXT, presenter.getMarkdown());
|
||||||
|
shareIntent.setType("text/plain");
|
||||||
|
startActivity(Intent.createChooser(
|
||||||
|
shareIntent,
|
||||||
|
getString(R.string.share_file)
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case R.id.action_load:
|
||||||
|
requestOpen();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSaveDialog() {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle(R.string.action_save);
|
||||||
|
|
||||||
|
final EditText input = new EditText(this);
|
||||||
|
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
input.setHint(R.string.hint_filename);
|
||||||
|
input.setText(presenter.getFileName());
|
||||||
|
builder.setView(input);
|
||||||
|
|
||||||
|
builder.setPositiveButton("OK", (dialog, which) -> {
|
||||||
|
if (input.getText().length() > 0) {
|
||||||
|
presenter.setFileName(input.getText().toString());
|
||||||
|
setTitle(input.getText());
|
||||||
|
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
|
String path = Environment.getExternalStorageDirectory() + "/" +
|
||||||
|
Environment.DIRECTORY_DOCUMENTS + "/" + input.getText();
|
||||||
|
presenter.saveMarkdown(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton("Cancel", (dialog, which) -> {
|
||||||
|
dialog.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode,
|
||||||
|
String permissions[], int[] grantResults) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case WRITE_PERMISSION_REQUEST: {
|
||||||
|
// If request is cancelled, the result arrays are empty.
|
||||||
|
if (grantResults.length > 0
|
||||||
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// Permission granted, open file save dialog
|
||||||
|
showSaveDialog();
|
||||||
|
} else {
|
||||||
|
// Permission denied, do nothing
|
||||||
|
Toast.makeText(MainActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (pager.getCurrentItem() == EditPagerAdapter.FRAGMENT_EDIT)
|
||||||
|
super.onBackPressed();
|
||||||
|
else
|
||||||
|
pager.setCurrentItem(EditPagerAdapter.FRAGMENT_EDIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case OPEN_FILE_REQUEST:
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
loadFromUri(data.getData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadFromUri(Uri fileUri) {
|
||||||
|
try {
|
||||||
|
InputStream in =
|
||||||
|
getContentResolver().openInputStream(fileUri);
|
||||||
|
Cursor retCur = getContentResolver()
|
||||||
|
.query(fileUri, null, null, null, null);
|
||||||
|
if (retCur != null) {
|
||||||
|
int nameIndex = retCur
|
||||||
|
.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||||
|
retCur.moveToFirst();
|
||||||
|
presenter.setFileName(retCur.getString(nameIndex));
|
||||||
|
}
|
||||||
|
presenter.loadMarkdown(in);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(MainActivity.this, R.string.file_load_error, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestOpen() {
|
||||||
|
Intent openIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
openIntent.setType("text/*");
|
||||||
|
openIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
try {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent.createChooser(
|
||||||
|
openIntent,
|
||||||
|
getString(R.string.open_file)
|
||||||
|
),
|
||||||
|
OPEN_FILE_REQUEST
|
||||||
|
);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(MainActivity.this, R.string.no_filebrowser, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.wbrawner.simplemarkdown;
|
package com.wbrawner.simplemarkdown.view.adapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by billy on 7/29/2017.
|
* Created by billy on 7/29/2017.
|
||||||
|
@ -10,11 +10,15 @@ import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
import android.support.v4.app.FragmentPagerAdapter;
|
||||||
|
|
||||||
import static com.wbrawner.simplemarkdown.MainActivity.FRAGMENT_EDIT;
|
import com.wbrawner.simplemarkdown.R;
|
||||||
import static com.wbrawner.simplemarkdown.MainActivity.FRAGMENT_PREVIEW;
|
import com.wbrawner.simplemarkdown.view.fragment.EditFragment;
|
||||||
import static com.wbrawner.simplemarkdown.MainActivity.NUM_PAGES;
|
import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment;
|
||||||
|
|
||||||
|
public class EditPagerAdapter extends FragmentPagerAdapter {
|
||||||
|
public static final int FRAGMENT_EDIT = 0;
|
||||||
|
public static final int FRAGMENT_PREVIEW = 1;
|
||||||
|
public static final int NUM_PAGES = 2;
|
||||||
|
|
||||||
class EditPagerAdapter extends FragmentPagerAdapter {
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
public EditPagerAdapter(FragmentManager fm, Context context) {
|
public EditPagerAdapter(FragmentManager fm, Context context) {
|
|
@ -0,0 +1,112 @@
|
||||||
|
package com.wbrawner.simplemarkdown.view.fragment;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.jakewharton.rxbinding2.widget.RxTextView;
|
||||||
|
import com.wbrawner.simplemarkdown.MarkdownApplication;
|
||||||
|
import com.wbrawner.simplemarkdown.R;
|
||||||
|
import com.wbrawner.simplemarkdown.model.MarkdownFile;
|
||||||
|
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter;
|
||||||
|
import com.wbrawner.simplemarkdown.view.MarkdownEditView;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
public class EditFragment extends Fragment implements MarkdownEditView {
|
||||||
|
public static final String SAVE_ACTION = "com.wbrawner.simplemarkdown.ACTION_SAVE";
|
||||||
|
public static final String LOAD_ACTION = "com.wbrawner.simplemarkdown.ACTION_LOAD";
|
||||||
|
private String TAG = EditFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MarkdownPresenter presenter;
|
||||||
|
|
||||||
|
@BindView(R.id.markdown_edit)
|
||||||
|
EditText markdownEditor;
|
||||||
|
|
||||||
|
public EditFragment() {
|
||||||
|
// Required empty public constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
View view = inflater.inflate(R.layout.fragment_edit, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
((MarkdownApplication) getActivity().getApplication()).getComponent().inject(this);
|
||||||
|
|
||||||
|
Observable<String> obs = RxTextView.textChanges(markdownEditor)
|
||||||
|
.debounce(50, TimeUnit.MILLISECONDS).map(CharSequence::toString);
|
||||||
|
obs.subscribeOn(Schedulers.io());
|
||||||
|
obs.observeOn(AndroidSchedulers.mainThread());
|
||||||
|
obs.subscribe(markdown -> {
|
||||||
|
presenter.onMarkdownEdited(markdown);
|
||||||
|
});
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
presenter.setEditView(this);
|
||||||
|
setMarkdown(presenter.getMarkdown());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
presenter.setEditView(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMarkdown() {
|
||||||
|
return markdownEditor.getText().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showFileSavedMessage() {
|
||||||
|
Toast.makeText(getActivity(), R.string.file_saved, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showFileSavedError(int code) {
|
||||||
|
String message = "";
|
||||||
|
switch (code) {
|
||||||
|
case MarkdownFile.WRITE_ERROR:
|
||||||
|
message = getString(R.string.error_write);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = getString(R.string.file_save_error);
|
||||||
|
}
|
||||||
|
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showFileLoadedMessage() {
|
||||||
|
Toast.makeText(getActivity(), R.string.file_loaded, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showFileLoadeddError(int code) {
|
||||||
|
String message = "";
|
||||||
|
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMarkdown(String markdown) {
|
||||||
|
markdownEditor.setText(markdown);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.wbrawner.simplemarkdown.view.fragment;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
|
||||||
|
import com.wbrawner.simplemarkdown.MarkdownApplication;
|
||||||
|
import com.wbrawner.simplemarkdown.R;
|
||||||
|
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter;
|
||||||
|
import com.wbrawner.simplemarkdown.view.MarkdownPreviewView;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class PreviewFragment extends Fragment implements MarkdownPreviewView {
|
||||||
|
private static final String TAG = PreviewFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MarkdownPresenter presenter;
|
||||||
|
|
||||||
|
@BindView(R.id.markdown_view)
|
||||||
|
WebView markdownPreview;
|
||||||
|
|
||||||
|
public PreviewFragment() {
|
||||||
|
// Required empty public constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
View view = inflater.inflate(R.layout.fragment_preview, container, false);
|
||||||
|
ButterKnife.bind(this, view);
|
||||||
|
((MarkdownApplication) getActivity().getApplication()).getComponent().inject(this);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
|
WebView.setWebContentsDebuggingEnabled(true);
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePreview(String html) {
|
||||||
|
markdownPreview.post(() -> {
|
||||||
|
markdownPreview.loadData(html, "text/html", "UTF-8");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
presenter.setPreviewView(this);
|
||||||
|
presenter.onMarkdownEdited();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
presenter.setPreviewView(null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.wbrawner.simplemarkdown.EditFragment">
|
tools:context="com.wbrawner.simplemarkdown.view.fragment.EditFragment">
|
||||||
<EditText
|
<EditText
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.wbrawner.simplemarkdown.PreviewFragment">
|
tools:context="com.wbrawner.simplemarkdown.view.fragment.PreviewFragment">
|
||||||
|
|
||||||
<WebView
|
<WebView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
|
||||||
android:title="@string/action_save"
|
|
||||||
android:id="@+id/action_save"
|
|
||||||
android:icon="@drawable/ic_action_save"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
<item
|
<item
|
||||||
android:title="@string/action_share"
|
android:title="@string/action_share"
|
||||||
android:id="@+id/action_share"
|
android:id="@+id/action_share"
|
||||||
android:icon="@drawable/ic_action_share"
|
android:icon="@drawable/ic_action_share"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="ifRoom" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_load"
|
android:title="@string/action_save"
|
||||||
android:orderInCategory="100"
|
android:id="@+id/action_save"
|
||||||
android:title="@string/action_load"
|
android:icon="@drawable/ic_action_save"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_load"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:title="@string/action_load"
|
||||||
|
app:showAsAction="never" />
|
||||||
<!--<item-->
|
<!--<item-->
|
||||||
<!--android:id="@+id/action_help"-->
|
<!--android:id="@+id/action_help"-->
|
||||||
<!--android:orderInCategory="100"-->
|
<!--android:orderInCategory="100"-->
|
||||||
|
|
|
@ -19,4 +19,8 @@
|
||||||
<string name="action_load">Load</string>
|
<string name="action_load">Load</string>
|
||||||
<string name="open_file">Select a file to open</string>
|
<string name="open_file">Select a file to open</string>
|
||||||
<string name="no_filebrowser">No file browser apps found</string>
|
<string name="no_filebrowser">No file browser apps found</string>
|
||||||
|
<string name="file_save_error">An error occurred while saving the file</string>
|
||||||
|
<string name="file_loaded">File successfully loaded</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>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue