From 1e50e6d9da969efe12e80ccf4bab3d7ca3ac4cd4 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Sat, 21 Oct 2017 15:10:34 +0800 Subject: [PATCH] add: uploaded script options --- app/build.gradle | 4 + .../external/tasker/TaskPrefEditActivity.java | 5 +- .../widget/ScriptWidgetSettingsActivity.java | 5 +- .../script => io}/StorageFileProvider.java | 4 +- .../scriptdroid/io/TmpScriptFiles.java | 40 ++++++ .../scriptdroid/model/script/ScriptFile.java | 31 ----- .../scriptdroid/model/script/Scripts.java | 1 + .../download/DownloadFailedException.java | 23 +++ .../network/download/DownloadManager.java | 124 +++++++++++++++++ .../sublime/SublimeResponseHandler.java | 2 +- .../scriptdroid/ui/common/OptionListView.java | 131 ++++++++++++++++++ .../ui/common/ScriptOperations.java | 70 ++++++++-- .../filechooser/FileChooserDialogBuilder.java | 26 +++- .../scriptdroid/ui/main/MainActivity.java | 6 +- .../ui/main/community/CommunityFragment.java | 2 +- .../ui/main/community/CommunityWebView.java | 116 ++++++++++++++++ .../ui/main/scripts/MyScriptListFragment.java | 2 +- .../ui/main/scripts/ScriptListView.java | 5 +- .../ui/update/UpdateInfoDialogBuilder.java | 2 +- .../java/com/stardust/widget/EWebView.java | 4 +- .../ic_file_download_black_48dp.png | Bin 0 -> 173 bytes .../ic_file_download_black_48dp.png | Bin 0 -> 144 bytes .../ic_file_download_black_48dp.png | Bin 0 -> 209 bytes .../ic_file_download_black_48dp.png | Bin 0 -> 264 bytes .../ic_file_download_black_48dp.png | Bin 0 -> 305 bytes .../main/res/layout/fragment_community.xml | 2 +- app/src/main/res/layout/option_list_view.xml | 27 ++++ app/src/main/res/values/strings.xml | 7 +- .../src/main/java/com/stardust/pio/PFile.java | 12 +- 29 files changed, 583 insertions(+), 68 deletions(-) rename app/src/main/java/com/stardust/scriptdroid/{model/script => io}/StorageFileProvider.java (98%) create mode 100644 app/src/main/java/com/stardust/scriptdroid/io/TmpScriptFiles.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/network/download/DownloadFailedException.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/network/download/DownloadManager.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/common/OptionListView.java create mode 100644 app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java create mode 100644 app/src/main/res/drawable-hdpi/ic_file_download_black_48dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_file_download_black_48dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_file_download_black_48dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_file_download_black_48dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_file_download_black_48dp.png create mode 100644 app/src/main/res/layout/option_list_view.xml diff --git a/app/build.gradle b/app/build.gradle index faef0803..90815baa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -126,6 +126,10 @@ dependencies { // RxJava compile "io.reactivex.rxjava2:rxjava:2.1.0" compile 'io.reactivex.rxjava2:rxandroid:2.0.1' + // RxDownload + compile('zlc.season:rxdownload3:1.0.8', { + exclude group: 'com.android.support' + }) // Retrofit compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' diff --git a/app/src/main/java/com/stardust/scriptdroid/external/tasker/TaskPrefEditActivity.java b/app/src/main/java/com/stardust/scriptdroid/external/tasker/TaskPrefEditActivity.java index bc5fb427..331be673 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/tasker/TaskPrefEditActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/tasker/TaskPrefEditActivity.java @@ -7,12 +7,11 @@ import android.support.annotation.Nullable; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; -import android.view.View; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.external.CommonUtils; import com.stardust.scriptdroid.model.script.ScriptFile; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.ui.BaseActivity; import com.stardust.scriptdroid.ui.main.scripts.ScriptListView; import com.twofortyfouram.locale.sdk.client.ui.activity.AbstractAppCompatPluginActivity; @@ -45,7 +44,7 @@ public class TaskPrefEditActivity extends AbstractAppCompatPluginActivity { mStorageFileProvider = StorageFileProvider.getExternalStorageProvider(); ScriptListView scriptList = (ScriptListView) findViewById(R.id.script_list); scriptList.setStorageFileProvider(mStorageFileProvider); - scriptList.setCurrentDirectory(StorageFileProvider.DEFAULT_DIRECTORY); + scriptList.setCurrentDirectory(new ScriptFile(StorageFileProvider.DEFAULT_DIRECTORY)); scriptList.setOnScriptFileClickListener((view, file) -> { mSelectedScriptFilePath = file.getPath(); finish(); diff --git a/app/src/main/java/com/stardust/scriptdroid/external/widget/ScriptWidgetSettingsActivity.java b/app/src/main/java/com/stardust/scriptdroid/external/widget/ScriptWidgetSettingsActivity.java index edc1f5b3..a7bca029 100644 --- a/app/src/main/java/com/stardust/scriptdroid/external/widget/ScriptWidgetSettingsActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/widget/ScriptWidgetSettingsActivity.java @@ -6,11 +6,10 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.view.Menu; import android.view.MenuItem; -import android.view.View; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.model.script.ScriptFile; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.ui.BaseActivity; import com.stardust.scriptdroid.ui.main.scripts.ScriptListView; @@ -45,7 +44,7 @@ public class ScriptWidgetSettingsActivity extends BaseActivity { mStorageFileProvider = StorageFileProvider.getExternalStorageProvider(); ScriptListView scriptList = (ScriptListView) findViewById(R.id.script_list); scriptList.setStorageFileProvider(mStorageFileProvider); - scriptList.setCurrentDirectory(StorageFileProvider.DEFAULT_DIRECTORY); + scriptList.setCurrentDirectory(new ScriptFile(StorageFileProvider.DEFAULT_DIRECTORY)); scriptList.setOnScriptFileClickListener((view, file) -> { mSelectedScriptFilePath = file.getPath(); finish(); diff --git a/app/src/main/java/com/stardust/scriptdroid/model/script/StorageFileProvider.java b/app/src/main/java/com/stardust/scriptdroid/io/StorageFileProvider.java similarity index 98% rename from app/src/main/java/com/stardust/scriptdroid/model/script/StorageFileProvider.java rename to app/src/main/java/com/stardust/scriptdroid/io/StorageFileProvider.java index a0be2e1c..9d528910 100644 --- a/app/src/main/java/com/stardust/scriptdroid/model/script/StorageFileProvider.java +++ b/app/src/main/java/com/stardust/scriptdroid/io/StorageFileProvider.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.model.script; +package com.stardust.scriptdroid.io; import android.os.Environment; @@ -31,7 +31,7 @@ public class StorageFileProvider { public static final int CHANGE = 2; public static final int ALL = 3; public static final String DEFAULT_DIRECTORY_PATH = Environment.getExternalStorageDirectory() + App.getApp().getString(R.string.folder_name); - public static final ScriptFile DEFAULT_DIRECTORY = new ScriptFile(DEFAULT_DIRECTORY_PATH); + public static final PFile DEFAULT_DIRECTORY = new PFile(DEFAULT_DIRECTORY_PATH); public static class DirectoryChangeEvent { diff --git a/app/src/main/java/com/stardust/scriptdroid/io/TmpScriptFiles.java b/app/src/main/java/com/stardust/scriptdroid/io/TmpScriptFiles.java new file mode 100644 index 00000000..4a816ecd --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/io/TmpScriptFiles.java @@ -0,0 +1,40 @@ +package com.stardust.scriptdroid.io; + +import android.content.Context; + +import com.stardust.pio.PFiles; +import com.stardust.scriptdroid.model.script.ScriptFile; + +import java.io.File; +import java.io.IOException; + +/** + * Created by Stardust on 2017/10/21. + */ + +public class TmpScriptFiles { + + + public static File create(Context context) throws IOException { + ensureTmpDir(context); + File tmp = new File(getTmpDir(context), "tmp-" + System.currentTimeMillis() + ".js"); + tmp.createNewFile(); + return tmp; + } + + public static void clearTmpDir(Context context) { + File dir = getTmpDir(context); + PFiles.deleteRecursively(dir); + } + + public static File getTmpDir(Context context) { + return new File(context.getCacheDir(), "tmp_scripts/"); + } + + private static void ensureTmpDir(Context context) { + File dir = getTmpDir(context); + if (!dir.exists()) { + dir.mkdirs(); + } + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/model/script/ScriptFile.java b/app/src/main/java/com/stardust/scriptdroid/model/script/ScriptFile.java index 44c6de16..0a43b7bd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/model/script/ScriptFile.java +++ b/app/src/main/java/com/stardust/scriptdroid/model/script/ScriptFile.java @@ -59,37 +59,6 @@ public class ScriptFile extends PFile { return new ScriptFile(p); } - @Override - public ScriptFile[] listFiles() { - return listFiles(file -> (file.getName().endsWith(".js") || file.getName().endsWith(".auto") || - file.isDirectory()) && !file.getName().startsWith(".")); - } - - @Override - public ScriptFile[] listFiles(FilenameFilter filter) { - String ss[] = list(); - if (ss == null) return null; - ArrayList files = new ArrayList<>(); - for (String s : ss) - if ((filter == null) || filter.accept(this, s)) - files.add(new ScriptFile(this, s)); - return files.toArray(new ScriptFile[files.size()]); - } - - @Override - public ScriptFile[] listFiles(FileFilter filter) { - String ss[] = list(); - if (ss == null) return null; - ArrayList files = new ArrayList<>(); - for (String s : ss) { - ScriptFile f = new ScriptFile(this, s); - if ((filter == null) || filter.accept(f)) - files.add(f); - } - return files.toArray(new ScriptFile[files.size()]); - - } - public ScriptSource toSource() { if (getType() == TYPE_JAVA_SCRIPT) { return new JavaScriptFileSource(this); diff --git a/app/src/main/java/com/stardust/scriptdroid/model/script/Scripts.java b/app/src/main/java/com/stardust/scriptdroid/model/script/Scripts.java index d40b6f5c..86c06307 100644 --- a/app/src/main/java/com/stardust/scriptdroid/model/script/Scripts.java +++ b/app/src/main/java/com/stardust/scriptdroid/model/script/Scripts.java @@ -18,6 +18,7 @@ import com.stardust.scriptdroid.autojs.AutoJs; import com.stardust.scriptdroid.external.CommonUtils; import com.stardust.scriptdroid.external.shortcut.Shortcut; import com.stardust.scriptdroid.external.shortcut.ShortcutActivity; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.model.sample.Sample; import com.stardust.scriptdroid.ui.edit.EditActivity; import com.stardust.util.AssetsCache; diff --git a/app/src/main/java/com/stardust/scriptdroid/network/download/DownloadFailedException.java b/app/src/main/java/com/stardust/scriptdroid/network/download/DownloadFailedException.java new file mode 100644 index 00000000..ade36dda --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/network/download/DownloadFailedException.java @@ -0,0 +1,23 @@ +package com.stardust.scriptdroid.network.download; + +/** + * Created by Stardust on 2017/10/20. + */ + +public class DownloadFailedException extends Throwable { + private final String mUrl; + private final String mPath; + + public DownloadFailedException(String url, String path) { + mUrl = url; + mPath = path; + } + + @Override + public String toString() { + return "DownloadFailedException{" + + "url='" + mUrl + '\'' + + ", path='" + mPath + '\'' + + "} " + super.toString(); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/network/download/DownloadManager.java b/app/src/main/java/com/stardust/scriptdroid/network/download/DownloadManager.java new file mode 100644 index 00000000..83bb7471 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/network/download/DownloadManager.java @@ -0,0 +1,124 @@ +package com.stardust.scriptdroid.network.download; + +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; +import android.os.Handler; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Flowable; +import io.reactivex.Observable; +import io.reactivex.disposables.Disposable; +import io.reactivex.subjects.PublishSubject; +import zlc.season.rxdownload3.RxDownload; +import zlc.season.rxdownload3.core.Failed; +import zlc.season.rxdownload3.core.Mission; +import zlc.season.rxdownload3.core.Status; +import zlc.season.rxdownload3.core.Succeed; + +import static android.app.DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR; +import static android.app.DownloadManager.COLUMN_STATUS; +import static android.app.DownloadManager.COLUMN_TOTAL_SIZE_BYTES; +import static android.app.DownloadManager.STATUS_FAILED; +import static android.app.DownloadManager.STATUS_RUNNING; +import static android.app.DownloadManager.STATUS_SUCCESSFUL; + +/** + * Created by Stardust on 2017/10/20. + */ + +public class DownloadManager { + + private static DownloadManager sInstance; + + private android.app.DownloadManager mManager; + private Context mContext; + private Handler mHandler; + + + public DownloadManager(Context context) { + mContext = context; + mHandler = new Handler(); + mManager = (android.app.DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + } + + public static DownloadManager getInstance(Context context) { + if (sInstance == null) { + sInstance = new DownloadManager(context); + } + return sInstance; + } + + + public static String parseFileNameLocally(String url) { + int i = url.lastIndexOf('-'); + if (i < 0) { + i = url.lastIndexOf('/'); + } + return url.substring(i + 1); + } + + public Observable download(String url, String path) { + File file = new File(path); + Mission mission = new Mission(url, file.getName(), file.getParent()); + PublishSubject progress = PublishSubject.create(); + RxDownload.INSTANCE.create(mission) + .subscribe(status -> { + int p = (int) Math.floor((float) status.getDownloadSize() / status.getTotalSize() * 100); + progress.onNext(p); + if (status instanceof Succeed) { + progress.onComplete(); + RxDownload.INSTANCE.delete(mission); + } else if (status instanceof Failed) { + progress.onError(((Failed) status).getThrowable()); + } + }); + RxDownload.INSTANCE.start(mission).subscribe(); + return progress; + } + + public Observable download$(String url, String path) { + android.app.DownloadManager.Request request = new android.app.DownloadManager.Request(Uri.parse(url)); + request.setDestinationUri(Uri.parse("file://" + path)); + long id = mManager.enqueue(request); + PublishSubject downloadProgress = PublishSubject.create(); + Disposable disposable = Observable.interval(0, 200, TimeUnit.MILLISECONDS) + .subscribe(t -> { + int progress = getDownloadProgress(id); + if (progress < 0) { + downloadProgress.onError(new DownloadFailedException(url, path)); + } + downloadProgress.onNext(progress); + if (progress == 100) { + downloadProgress.onComplete(); + } + }); + downloadProgress.doOnComplete(disposable::dispose); + return downloadProgress; + } + + private int getDownloadProgress(long id) { + Cursor cursor = mManager.query(new android.app.DownloadManager.Query() + .setFilterById(id)); + if (!cursor.moveToFirst()) { + return -1; + } + int total = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_TOTAL_SIZE_BYTES)); + int downloaded = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_BYTES_DOWNLOADED_SO_FAR)); + int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS)); + if (status == STATUS_SUCCESSFUL) { + return 100; + } else if (status == STATUS_FAILED) { + return -1; + } + return (int) Math.floor((float) downloaded / total * 100); + } + + public void cancelDownload(String url) { + RxDownload.INSTANCE.stop(url); + RxDownload.INSTANCE.delete(url); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java index e3e4c00f..8640a128 100644 --- a/app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java +++ b/app/src/main/java/com/stardust/scriptdroid/sublime/SublimeResponseHandler.java @@ -13,7 +13,7 @@ import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.autojs.AutoJs; import com.stardust.scriptdroid.model.script.Scripts; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; /** * Created by Stardust on 2017/5/11. diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/common/OptionListView.java b/app/src/main/java/com/stardust/scriptdroid/ui/common/OptionListView.java new file mode 100644 index 00000000..744718f8 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/common/OptionListView.java @@ -0,0 +1,131 @@ +package com.stardust.scriptdroid.ui.common; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.stardust.scriptdroid.R; + +import java.util.ArrayList; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by Stardust on 2017/10/20. + */ + +public class OptionListView extends LinearLayout { + + + public static class Builder { + + private OptionListView mOptionListView; + private Context mContext; + + public Builder(Context context) { + mContext = context; + mOptionListView = (OptionListView) View.inflate(context, R.layout.option_list_view, null); + } + + public Builder item(int id, int iconRes, int textRes) { + return item(id, iconRes, mContext.getString(textRes)); + } + + public Builder item(int id, int iconRes, String text) { + mOptionListView.mIds.add(id); + mOptionListView.mIcons.add(iconRes); + mOptionListView.mTexts.add(text); + return this; + } + + public Builder bindItemClick(Object target) { + mOptionListView.mOnItemClickTarget = target; + return this; + } + + public Builder title(String title) { + mOptionListView.mTitleView.setVisibility(VISIBLE); + mOptionListView.mTitleView.setText(title); + return this; + } + + public Builder title(int title) { + return title(mContext.getString(title)); + } + + public OptionListView build() { + return mOptionListView; + } + } + + + private ArrayList mIds = new ArrayList<>(); + private ArrayList mIcons = new ArrayList<>(); + private ArrayList mTexts = new ArrayList<>(); + private Object mOnItemClickTarget; + private RecyclerView mOptionList; + private TextView mTitleView; + + public OptionListView(Context context) { + super(context); + } + + public OptionListView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mTitleView = (TextView) findViewById(R.id.title); + mOptionList = (RecyclerView) findViewById(R.id.list); + mOptionList.setLayoutManager(new LinearLayoutManager(getContext())); + mOptionList.setAdapter(new Adapter()); + } + + private class Adapter extends RecyclerView.Adapter { + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.operation_dialog_item, parent, false)); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + holder.itemView.setId(mIds.get(position)); + holder.text.setText(mTexts.get(position)); + holder.icon.setImageResource(mIcons.get(position)); + if (mOnItemClickTarget != null) { + ButterKnife.bind(mOnItemClickTarget, holder.itemView); + } + } + + @Override + public int getItemCount() { + return mIds.size(); + } + } + + + class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.icon) + ImageView icon; + @BindView(R.id.text) + TextView text; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java b/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java index 354c8306..2abcb3e3 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java @@ -6,6 +6,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.text.InputType; +import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; @@ -18,10 +19,13 @@ import com.stardust.pio.PFiles; import com.stardust.pio.UncheckedIOException; import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.io.TmpScriptFiles; import com.stardust.scriptdroid.model.script.ScriptFile; import com.stardust.scriptdroid.model.script.Scripts; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.model.sample.Sample; +import com.stardust.scriptdroid.network.download.DownloadManager; +import com.stardust.scriptdroid.ui.filechooser.FileChooserDialogBuilder; import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; import org.reactivestreams.Publisher; @@ -30,6 +34,7 @@ import org.reactivestreams.Subscriber; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.concurrent.Callable; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -38,12 +43,14 @@ import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; + /** * Created by Stardust on 2017/7/31. */ public class ScriptOperations { + private static final String LOG_TAG = "ScriptOperations"; private Context mContext; private View mView; private ScriptFile mCurrentDirectory; @@ -57,7 +64,7 @@ public class ScriptOperations { } public ScriptOperations(Context context, View view) { - this(context, view, StorageFileProvider.DEFAULT_DIRECTORY); + this(context, view, new ScriptFile(StorageFileProvider.DEFAULT_DIRECTORY)); } public void newScriptFileForScript(final String script) { @@ -240,16 +247,61 @@ public class ScriptOperations { } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Consumer() { - @Override - public void accept(@io.reactivex.annotations.NonNull Boolean deleted) throws Exception { - showMessage(deleted ? R.string.text_already_delete : R.string.text_delete_failed); - if (deleted) - mStorageFileProvider.notifyFileRemoved(mCurrentDirectory, scriptFile); - } + .subscribe(deleted -> { + showMessage(deleted ? R.string.text_already_delete : R.string.text_delete_failed); + if (deleted) + mStorageFileProvider.notifyFileRemoved(mCurrentDirectory, scriptFile); }); } + public Observable download(String url) { + String fileName = DownloadManager.parseFileNameLocally(url); + MaterialDialog progressDialog = createDownloadProgressDialog(url, fileName); + return new FileChooserDialogBuilder(mContext) + .title(R.string.text_select_save_path) + .chooseDir() + .singleChoice() + .map(saveDir -> new File(saveDir, fileName).getPath()) + .flatMap(savePath -> download(url, savePath, progressDialog)); + } + + private MaterialDialog createDownloadProgressDialog(String url, String fileName) { + return new MaterialDialog.Builder(mContext) + .progress(false, 100) + .title(fileName) + .cancelable(false) + .positiveText(R.string.text_cancel_download) + .onPositive((dialog, which) -> DownloadManager.getInstance(mContext).cancelDownload(url)) + .show(); + } + + public Observable download(String url, String path, MaterialDialog progressDialog) { + PublishSubject subject = PublishSubject.create(); + DownloadManager.getInstance(mContext).download(url, path) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext(progressDialog::setProgress) + .doOnComplete(() -> { + progressDialog.dismiss(); + subject.onNext(new ScriptFile(path)); + subject.onComplete(); + }) + .doOnError(error -> { + Log.e(LOG_TAG, "Download failed", error); + progressDialog.dismiss(); + showMessage(R.string.text_download_failed); + subject.onError(error); + }) + .subscribe(); + return subject; + } + + public Observable temporarilyDownload(String url) { + String fileName = DownloadManager.parseFileNameLocally(url); + return Observable.fromCallable(() -> TmpScriptFiles.create(mContext)) + .flatMap(tmpFile -> + download(url, tmpFile.getPath(), createDownloadProgressDialog(url, fileName))); + } + private class InputCallback implements MaterialDialog.InputCallback { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java b/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java index 50c5e712..91fc8e05 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java @@ -2,17 +2,21 @@ package com.stardust.scriptdroid.ui.filechooser; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.StringRes; import com.stardust.pio.PFile; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.model.script.ScriptFile; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; import java.io.File; import java.util.Collections; import java.util.List; +import io.reactivex.Observable; +import io.reactivex.subjects.PublishSubject; + /** * Created by Stardust on 2017/10/19. */ @@ -87,5 +91,25 @@ public class FileChooserDialogBuilder extends ThemeColorMaterialDialogBuilder { return this; } + public Observable singleChoice() { + PublishSubject result = PublishSubject.create(); + singleChoice(file -> { + result.onNext(file); + result.onComplete(); + }); + show(); + return result; + } + @Override + public FileChooserDialogBuilder title(@NonNull CharSequence title) { + super.title(title); + return this; + } + + @Override + public FileChooserDialogBuilder title(@StringRes int titleRes) { + super.title(titleRes); + return this; + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java index 8f84a96f..fda2c7c6 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java @@ -5,7 +5,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.support.annotation.NonNull; import android.support.annotation.RequiresApi; import android.support.design.widget.FloatingActionButton; @@ -17,7 +16,6 @@ import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.widget.Toolbar; import android.view.Gravity; import android.view.View; -import android.widget.Toast; import com.qq.e.comm.DownloadService; import com.stardust.app.FragmentPagerAdapterBuilder; @@ -29,9 +27,9 @@ import com.stardust.scriptdroid.Pref; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.autojs.AutoJs; import com.stardust.scriptdroid.ui.common.NotAskAgainDialog; -import com.stardust.scriptdroid.ui.filechooser.FileChooserDialogBuilder; +import com.stardust.scriptdroid.ui.common.ScriptOperations; import com.stardust.scriptdroid.ui.floating.FloatyWindowManger; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.ui.main.community.CommunityFragment_; import com.stardust.scriptdroid.ui.main.doc.OnlineDocsFragment_; import com.stardust.scriptdroid.ui.main.scripts.MyScriptListFragment_; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java index a782b72d..083f26bd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityFragment.java @@ -25,7 +25,7 @@ public class CommunityFragment extends ViewPagerFragment implements BackPressedH private static final String POSTS_PAGE_PATTERN = "[\\S\\s]+/topic/[0-9]+/[\\S\\s]+"; @ViewById(R.id.eweb_view) - EWebView mEWebView; + CommunityWebView mEWebView; WebView mWebView; public CommunityFragment() { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java new file mode 100644 index 00000000..e1c29eac --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/community/CommunityWebView.java @@ -0,0 +1,116 @@ +package com.stardust.scriptdroid.ui.main.community; + +import android.content.Context; +import android.support.design.widget.BottomSheetDialog; +import android.support.design.widget.Snackbar; +import android.util.AttributeSet; +import android.webkit.WebView; + +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.model.script.ScriptFile; +import com.stardust.scriptdroid.model.script.Scripts; +import com.stardust.scriptdroid.network.download.DownloadManager; +import com.stardust.scriptdroid.ui.common.OptionListView; +import com.stardust.scriptdroid.ui.common.ScriptOperations; +import com.stardust.widget.EWebView; + +import java.util.regex.Pattern; + +import butterknife.OnClick; +import butterknife.Optional; +import io.reactivex.android.schedulers.AndroidSchedulers; + +/** + * Created by Stardust on 2017/10/19. + */ + +public class CommunityWebView extends EWebView { + + private String mUrl; + private BottomSheetDialog mBottomSheetDialog; + + public CommunityWebView(Context context) { + super(context); + init(); + } + + public CommunityWebView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + getWebView().setWebViewClient(new MyWebViewClient()); + } + + private void shouldScriptOptionsDialog(String url) { + mUrl = url; + String fileName = DownloadManager.parseFileNameLocally(url); + mBottomSheetDialog = new BottomSheetDialog(getContext()); + mBottomSheetDialog.setContentView(new OptionListView.Builder(getContext()) + .title(fileName) + .item(R.id.save, R.drawable.ic_file_download_black_48dp, R.string.text_download) + .item(R.id.run, R.drawable.ic_play_arrow_white_48dp, R.string.text_run) + .item(R.id.edit, R.drawable.ic_edit_white_24dp, R.string.text_save_and_edit) + .bindItemClick(this) + .build()); + mBottomSheetDialog.show(); + } + + @Optional + @OnClick(R.id.save) + void save() { + dismissBottomSheetDialog(); + new ScriptOperations(getContext(), CommunityWebView.this) + .download(mUrl) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(file -> + Snackbar.make(CommunityWebView.this, getResources().getString(R.string.format_file_downloaded, file.getPath()) + , Snackbar.LENGTH_SHORT).show()); + } + + @Optional + @OnClick(R.id.edit) + void saveAndEdit() { + dismissBottomSheetDialog(); + new ScriptOperations(getContext(), CommunityWebView.this) + .download(mUrl) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(Scripts::edit); + } + + @Optional + @OnClick(R.id.run) + void run() { + dismissBottomSheetDialog(); + new ScriptOperations(getContext(), CommunityWebView.this) + .temporarilyDownload(mUrl) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(file -> { + Snackbar.make(CommunityWebView.this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); + Scripts.run(file); + }); + } + + private void dismissBottomSheetDialog() { + mBottomSheetDialog.dismiss(); + mBottomSheetDialog = null; + } + + + private class MyWebViewClient extends EWebView.MyWebViewClient { + + private final Pattern UPLOAD_FILE_PATTERN = Pattern.compile("http://www.autojs.org/assets/uploads/files/.+(\\.js|\\.auto)"); + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (UPLOAD_FILE_PATTERN.matcher(url).matches()) { + shouldScriptOptionsDialog(url); + return true; + } + return super.shouldOverrideUrlLoading(view, url); + } + + + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java index 80497c5e..28b94535 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java @@ -7,7 +7,7 @@ import android.view.View; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.model.script.ScriptFile; import com.stardust.scriptdroid.model.script.Scripts; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.tool.SimpleObserver; import com.stardust.scriptdroid.ui.common.ScriptOperations; import com.stardust.scriptdroid.ui.main.FloatingActionMenu; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java index 7a4e4f10..4b71ebe2 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java @@ -20,7 +20,7 @@ import com.stardust.pio.PFiles; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.model.script.ScriptFile; import com.stardust.scriptdroid.model.script.Scripts; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.ui.common.ScriptLoopDialog; import com.stardust.scriptdroid.ui.common.ScriptOperations; import com.stardust.scriptdroid.ui.viewmodel.ScriptList; @@ -181,7 +181,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa @Override public void onRefresh() { - loadScriptList(); + mStorageFileProvider.notifyDirectoryChanged(mCurrentDirectory); } @@ -289,6 +289,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa int positionOfCategoryFile = positionOfCategoryFile(); BindableViewHolder bindableViewHolder = (BindableViewHolder) holder; if (position == positionOfCategoryDir || position == positionOfCategoryFile) { + // FIXME: 2017/10/20 java.lang.ClassCastException: java.lang.Boolean cannot be cast to com.stardust.scriptdroid.model.script.ScriptFile bindableViewHolder.bind(position == positionOfCategoryDir, position); return; } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/update/UpdateInfoDialogBuilder.java b/app/src/main/java/com/stardust/scriptdroid/ui/update/UpdateInfoDialogBuilder.java index 05e810ed..baa4111b 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/update/UpdateInfoDialogBuilder.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/update/UpdateInfoDialogBuilder.java @@ -17,7 +17,7 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.scriptdroid.BuildConfig; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.network.entity.VersionInfo; -import com.stardust.scriptdroid.model.script.StorageFileProvider; +import com.stardust.scriptdroid.io.StorageFileProvider; import com.stardust.scriptdroid.tool.IntentTool; import com.stardust.util.DownloadTask; import com.stardust.util.IntentUtil; diff --git a/app/src/main/java/com/stardust/widget/EWebView.java b/app/src/main/java/com/stardust/widget/EWebView.java index 52014e8f..41cdd68e 100644 --- a/app/src/main/java/com/stardust/widget/EWebView.java +++ b/app/src/main/java/com/stardust/widget/EWebView.java @@ -73,7 +73,7 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres mWebView.reload(); } - private class MyWebChromeClient extends WebChromeClient { + protected class MyWebChromeClient extends WebChromeClient { @Override public void onProgressChanged(WebView view, int newProgress) { @@ -82,7 +82,7 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres } } - private class MyWebViewClient extends WebViewClient { + protected class MyWebViewClient extends WebViewClient { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { diff --git a/app/src/main/res/drawable-hdpi/ic_file_download_black_48dp.png b/app/src/main/res/drawable-hdpi/ic_file_download_black_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ce97c85dfa3544a0246aa9604effbfd8a9b8d75f GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawN<3X0Ln;{Gp4-UCWXRBZq37JQ z<#+XSgBE;>Xqc?B^YPCZXI|4Q0T80z@JOXzdv<3r#1fAyL;U#1&qKZB>MpUXO@geCyfj6=8p literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_file_download_black_48dp.png b/app/src/main/res/drawable-mdpi/ic_file_download_black_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f5afb24dc5724aefabc49520b22dfcb761e6dac2 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0Da8DP)a=3ghylE3c2%xjXsc0z{Fyzw{Joqi?vh|k>Fb%|&7*ZgcX-Cywh rKBv-wx%XKF1wV;r<(2c81cdTS$sUS|W!^RgXa$3(tDnm{r-UW|ZQry9=^}c(P=<~# tlyP_xISf79`&DxfRxf6E`Jb`&EA#8N7|*_%oGT#zc)I$ztaD0e0syc5W^Dif literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_file_download_black_48dp.png b/app/src/main/res/drawable-xxxhdpi/ic_file_download_black_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..065bcf7202b39f5c5451ddb96b5217da0a93922c GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvK8A$4HYMBD0I0Jk_T!AzMG$+420Aw+j1o;Is z{BLM^wW|lnz2fQO7*fIb_WVNLLkSWLflbK*ZofD-EiUPN7ae)zKTF>P>-tA`SFNhs z|8vE|RSO~Dp~SZ+K7aoAPd|LvpxeH?{Vs=akHJA0p}@!?(7*sE1P*ct^e})3GFb{> zlNmXL8w@}M(0B~ikFJ2w$IBKz{NKK6l~xJUlCNorP75UWf;{f&>gTe~DWM4f!R=%M literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/fragment_community.xml b/app/src/main/res/layout/fragment_community.xml index 84e9d009..56dbe71c 100644 --- a/app/src/main/res/layout/fragment_community.xml +++ b/app/src/main/res/layout/fragment_community.xml @@ -1,5 +1,5 @@ - + + + + + + + \ 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 22488b0c..b60e7ecd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -132,7 +132,7 @@ 下载地址 直接下载 下载中 - 下载失败~请到应用商店下载 + 下载失败 此版本不再提示 格式化代码 处理中 @@ -237,6 +237,11 @@ 关闭 调整 退出悬浮窗 + 下载并编辑 + 保存到 + 取消下载 + 下载 + 文件已保存到 %s diff --git a/common/src/main/java/com/stardust/pio/PFile.java b/common/src/main/java/com/stardust/pio/PFile.java index 3b5d0e56..04130c0b 100644 --- a/common/src/main/java/com/stardust/pio/PFile.java +++ b/common/src/main/java/com/stardust/pio/PFile.java @@ -94,11 +94,13 @@ public class PFile extends File { public PFile[] listFiles() { String ss[] = list(); if (ss == null) return null; - PFile[] files = new PFile[ss.length]; + ArrayList files = new ArrayList<>(); for (int i = 0; i < ss.length; i++) { - files[i] = new PFile(ss[i]); + if (!ss[i].startsWith(".")) { + files.add(new PFile(ss[i])); + } } - return files; + return files.toArray(new PFile[files.size()]); } @Override @@ -107,7 +109,7 @@ public class PFile extends File { if (ss == null) return null; ArrayList files = new ArrayList<>(); for (String s : ss) - if ((filter == null) || filter.accept(this, s)) + if (!s.startsWith(".") && (filter == null || filter.accept(this, s))) files.add(new PFile(this, s)); return files.toArray(new PFile[files.size()]); } @@ -119,7 +121,7 @@ public class PFile extends File { ArrayList files = new ArrayList<>(); for (String s : ss) { PFile f = new PFile(this, s); - if ((filter == null) || filter.accept(f)) + if (!f.isHidden() && (filter == null || filter.accept(f))) files.add(f); } return files.toArray(new PFile[files.size()]);