diff --git a/.gitignore b/.gitignore
index aa724b7..b9048a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@
.externalNativeBuild
.cxx
local.properties
+app/build
diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 0000000..6863b14
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 261e26d..e61186d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -31,7 +31,7 @@ android {
dependencies {
implementation fileTree(dir: "libs", includes: ["*.aar", "*.jar"])
//文件选择器(包含权限请求)
- implementation 'io.github.molihuan:pathselector:1.1.5'
+ implementation 'io.github.molihuan:pathselector:1.1.6'
//RxFFmpeg依赖
implementation 'com.github.microshow:RxFFmpeg:4.9.0-lite'
//bugly依赖
@@ -47,6 +47,7 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:4.12.0'
//XUI
+
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
diff --git a/app/release/app-release.apk "b/app/release/1.6.0\345\260\235\351\262\234\347\211\210.apk"
similarity index 90%
rename from app/release/app-release.apk
rename to "app/release/1.6.0\345\260\235\351\262\234\347\211\210.apk"
index e3e7776..836c46a 100644
Binary files a/app/release/app-release.apk and "b/app/release/1.6.0\345\260\235\351\262\234\347\211\210.apk" differ
diff --git a/app/src/main/java/com/molihua/hlbmerge/App.java b/app/src/main/java/com/molihua/hlbmerge/App.java
index b8acbae..f5e38e9 100644
--- a/app/src/main/java/com/molihua/hlbmerge/App.java
+++ b/app/src/main/java/com/molihua/hlbmerge/App.java
@@ -4,6 +4,7 @@
import com.molihua.hlbmerge.dao.ConfigData;
import com.molihuan.pathselector.PathSelector;
+import com.molihuan.pathselector.configs.PathSelectorConfig;
import com.tencent.bugly.Bugly;
import com.tencent.mmkv.MMKV;
import com.xuexiang.xui.XUI;
@@ -32,6 +33,8 @@ public void onCreate() {
ConfigData.init();
//路径选择器debug
PathSelector.setDebug(true);
+ //取消自动申请权限
+ PathSelectorConfig.setAutoGetPermission(false);
super.onCreate();
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/activity/AbstractMainActivity.java b/app/src/main/java/com/molihua/hlbmerge/activity/AbstractMainActivity.java
index 1262499..ab1e35a 100644
--- a/app/src/main/java/com/molihua/hlbmerge/activity/AbstractMainActivity.java
+++ b/app/src/main/java/com/molihua/hlbmerge/activity/AbstractMainActivity.java
@@ -4,6 +4,7 @@
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationView;
+import com.molihua.hlbmerge.fragment.AbstractMainFileShowFragment;
import com.molihua.hlbmerge.interfaces.IMainFileShowFragment;
import com.molihua.hlbmerge.interfaces.IMainTitlebarFragment;
@@ -23,4 +24,6 @@ public abstract class AbstractMainActivity extends BaseActivity implements IMain
public abstract void showHideNavigation(boolean status);
public abstract void handleShowHide(boolean isShow);
+
+ public abstract AbstractMainFileShowFragment getMainFileShowFragment();
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/activity/impl/MainActivity.java b/app/src/main/java/com/molihua/hlbmerge/activity/impl/MainActivity.java
index 37846e4..8079b53 100644
--- a/app/src/main/java/com/molihua/hlbmerge/activity/impl/MainActivity.java
+++ b/app/src/main/java/com/molihua/hlbmerge/activity/impl/MainActivity.java
@@ -66,6 +66,8 @@ public void getComponents() {
@Override
public void initData() {
+
+ //申请权限
PermissionsTools.getStoragePermissions(this);
mainTitlebarFragment = new MainTitlebarFragment();
@@ -187,6 +189,11 @@ public NavigationView getNavigationView() {
return navigationView;
}
+ @Override
+ public AbstractMainFileShowFragment getMainFileShowFragment() {
+ return mainFileShowFragment;
+ }
+
@Override
public void showHideNavigation(boolean status) {
if (status) {
diff --git a/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeOptionDialog.java b/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeOptionDialog.java
index 6537dd6..b6a12dc 100644
--- a/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeOptionDialog.java
+++ b/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeOptionDialog.java
@@ -6,6 +6,7 @@
import android.widget.CompoundButton;
import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import com.molihua.hlbmerge.R;
import com.molihua.hlbmerge.dao.ConfigData;
@@ -17,6 +18,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* @ClassName: JudgeMergeDialog
@@ -26,14 +28,29 @@
*/
public class MergeOptionDialog {
-
- public static MaterialDialog showMergeOptionDialog(CacheFile cacheFile, Context context) {
+ /**
+ * 单个合并
+ *
+ * @param cacheFile
+ * @param fragment
+ * @return
+ */
+ public static MaterialDialog showMergeOptionDialog(CacheFile cacheFile, Fragment fragment) {
List cacheFileList = new ArrayList<>();
cacheFileList.add(cacheFile);
- return showMergeOptionDialog(cacheFileList, context);
+ return showMergeOptionDialog(cacheFileList, fragment);
}
- public static MaterialDialog showMergeOptionDialog(List cacheFileList, Context context) {
+ /**
+ * 多个合并
+ *
+ * @param cacheFileList
+ * @param fragment
+ * @return
+ */
+ public static MaterialDialog showMergeOptionDialog(List cacheFileList, Fragment fragment) {
+ Context context = fragment.getContext();
+ Objects.requireNonNull(context, "context is null");
View dialog_judgemerge = LayoutInflater.from(context).inflate(R.layout.dialog_judge_merge, null);
MaterialSpinner dialog_materialspinner = dialog_judgemerge.findViewById(R.id.dialog_materialspinner);
@@ -68,7 +85,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
//打开合并进度窗口
- MergeProgressDialog.showMergeProgressDialog(cacheFileList, context);
+ MergeProgressDialog.showMergeProgressDialog(cacheFileList, fragment);
}
})
.negativeText("取消")
diff --git a/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeProgressDialog.java b/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeProgressDialog.java
index 88bf8d5..7e5460a 100644
--- a/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeProgressDialog.java
+++ b/app/src/main/java/com/molihua/hlbmerge/dialog/impl/MergeProgressDialog.java
@@ -2,14 +2,21 @@
import android.content.Context;
import android.content.DialogInterface;
+import android.net.Uri;
import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import com.blankj.molihuan.utilcode.util.FileIOUtils;
import com.blankj.molihuan.utilcode.util.FileUtils;
+import com.blankj.molihuan.utilcode.util.UriUtils;
import com.molihua.hlbmerge.dao.ConfigData;
import com.molihua.hlbmerge.entity.CacheFile;
-import com.molihua.hlbmerge.service.BaseCacheFileManager;
+import com.molihua.hlbmerge.service.impl.PathCacheFileManager;
import com.molihua.hlbmerge.service.impl.RxFFmpegCallback;
+import com.molihua.hlbmerge.service.impl.UriCacheFileManager;
+import com.molihua.hlbmerge.utils.RxFfmpegTools;
+import com.molihuan.pathselector.utils.FileTools;
import com.xuexiang.xtask.XTask;
import com.xuexiang.xtask.core.ITaskChainEngine;
import com.xuexiang.xtask.core.param.ITaskResult;
@@ -21,8 +28,7 @@
import java.io.File;
import java.util.List;
-
-import io.microshow.rxffmpeg.RxFFmpegInvoke;
+import java.util.Objects;
/**
* @ClassName: MergeProgressDialog
@@ -34,13 +40,29 @@ public class MergeProgressDialog {
//用户是否选择的标志位
public static boolean FLAG_USER_HANDLE = false;
- public static String cmdTemplate = "ffmpeg -i %s -i %s -c copy %s.mp4";
+ public static final String CMD_TEMPLATE = "ffmpeg -i %s -i %s -c copy %s";
+ /**
+ * 显示合并进度弹窗
+ *
+ * @param cacheFileList
+ * @return
+ */
+ public static MaterialDialog showMergeProgressDialog(List cacheFileList, Fragment fragment) {
+ Context context = fragment.getContext();
+ Objects.requireNonNull(context, "context is null");
- public static MaterialDialog showMergeProgressDialog(List cacheFileList, Context context) {
+ List handledCacheFileList;
+ //是否需要使用uri
+ boolean dataUseUri = FileTools.underAndroidDataUseUri(ConfigData.getCacheFilePath());
//把合集item处理成章节item
- List handledCacheFileList = BaseCacheFileManager.collection2ChapterCacheFileList(cacheFileList);
+ if (dataUseUri) {
+ handledCacheFileList = UriCacheFileManager.collection2ChapterCacheFileList(fragment, cacheFileList);
+ } else {
+ handledCacheFileList = PathCacheFileManager.collection2ChapterCacheFileList(cacheFileList);
+ }
+
MaterialDialog materialDialog = new MaterialDialog.Builder(context)
.title("提示")
@@ -77,53 +99,80 @@ public static void startMerge(List cacheFileList, MaterialDialog dial
RxFFmpegCallback ffmpegCallback = new RxFFmpegCallback(dialog);
//获取输出根目录
String outRoot = ConfigData.getOutputFilePath();
+ //获取导出配置
+ int exportType = ConfigData.getExportType();
+ boolean exportDanmaku = ConfigData.isExportDanmaku();
XTask.getTaskChain()
.addTask(XTask.getTask(new TaskCommand() {
@Override
public void run() throws Exception {
- String[] cmd;
String cmdStr;
+ CacheFile srcCacheFile;
CacheFile cacheFile;
String subOutPath;
String completeOutPath;
+ String completeOutPathSuf;
for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
+ srcCacheFile = cacheFileList.get(i);
+
+ //将uri转换为file并把路径返回存入CacheFile中
+ cacheFile = MergeProgressDialog.cacheFileUri2File(srcCacheFile);
+
//创建输出目录
subOutPath = outRoot + File.separator + cacheFile.getCollectionName();
FileUtils.createOrExistsDir(subOutPath);
//获取完整的输出目录
completeOutPath = subOutPath + File.separator + cacheFile.getChapterName();
- //判断是否已经存在,如果存在则让用户选择都保留还是直接覆盖
- if (FileUtils.isFileExists(completeOutPath + ".mp4")) {
- //用户选择标志归位
- MergeProgressDialog.FLAG_USER_HANDLE = false;
- //处理弹窗
- MergeProgressDialog.existsSameFileDialog(dialog.getContext(), completeOutPath, cacheFile, ffmpegCallback);
- //用户没有选择就休眠等待
- while (!MergeProgressDialog.FLAG_USER_HANDLE) {
- Thread.sleep(600);
- }
-
- } else {
-
- //构造ffmpeg命令
- cmdStr = String.format(MergeProgressDialog.cmdTemplate, cacheFile.getAudioPath(), cacheFile.getVideoPath(), completeOutPath);
- cmd = cmdStr.split(" ");
-
- //LogUtils.e(cmdStr);
- //执行命令
- RxFFmpegInvoke.getInstance()
- .runCommand(cmd, ffmpegCallback);
+ //合并或复制视频
+ switch (exportType) {
+ case 0:
+ completeOutPathSuf = completeOutPath + ".mp4";
+ if (FileUtils.isFileExists(completeOutPathSuf)) {
+ //处理已经存在的文件弹窗
+ MergeProgressDialog.handleExistsFileDialog(dialog.getContext(), completeOutPathSuf, cacheFile, ffmpegCallback, exportType, exportDanmaku);
+ } else {
+ cmdStr = String.format(MergeProgressDialog.CMD_TEMPLATE, cacheFile.getAudioPath(), cacheFile.getVideoPath(), completeOutPathSuf);
+ RxFfmpegTools.runCommand(cmdStr, ffmpegCallback);
+ //是否导出弹幕
+ if (exportDanmaku) {
+ FileUtils.copy(cacheFile.getDanmakuPath(), completeOutPath + ".xml");
+ }
+ }
+ break;
+ case 1:
+ completeOutPathSuf = completeOutPath + ".mp4";
+ if (FileUtils.isFileExists(completeOutPathSuf)) {
+ MergeProgressDialog.handleExistsFileDialog(dialog.getContext(), completeOutPathSuf, cacheFile, ffmpegCallback, exportType, exportDanmaku);
+ } else {
+ MergeProgressDialog.copyVideoAudioWithProgress(cacheFile.getVideoPath(), completeOutPathSuf, ffmpegCallback);
+ //是否导出弹幕
+ if (exportDanmaku) {
+ FileUtils.copy(cacheFile.getDanmakuPath(), completeOutPath + ".xml");
+ }
+ }
+ break;
+ case 2:
+ completeOutPathSuf = completeOutPath + ".mp3";
+ if (FileUtils.isFileExists(completeOutPathSuf)) {
+ MergeProgressDialog.handleExistsFileDialog(dialog.getContext(), completeOutPathSuf, cacheFile, ffmpegCallback, exportType, exportDanmaku);
+ } else {
+ MergeProgressDialog.copyVideoAudioWithProgress(cacheFile.getAudioPath(), completeOutPathSuf, ffmpegCallback);
+ //是否导出弹幕
+ if (exportDanmaku) {
+ FileUtils.copy(cacheFile.getDanmakuPath(), completeOutPath + ".xml");
+ }
+ }
+ break;
+ default:
}
}
-
}
}))
.setTaskChainCallback(new TaskChainCallbackAdapter() {
@@ -135,42 +184,126 @@ public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITas
})
.start();
+ }
+
+ /**
+ * 将uri转换为file并把路径返回存入CacheFile中
+ *
+ * @param cacheFile
+ * @return 转换成功或不是Android11返回true
+ */
+ public static CacheFile cacheFileUri2File(CacheFile cacheFile) {
+ if (cacheFile.getUseUri()) {
+ //uri转byte
+ byte[] bytesAudio = UriUtils.uri2Bytes(Uri.parse(cacheFile.getAudioPath()));
+ byte[] bytesVideo = UriUtils.uri2Bytes(Uri.parse(cacheFile.getVideoPath()));
+ byte[] bytesDanmaku = UriUtils.uri2Bytes(Uri.parse(cacheFile.getDanmakuPath()));
+ //获取临时文件名
+ String audioTemp = ConfigData.TYPE_OUTPUT_FILE_PATH_TEMP + "/audio.mp3";
+ String videoTemp = ConfigData.TYPE_OUTPUT_FILE_PATH_TEMP + "/video.mp4";
+ String danmakuTemp = ConfigData.TYPE_OUTPUT_FILE_PATH_TEMP + "/danmaku.xml";
+ //删除已经存在的临时文件名
+ FileUtils.delete(audioTemp);
+ FileUtils.delete(videoTemp);
+ FileUtils.delete(danmakuTemp);
+ //byte转file
+ FileIOUtils.writeFileFromBytesByChannel(audioTemp, bytesAudio, true);
+ boolean success = FileIOUtils.writeFileFromBytesByChannel(videoTemp, bytesVideo, true);
+ FileIOUtils.writeFileFromBytesByChannel(danmakuTemp, bytesDanmaku, true);
+ //拷贝一份,不能影响源CacheFile
+ CacheFile tempCacheFile = null;
+ try {
+ tempCacheFile = cacheFile.clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+
+ if (tempCacheFile != null) {
+ //重新设置路径
+ tempCacheFile.setAudioPath(audioTemp);
+ tempCacheFile.setVideoPath(videoTemp);
+ tempCacheFile.setDanmakuPath(danmakuTemp);
+ }
+
+ return tempCacheFile;
+ } else {
+ return cacheFile;
+ }
}
+ /**
+ * 复制Video、Audio带有进度设置
+ *
+ * @param src
+ * @param target
+ * @param ffmpegCallback
+ */
+ public static void copyVideoAudioWithProgress(String src, String target, RxFFmpegCallback ffmpegCallback) {
+ boolean success = FileUtils.copy(src, target);
+ if (ffmpegCallback == null) {
+ return;
+ }
+ if (success) {
+ ffmpegCallback.onFinish();
+ } else {
+ ffmpegCallback.onError(src + "复制失败");
+ }
+ }
+
/**
* 存在相同文件处理弹窗
*
* @param context
- * @param completeOutPath
+ * @param completeOutPathSuf
* @param cacheFile
* @param ffmpegCallback
*/
- public static void existsSameFileDialog(Context context, String completeOutPath, CacheFile cacheFile, RxFFmpegCallback ffmpegCallback) {
+ public static void handleExistsFileDialog(Context context, String completeOutPathSuf, CacheFile cacheFile, RxFFmpegCallback ffmpegCallback, int type, boolean exportDanmaku) throws InterruptedException {
+ //用户选择标志归位
+ MergeProgressDialog.FLAG_USER_HANDLE = false;
+
//放在主线程中去执行
XTask.postToMain(new Runnable() {
@Override
public void run() {
new MaterialDialog.Builder(context)
.title("文件已经存在")
- .content(completeOutPath + ".mp4已存在,请选择处理方法")
+ .content(completeOutPathSuf + "\n已存在,请选择处理方法")
.cancelable(false)
.positiveText("都保存")
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
+ //获取扩展名
+ String extension = FileTools.getFileExtension(completeOutPathSuf);
+ //设置新名称
int k = 0;
- while (FileUtils.isFileExists(completeOutPath + "(" + k + ").mp4")) {
+ String reName;
+ do {
+ reName = completeOutPathSuf.replace("." + extension, "(" + k + ")." + extension);
k++;
+ } while (FileUtils.isFileExists(reName));
+
+ //是否导出弹幕
+ if (exportDanmaku) {
+ FileUtils.copy(cacheFile.getDanmakuPath(), reName.replace(extension, "xml"));
}
- //构造ffmpeg命令
- String cmdStr = String.format(MergeProgressDialog.cmdTemplate, cacheFile.getAudioPath(), cacheFile.getVideoPath(), completeOutPath + "(" + k + ")");
- String[] cmd = cmdStr.split(" ");
- //LogUtils.e(cmdStr);
- //执行命令
- RxFFmpegInvoke.getInstance()
- .runCommand(cmd, ffmpegCallback);
+ switch (type) {
+ case 0:
+ //构造ffmpeg命令
+ String cmdStr = String.format(MergeProgressDialog.CMD_TEMPLATE, cacheFile.getAudioPath(), cacheFile.getVideoPath(), reName);
+ RxFfmpegTools.runCommand(cmdStr, ffmpegCallback);
+ break;
+ case 1:
+ MergeProgressDialog.copyVideoAudioWithProgress(cacheFile.getVideoPath(), reName, ffmpegCallback);
+ break;
+ case 2:
+ MergeProgressDialog.copyVideoAudioWithProgress(cacheFile.getAudioPath(), reName, ffmpegCallback);
+ break;
+ default:
+ }
dialog.dismiss();
}
@@ -179,15 +312,34 @@ public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which)
.onNeutral(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
+ //获取扩展名
+ String extension = FileTools.getFileExtension(completeOutPathSuf);
//删除已存在的
- FileUtils.delete(completeOutPath + ".mp4");
- //构造ffmpeg命令
- String cmdStr = String.format(MergeProgressDialog.cmdTemplate, cacheFile.getAudioPath(), cacheFile.getVideoPath(), completeOutPath);
- String[] cmd = cmdStr.split(" ");
- //LogUtils.e(cmdStr);
- //执行命令
- RxFFmpegInvoke.getInstance()
- .runCommand(cmd, ffmpegCallback);
+ FileUtils.delete(completeOutPathSuf);
+
+ switch (type) {
+ case 0:
+ //构造ffmpeg命令
+ String cmdStr = String.format(MergeProgressDialog.CMD_TEMPLATE, cacheFile.getAudioPath(), cacheFile.getVideoPath(), completeOutPathSuf);
+ RxFfmpegTools.runCommand(cmdStr, ffmpegCallback);
+ break;
+ case 1:
+ MergeProgressDialog.copyVideoAudioWithProgress(cacheFile.getVideoPath(), completeOutPathSuf, ffmpegCallback);
+ break;
+ case 2:
+ MergeProgressDialog.copyVideoAudioWithProgress(cacheFile.getAudioPath(), completeOutPathSuf, ffmpegCallback);
+ break;
+ default:
+ }
+
+ //是否导出弹幕
+ if (exportDanmaku) {
+ String targetXml = completeOutPathSuf.replace(extension, "xml");
+ //删除已存在的
+ FileUtils.delete(targetXml);
+ FileUtils.copy(cacheFile.getDanmakuPath(), targetXml);
+ }
+
dialog.dismiss();
}
})
@@ -209,6 +361,14 @@ public void onDismiss(DialogInterface dialog) {
.show();
}
});
+
+
+ //用户没有选择就休眠等待
+ while (!MergeProgressDialog.FLAG_USER_HANDLE) {
+ Thread.sleep(600);
+ }
+
+
}
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/entity/CacheFile.java b/app/src/main/java/com/molihua/hlbmerge/entity/CacheFile.java
index 138c6d0..d9e3deb 100644
--- a/app/src/main/java/com/molihua/hlbmerge/entity/CacheFile.java
+++ b/app/src/main/java/com/molihua/hlbmerge/entity/CacheFile.java
@@ -1,5 +1,10 @@
package com.molihua.hlbmerge.entity;
+import androidx.annotation.NonNull;
+import androidx.documentfile.provider.DocumentFile;
+
+import java.io.Serializable;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -8,7 +13,7 @@
* @Date: 2022/12/21/17:13
* @Description:
*/
-public class CacheFile {
+public class CacheFile implements Serializable, Cloneable {
//如果是合集则为0,如果是章节则是1
private Integer flag;
//整体是否可见
@@ -37,6 +42,10 @@ public class CacheFile {
private Boolean boxCheck;
//存储blv格式的文件路径
private List blvPathList;
+ //是否使用uri地址
+ private Boolean useUri;
+ //document
+ private DocumentFile documentFile;
public CacheFile() {
}
@@ -158,6 +167,34 @@ public CacheFile setBlvPathList(List blvPathList) {
return this;
}
+ public Boolean getUseUri() {
+ return useUri;
+ }
+
+ public CacheFile setUseUri(Boolean useUri) {
+ this.useUri = useUri;
+ return this;
+ }
+
+ public DocumentFile getDocumentFile() {
+ return documentFile;
+ }
+
+ public CacheFile setDocumentFile(DocumentFile documentFile) {
+ this.documentFile = documentFile;
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public CacheFile clone() throws CloneNotSupportedException {
+ CacheFile cloneCacheFile = (CacheFile) super.clone();
+ if (blvPathList != null) {
+ cloneCacheFile.setBlvPathList(new ArrayList<>(blvPathList));
+ }
+ return cloneCacheFile;
+ }
+
@Override
public String toString() {
return "CacheFile{" +
@@ -173,6 +210,10 @@ public String toString() {
", danmakuPath='" + danmakuPath + '\'' +
", boxVisibility=" + boxVisibility +
", boxCheck=" + boxCheck +
+ ", useUri=" + useUri +
+ ", documentFile=" + documentFile +
'}';
}
+
+
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFileShowFragment.java b/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFileShowFragment.java
index 5c83461..6e5d0ac 100644
--- a/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFileShowFragment.java
+++ b/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFileShowFragment.java
@@ -9,4 +9,6 @@
* @Description:
*/
public abstract class AbstractMainFileShowFragment extends AbstractMainFragment implements IMainFileShowFragment {
+
+
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFragment.java b/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFragment.java
index fe59738..fcea923 100644
--- a/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFragment.java
+++ b/app/src/main/java/com/molihua/hlbmerge/fragment/AbstractMainFragment.java
@@ -22,4 +22,6 @@ public void onAttach(@NonNull Context context) {
abstractMainActivity = (AbstractMainActivity) mActivity;
}
}
+
+
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainFileShowFragment.java b/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainFileShowFragment.java
index bf3b098..a30e5fd 100644
--- a/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainFileShowFragment.java
+++ b/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainFileShowFragment.java
@@ -1,5 +1,8 @@
package com.molihua.hlbmerge.fragment.impl;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.net.Uri;
import android.view.View;
import androidx.annotation.NonNull;
@@ -19,6 +22,10 @@
import com.molihua.hlbmerge.service.BaseCacheFileManager;
import com.molihua.hlbmerge.service.ICacheFileManager;
import com.molihua.hlbmerge.service.impl.PathCacheFileManager;
+import com.molihua.hlbmerge.service.impl.UriCacheFileManager;
+import com.molihuan.pathselector.utils.FileTools;
+import com.molihuan.pathselector.utils.PermissionsTools;
+import com.molihuan.pathselector.utils.VersionTool;
import java.util.ArrayList;
import java.util.List;
@@ -39,6 +46,7 @@ public class MainFileShowFragment extends AbstractMainFileShowFragment implement
private CacheFileListAdapter cacheFileListAdapter;
private ICacheFileManager pathCacheFileManager;
+ private ICacheFileManager uriCacheFileManager;
//当前是否为多选模式
private boolean multipleSelectionMode = false;
@@ -56,7 +64,13 @@ public void getComponents(View view) {
@Override
public void initData() {
+ //权限申请
+// UriTool.grantedUriPermission(ConfigData.getCacheFilePath(), this);
+
+
pathCacheFileManager = new PathCacheFileManager();
+ uriCacheFileManager = new UriCacheFileManager(this);
+
allCacheFileList = new ArrayList<>();
updateCollectionFileList();
}
@@ -102,8 +116,8 @@ public void onItemClick(@NonNull BaseQuickAdapter, ?> adapter, @NonNull View v
refreshCacheFileList();
break;
case BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER:
-
- MergeOptionDialog.showMergeOptionDialog(item, mActivity);
+ //打开合并弹窗
+ MergeOptionDialog.showMergeOptionDialog(item, this);
break;
case BaseCacheFileManager.FLAG_CACHE_FILE_BACK:
updateCollectionFileList();
@@ -131,23 +145,47 @@ public boolean onItemLongClick(@NonNull BaseQuickAdapter, ?> adapter, @NonNull
return true;
}
-
return false;
}
@Override
public List updateCollectionFileList() {
- return pathCacheFileManager.updateCollectionFileList(ConfigData.getCacheFilePath(), allCacheFileList);
+ //是否需要使用uri
+ boolean dataUseUri = FileTools.underAndroidDataUseUri(ConfigData.getCacheFilePath());
+
+ if (dataUseUri) {
+ allCacheFileList = uriCacheFileManager.updateCollectionFileList(ConfigData.getCacheFilePath(), allCacheFileList);
+ } else {
+ allCacheFileList = pathCacheFileManager.updateCollectionFileList(ConfigData.getCacheFilePath(), allCacheFileList);
+ }
+
+ return allCacheFileList;
}
@Override
public List updateChapterFileList() {
- return pathCacheFileManager.updateChapterFileList(allCacheFileList.get(0).getCollectionPath(), allCacheFileList);
+ boolean dataUseUri = FileTools.underAndroidDataUseUri(ConfigData.getCacheFilePath());
+
+ if (dataUseUri) {
+ allCacheFileList = uriCacheFileManager.updateChapterFileList(allCacheFileList.get(0).getCollectionPath(), allCacheFileList);
+ } else {
+ allCacheFileList = pathCacheFileManager.updateChapterFileList(allCacheFileList.get(0).getCollectionPath(), allCacheFileList);
+ }
+
+ return allCacheFileList;
}
@Override
public List updateChapterFileList(String collectionPath) {
- return pathCacheFileManager.updateChapterFileList(collectionPath, allCacheFileList);
+ boolean dataUseUri = FileTools.underAndroidDataUseUri(ConfigData.getCacheFilePath());
+
+ if (dataUseUri) {
+ allCacheFileList = uriCacheFileManager.updateChapterFileList(collectionPath, allCacheFileList);
+ } else {
+ allCacheFileList = pathCacheFileManager.updateChapterFileList(collectionPath, allCacheFileList);
+ }
+
+ return allCacheFileList;
}
@Override
@@ -228,14 +266,37 @@ public boolean onBackPressed() {
return true;
}
- Integer flag = allCacheFileList.get(0).getFlag();
- if (flag == BaseCacheFileManager.FLAG_CACHE_FILE_BACK || flag == BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER) {
- updateCollectionFileList();
- refreshCacheFileList();
- return true;
+ if (allCacheFileList != null && allCacheFileList.size() > 0) {
+ Integer flag = allCacheFileList.get(0).getFlag();
+ if (flag != BaseCacheFileManager.FLAG_CACHE_FILE_COLLECTION) {
+ updateCollectionFileList();
+ refreshCacheFileList();
+ return true;
+ }
}
-
return false;
}
+
+
+ @SuppressLint("WrongConstant")
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ //保存这个uri目录的访问权限
+ if (VersionTool.isAndroid11()) {
+ if (requestCode == PermissionsTools.PERMISSION_REQUEST_CODE) {
+ Uri uri;
+ if ((uri = data.getData()) != null) {
+ mActivity.getContentResolver()
+ .takePersistableUriPermission(uri,
+ data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+ );
+ }
+ //更新列表数据
+ updateCollectionFileList();
+ }
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainHandleFragment.java b/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainHandleFragment.java
index 3d1ada4..90c9128 100644
--- a/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainHandleFragment.java
+++ b/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainHandleFragment.java
@@ -64,7 +64,7 @@ public void onClick(View v) {
}
} else if (id == R.id.center_tv) {
- MergeOptionDialog.showMergeOptionDialog(abstractMainActivity.getSelectedCacheFileList(), mActivity);
+ MergeOptionDialog.showMergeOptionDialog(abstractMainActivity.getSelectedCacheFileList(), abstractMainActivity.getMainFileShowFragment());
} else if (id == R.id.right_tv) {
abstractMainActivity.openCloseMultipleMode(false);
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainTitlebarFragment.java b/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainTitlebarFragment.java
index 931b986..df1796e 100644
--- a/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainTitlebarFragment.java
+++ b/app/src/main/java/com/molihua/hlbmerge/fragment/impl/MainTitlebarFragment.java
@@ -87,7 +87,13 @@ public void onClick(View v) {
return;
}
- CacheFile cacheFile = abstractMainActivity.getAllCacheFileList().get(0);
+ List allCacheFileList = abstractMainActivity.getAllCacheFileList();
+
+ if (allCacheFileList.size() == 0) {
+ return;
+ }
+
+ CacheFile cacheFile = allCacheFileList.get(0);
if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_COLLECTION) {
abstractMainActivity.updateCollectionFileList();
} else {
@@ -151,7 +157,7 @@ public List filterCacheFileList(String key) {
cacheFile.setWholeVisibility(View.VISIBLE);
break;
default:
-
+
}
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/interfaces/IMainFileShowFragment.java b/app/src/main/java/com/molihua/hlbmerge/interfaces/IMainFileShowFragment.java
index 2e7f2b2..8861a2c 100644
--- a/app/src/main/java/com/molihua/hlbmerge/interfaces/IMainFileShowFragment.java
+++ b/app/src/main/java/com/molihua/hlbmerge/interfaces/IMainFileShowFragment.java
@@ -11,8 +11,19 @@
public interface IMainFileShowFragment {
List updateCollectionFileList();
+ /**
+ * 用来刷新的
+ *
+ * @return
+ */
List updateChapterFileList();
+ /**
+ * 进入合集中
+ *
+ * @param collectionPath
+ * @return
+ */
List updateChapterFileList(String collectionPath);
List getSelectedCacheFileList();
@@ -31,8 +42,17 @@ public interface IMainFileShowFragment {
boolean isMultipleSelectionMode();
+ /**
+ * 刷新UI
+ */
void refreshCacheFileList();
+ /**
+ * 设置整体是否可见
+ *
+ * @param state
+ * @return
+ */
List setWholeVisible(boolean state);
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/service/BaseCacheFileManager.java b/app/src/main/java/com/molihua/hlbmerge/service/BaseCacheFileManager.java
index d3b50af..3b6a61a 100644
--- a/app/src/main/java/com/molihua/hlbmerge/service/BaseCacheFileManager.java
+++ b/app/src/main/java/com/molihua/hlbmerge/service/BaseCacheFileManager.java
@@ -1,13 +1,14 @@
package com.molihua.hlbmerge.service;
+import android.annotation.SuppressLint;
import android.view.View;
+import com.molihua.hlbmerge.adapter.CacheFileListAdapter;
import com.molihua.hlbmerge.entity.CacheFile;
-import com.molihua.hlbmerge.utils.FileTools;
-import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* @ClassName: BaseCacheFileManager
@@ -33,54 +34,99 @@ public List initCollectionFileList(String path, List cache
return cacheFileList;
}
- /**
- * 将合集item转换为章节item
- *
- * @param collectionCacheFileList
- * @return
- */
- public static List collection2ChapterCacheFileList(List collectionCacheFileList) {
- //如果已经是章节了就直接返回
- if (collectionCacheFileList.get(0).getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER) {
- return collectionCacheFileList;
+ @Override
+ public List setBoxVisible(List cacheFileList, CacheFileListAdapter cacheFileAdapter, boolean state) {
+
+ int type;
+ if (state) {
+ type = View.VISIBLE;
+ } else {
+ type = View.INVISIBLE;
+ }
+
+ CacheFile cacheFile;
+ for (int i = 0; i < cacheFileList.size(); i++) {
+ cacheFile = cacheFileList.get(i);
+ //判断是不是返回item
+ if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
+ continue;
+ }
+ cacheFile.setBoxVisibility(type);
+ //显示和不显示时都设为不选中防止有缓存
+ cacheFile.setBoxCheck(false);
}
- List tempList = new ArrayList<>();
-
- String[] needPath = new String[4];
- String[] names = new String[2];
-
- String collectionPath;
- //遍历所有合集
- for (int n = 0; n < collectionCacheFileList.size(); n++) {
- //获取一个合集路径
- collectionPath = collectionCacheFileList.get(n).getCollectionPath();
- //获取一个合集下面所有的章节
- File[] chapterFile = FileTools.getCollectionChapterFile(collectionPath);
- for (int i = 0; i < chapterFile.length; i++) {
- //获取章节里需要的路径
- needPath = FileTools.getNeedPath(chapterFile[i], needPath);
- //获取合集名称和章节名称
- names = FileTools.getCollectionChapterName(needPath[2], names);
- tempList.add(
- new CacheFile()
- .setFlag(BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER)
- .setWholeVisibility(View.VISIBLE)
- .setCollectionPath(collectionPath)
- .setCollectionName(names[0])
- .setChapterPath(chapterFile[i].getAbsolutePath())
- .setChapterName(names[1])
- .setAudioPath(needPath[0])
- .setVideoPath(needPath[1])
- .setJsonPath(needPath[2])
- .setDanmakuPath(needPath[3])
- .setBoxVisibility(View.INVISIBLE)
- .setBoxCheck(false)
- );
+ return cacheFileList;
+ }
+
+ @Override
+ public List setBoxChecked(List cacheFileList, CacheFileListAdapter cacheFileAdapter, boolean state) {
+ CacheFile cacheFile;
+ for (int i = 0; i < cacheFileList.size(); i++) {
+ cacheFile = cacheFileList.get(i);
+ //判断是不是返回item
+ if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
+ continue;
+ }
+ //如果是不可见的
+ if (cacheFile.getBoxVisibility() != View.VISIBLE || cacheFile.getWholeVisibility() != View.VISIBLE) {
+ cacheFile.setBoxCheck(false);
+ } else {
+ cacheFile.setBoxCheck(state);
}
}
+ return cacheFileList;
+ }
+
+ @Override
+ public List setWholeVisible(List cacheFileList, boolean state) {
+ int type;
+ if (state) {
+ type = View.VISIBLE;
+ } else {
+ type = View.GONE;
+ }
- return tempList;
+ CacheFile cacheFile;
+ for (int i = 0; i < cacheFileList.size(); i++) {
+ cacheFile = cacheFileList.get(i);
+ //判断是不是返回item
+ if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
+ continue;
+ }
+ cacheFile.setWholeVisibility(type);
+ //显示和不显示时都设为不选中防止有缓存
+ cacheFile.setBoxCheck(false);
+ }
+
+ return cacheFileList;
}
+
+ @Override
+ public List getSelectedCacheFileList(List allCacheFileList, List selectedCacheFileList) {
+ Objects.requireNonNull(allCacheFileList, "allCacheFileList is null");
+ //初始化
+ if (selectedCacheFileList == null) {
+ selectedCacheFileList = new ArrayList<>();
+ } else {
+ selectedCacheFileList.clear();
+ }
+ //把勾选的添加到选择列表中
+ for (CacheFile cacheFile : allCacheFileList) {
+ if (cacheFile.getBoxCheck()) {
+ selectedCacheFileList.add(cacheFile);
+ }
+ }
+
+ return selectedCacheFileList;
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ @Override
+ public void refreshCacheFileList(CacheFileListAdapter cacheFileAdapter) {
+ cacheFileAdapter.notifyDataSetChanged();
+ }
+
+
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/service/impl/PathCacheFileManager.java b/app/src/main/java/com/molihua/hlbmerge/service/impl/PathCacheFileManager.java
index 30f2006..582ef69 100644
--- a/app/src/main/java/com/molihua/hlbmerge/service/impl/PathCacheFileManager.java
+++ b/app/src/main/java/com/molihua/hlbmerge/service/impl/PathCacheFileManager.java
@@ -1,9 +1,7 @@
package com.molihua.hlbmerge.service.impl;
-import android.annotation.SuppressLint;
import android.view.View;
-import com.molihua.hlbmerge.adapter.CacheFileListAdapter;
import com.molihua.hlbmerge.entity.CacheFile;
import com.molihua.hlbmerge.service.BaseCacheFileManager;
import com.molihua.hlbmerge.utils.FileTools;
@@ -31,6 +29,9 @@ public List updateCollectionFileList(String path, List cac
String[] names = new String[2];
//获取所有的合集
File[] collectionFile = FileTools.getCollectionChapterFile(path);
+ if (collectionFile == null) {
+ return cacheFileList;
+ }
for (int i = 0; i < collectionFile.length; i++) {
//获取每一个集合中的第一个章节
File oneChapterPath = Objects.requireNonNull(collectionFile[i].listFiles())[0];
@@ -51,6 +52,7 @@ public List updateCollectionFileList(String path, List cac
.setDanmakuPath(needPath[3])
.setBoxVisibility(View.INVISIBLE)
.setBoxCheck(false)
+ .setUseUri(false)
);
}
@@ -67,12 +69,13 @@ public List initChapterFileList(String collectionPath, List updateChapterFileList(String collectionPath, List setBoxVisible(List cacheFileList, CacheFileListAdapter cacheFileAdapter, boolean state) {
-
- int type;
- if (state) {
- type = View.VISIBLE;
- } else {
- type = View.INVISIBLE;
+ /**
+ * 将合集item转换为章节item
+ *
+ * @param collectionCacheFileList
+ * @return
+ */
+ public static List collection2ChapterCacheFileList(List collectionCacheFileList) {
+ Objects.requireNonNull(collectionCacheFileList, "collectionCacheFileList is null");
+
+ //如果已经是章节了就直接返回
+ if (collectionCacheFileList.get(0).getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER) {
+ return collectionCacheFileList;
}
- CacheFile cacheFile;
- for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
- //判断是不是返回item
- if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
- continue;
- }
- cacheFile.setBoxVisibility(type);
- //显示和不显示时都设为不选中防止有缓存
- cacheFile.setBoxCheck(false);
- }
+ List tempList = new ArrayList<>();
- return cacheFileList;
- }
+ String[] needPath = new String[4];
+ String[] names = new String[2];
- @Override
- public List setBoxChecked(List cacheFileList, CacheFileListAdapter cacheFileAdapter, boolean state) {
- CacheFile cacheFile;
- for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
- //判断是不是返回item
- if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
- continue;
- }
- //如果是不可见的
- if (cacheFile.getBoxVisibility() != View.VISIBLE || cacheFile.getWholeVisibility() != View.VISIBLE) {
- cacheFile.setBoxCheck(false);
- } else {
- cacheFile.setBoxCheck(state);
+ String collectionPath;
+ //遍历所有合集
+ for (int n = 0; n < collectionCacheFileList.size(); n++) {
+ //获取一个合集路径
+ collectionPath = collectionCacheFileList.get(n).getCollectionPath();
+ //获取一个合集下面所有的章节
+ File[] chapterFile = FileTools.getCollectionChapterFile(collectionPath);
+ for (int i = 0; i < chapterFile.length; i++) {
+ //获取章节里需要的路径
+ needPath = FileTools.getNeedPath(chapterFile[i], needPath);
+ //获取合集名称和章节名称
+ names = FileTools.getCollectionChapterName(needPath[2], names);
+ tempList.add(
+ new CacheFile()
+ .setFlag(BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER)
+ .setWholeVisibility(View.VISIBLE)
+ .setCollectionPath(collectionPath)
+ .setCollectionName(names[0])
+ .setChapterPath(chapterFile[i].getAbsolutePath())
+ .setChapterName(names[1])
+ .setAudioPath(needPath[0])
+ .setVideoPath(needPath[1])
+ .setJsonPath(needPath[2])
+ .setDanmakuPath(needPath[3])
+ .setBoxVisibility(View.INVISIBLE)
+ .setBoxCheck(false)
+ .setUseUri(false)
+ );
}
}
- return cacheFileList;
- }
-
- @Override
- public List setWholeVisible(List cacheFileList, boolean state) {
- int type;
- if (state) {
- type = View.VISIBLE;
- } else {
- type = View.GONE;
- }
- CacheFile cacheFile;
- for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
- //判断是不是返回item
- if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
- continue;
- }
- cacheFile.setWholeVisibility(type);
- //显示和不显示时都设为不选中防止有缓存
- cacheFile.setBoxCheck(false);
- }
-
- return cacheFileList;
+ return tempList;
}
- @Override
- public List getSelectedCacheFileList(List allCacheFileList, List selectedCacheFileList) {
- Objects.requireNonNull(allCacheFileList, "allCacheFileList is null");
- //初始化
- if (selectedCacheFileList == null) {
- selectedCacheFileList = new ArrayList<>();
- } else {
- selectedCacheFileList.clear();
- }
- //把勾选的添加到选择列表中
- for (CacheFile cacheFile : allCacheFileList) {
- if (cacheFile.getBoxCheck()) {
- selectedCacheFileList.add(cacheFile);
- }
- }
-
- return selectedCacheFileList;
- }
- @SuppressLint("NotifyDataSetChanged")
- @Override
- public void refreshCacheFileList(CacheFileListAdapter cacheFileAdapter) {
- cacheFileAdapter.notifyDataSetChanged();
- }
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/service/impl/UriCacheFileManager.java b/app/src/main/java/com/molihua/hlbmerge/service/impl/UriCacheFileManager.java
index 73ffaa0..78a9665 100644
--- a/app/src/main/java/com/molihua/hlbmerge/service/impl/UriCacheFileManager.java
+++ b/app/src/main/java/com/molihua/hlbmerge/service/impl/UriCacheFileManager.java
@@ -1,12 +1,14 @@
package com.molihua.hlbmerge.service.impl;
-import android.annotation.SuppressLint;
+import android.net.Uri;
import android.view.View;
-import com.molihua.hlbmerge.adapter.CacheFileListAdapter;
+import androidx.documentfile.provider.DocumentFile;
+import androidx.fragment.app.Fragment;
+
import com.molihua.hlbmerge.entity.CacheFile;
import com.molihua.hlbmerge.service.BaseCacheFileManager;
-import com.molihua.hlbmerge.utils.FileTools;
+import com.molihua.hlbmerge.utils.UriTool;
import java.io.File;
import java.util.ArrayList;
@@ -21,36 +23,49 @@
*/
public class UriCacheFileManager extends BaseCacheFileManager {
+ private Fragment fragment;
+
+ public UriCacheFileManager(Fragment fragment) {
+ this.fragment = fragment;
+ }
@Override
public List updateCollectionFileList(String path, List cacheFileList) {
//初始化列表
cacheFileList = initCollectionFileList(path, cacheFileList);
- String[] needPath = new String[4];
+ Uri[] needUri = new Uri[4];
String[] names = new String[2];
- //获取所有的合集
- File[] collectionFile = FileTools.getCollectionChapterFile(path);
- for (int i = 0; i < collectionFile.length; i++) {
- //获取每一个集合中的第一个章节
- File oneChapterPath = Objects.requireNonNull(collectionFile[i].listFiles())[0];
- //获取章节里需要的路径
- needPath = FileTools.getNeedPath(oneChapterPath, needPath);
+ //获取所有的合集路径
+ DocumentFile[] collectionFiles = UriTool.getCollectionChapterFile(fragment, path);
+
+ if (collectionFiles == null) {
+ return cacheFileList;
+ }
+ for (int i = 0; i < collectionFiles.length; i++) {
+ //获取每一个集合中的第一个章节路径
+ DocumentFile oneChapterPath = Objects.requireNonNull(collectionFiles[i].listFiles())[0];
+
+ //获取章节里需要的Uri
+ needUri = UriTool.getNeedUri(oneChapterPath, needUri);
+
//获取合集名称和章节名称
- names = FileTools.getCollectionChapterName(needPath[2], names);
+ names = UriTool.getCollectionChapterName(needUri[2], names);
+
cacheFileList.add(
new CacheFile()
.setFlag(BaseCacheFileManager.FLAG_CACHE_FILE_COLLECTION)
.setWholeVisibility(View.VISIBLE)
- .setCollectionPath(collectionFile[i].getAbsolutePath())
+ .setCollectionPath(path + File.separator + collectionFiles[i].getName())
.setCollectionName(names[0])
.setChapterName(names[1])
- .setAudioPath(needPath[0])
- .setVideoPath(needPath[1])
- .setJsonPath(needPath[2])
- .setDanmakuPath(needPath[3])
+ .setAudioPath(needUri[0].toString())
+ .setVideoPath(needUri[1].toString())
+ .setJsonPath(needUri[2].toString())
+ .setDanmakuPath(needUri[3].toString())
.setBoxVisibility(View.INVISIBLE)
.setBoxCheck(false)
+ .setUseUri(true)
);
}
@@ -67,12 +82,13 @@ public List initChapterFileList(String collectionPath, List initChapterFileList(String collectionPath, List updateChapterFileList(String collectionPath, List cacheFileList) {
cacheFileList = initChapterFileList(collectionPath, cacheFileList);
- String[] needPath = new String[4];
+ Uri[] needUri = new Uri[4];
String[] names = new String[2];
//获取一个合集下面所有的章节
- File[] chapterFile = FileTools.getCollectionChapterFile(collectionPath);
+ DocumentFile[] chapterFile = UriTool.getCollectionChapterFile(fragment, collectionPath);
+
+ if (chapterFile == null) {
+ return cacheFileList;
+ }
+
for (int i = 0; i < chapterFile.length; i++) {
- //获取章节里需要的路径
- needPath = FileTools.getNeedPath(chapterFile[i], needPath);
+
+ //获取章节里需要的Uri
+ needUri = UriTool.getNeedUri(chapterFile[i], needUri);
+
//获取合集名称和章节名称
- names = FileTools.getCollectionChapterName(needPath[2], names);
+ names = UriTool.getCollectionChapterName(needUri[2], names);
+
cacheFileList.add(
new CacheFile()
.setFlag(BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER)
.setWholeVisibility(View.VISIBLE)
.setCollectionPath(collectionPath)
.setCollectionName(names[0])
- .setChapterPath(chapterFile[i].getAbsolutePath())
+ .setChapterPath(collectionPath + File.separator + chapterFile[i].getName())
.setChapterName(names[1])
- .setAudioPath(needPath[0])
- .setVideoPath(needPath[1])
- .setJsonPath(needPath[2])
- .setDanmakuPath(needPath[3])
+ .setAudioPath(needUri[0].toString())
+ .setVideoPath(needUri[1].toString())
+ .setJsonPath(needUri[2].toString())
+ .setDanmakuPath(needUri[3].toString())
.setBoxVisibility(View.INVISIBLE)
.setBoxCheck(false)
+ .setUseUri(true)
);
}
return cacheFileList;
}
- @Override
- public List setBoxVisible(List cacheFileList, CacheFileListAdapter cacheFileAdapter, boolean state) {
-
- int type;
- if (state) {
- type = View.VISIBLE;
- } else {
- type = View.INVISIBLE;
+ /**
+ * 将合集item转换为章节item
+ *
+ * @param collectionCacheFileList
+ * @return
+ */
+ public static List collection2ChapterCacheFileList(Fragment fragment, List collectionCacheFileList) {
+ Objects.requireNonNull(collectionCacheFileList, "collectionCacheFileList is null");
+
+ //如果已经是章节了就直接返回
+ if (collectionCacheFileList.get(0).getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER) {
+ return collectionCacheFileList;
}
- CacheFile cacheFile;
- for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
- //判断是不是返回item
- if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
- continue;
- }
- cacheFile.setBoxVisibility(type);
- //显示和不显示时都设为不选中防止有缓存
- cacheFile.setBoxCheck(false);
- }
-
- return cacheFileList;
- }
+ List tempList = new ArrayList<>();
- @Override
- public List setBoxChecked(List cacheFileList, CacheFileListAdapter cacheFileAdapter, boolean state) {
- CacheFile cacheFile;
- for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
- //判断是不是返回item
- if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
- continue;
- }
- //如果是不可见的
- if (cacheFile.getBoxVisibility() != View.VISIBLE || cacheFile.getWholeVisibility() != View.VISIBLE) {
- cacheFile.setBoxCheck(false);
- } else {
- cacheFile.setBoxCheck(state);
- }
-
- }
- return cacheFileList;
- }
-
- @Override
- public List setWholeVisible(List cacheFileList, boolean state) {
- int type;
- if (state) {
- type = View.VISIBLE;
- } else {
- type = View.GONE;
- }
+ Uri[] needUri = new Uri[4];
+ String[] names = new String[2];
- CacheFile cacheFile;
- for (int i = 0; i < cacheFileList.size(); i++) {
- cacheFile = cacheFileList.get(i);
- //判断是不是返回item
- if (cacheFile.getFlag() == BaseCacheFileManager.FLAG_CACHE_FILE_BACK) {
- continue;
+ String collectionPath;
+ //遍历所有合集
+ for (int n = 0; n < collectionCacheFileList.size(); n++) {
+ //获取一个合集路径
+ collectionPath = collectionCacheFileList.get(n).getCollectionPath();
+ //获取一个合集下面所有的章节
+ DocumentFile[] chapterFile = UriTool.getCollectionChapterFile(fragment, collectionPath);
+ for (int i = 0; i < chapterFile.length; i++) {
+
+ //获取章节里需要的Uri
+ needUri = UriTool.getNeedUri(chapterFile[i], needUri);
+
+ //获取合集名称和章节名称
+ names = UriTool.getCollectionChapterName(needUri[2], names);
+
+ tempList.add(
+ new CacheFile()
+ .setFlag(BaseCacheFileManager.FLAG_CACHE_FILE_CHAPTER)
+ .setWholeVisibility(View.VISIBLE)
+ .setCollectionPath(collectionPath)
+ .setCollectionName(names[0])
+ .setChapterPath(collectionPath + File.separator + chapterFile[i].getName())
+ .setChapterName(names[1])
+ .setAudioPath(needUri[0].toString())
+ .setVideoPath(needUri[1].toString())
+ .setJsonPath(needUri[2].toString())
+ .setDanmakuPath(needUri[3].toString())
+ .setBoxVisibility(View.INVISIBLE)
+ .setBoxCheck(false)
+ .setUseUri(true)
+ );
}
- cacheFile.setWholeVisibility(type);
- //显示和不显示时都设为不选中防止有缓存
- cacheFile.setBoxCheck(false);
- }
-
- return cacheFileList;
- }
- @Override
- public List getSelectedCacheFileList(List allCacheFileList, List selectedCacheFileList) {
- Objects.requireNonNull(allCacheFileList, "allCacheFileList is null");
- //初始化
- if (selectedCacheFileList == null) {
- selectedCacheFileList = new ArrayList<>();
- } else {
- selectedCacheFileList.clear();
- }
- //把勾选的添加到选择列表中
- for (CacheFile cacheFile : allCacheFileList) {
- if (cacheFile.getBoxCheck()) {
- selectedCacheFileList.add(cacheFile);
- }
}
- return selectedCacheFileList;
+ return tempList;
}
- @SuppressLint("NotifyDataSetChanged")
- @Override
- public void refreshCacheFileList(CacheFileListAdapter cacheFileAdapter) {
- cacheFileAdapter.notifyDataSetChanged();
- }
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/utils/FileTools.java b/app/src/main/java/com/molihua/hlbmerge/utils/FileTools.java
index 51eb469..a1f1b67 100644
--- a/app/src/main/java/com/molihua/hlbmerge/utils/FileTools.java
+++ b/app/src/main/java/com/molihua/hlbmerge/utils/FileTools.java
@@ -1,6 +1,8 @@
package com.molihua.hlbmerge.utils;
+import com.blankj.molihuan.utilcode.util.ConvertUtils;
import com.blankj.molihuan.utilcode.util.FileIOUtils;
+import com.blankj.molihuan.utilcode.util.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
@@ -34,11 +36,16 @@ public static File[] getCollectionChapterFile(String path) {
return file.listFiles();
}
+ public static String[] getCollectionChapterName(byte[] jsonByte, String[] result) {
+ //把jsonByte转换成json字符串
+ String jsonStr = ConvertUtils.bytes2String(jsonByte);
+ return getCollectionChapterNameByJsonStr(jsonStr, result);
+ }
/**
* 获取合集和章节名称
*
- * @param jsonPath
+ * @param jsonPath json文件路径
* @param result
* @return result[0]合集名称
* result[1]章节名称
@@ -46,6 +53,22 @@ public static File[] getCollectionChapterFile(String path) {
public static String[] getCollectionChapterName(String jsonPath, String[] result) {
//把json文件转换成json字符串
String jsonStr = FileIOUtils.readFile2String(jsonPath, "UTF-8");
+ return getCollectionChapterNameByJsonStr(jsonStr, result);
+ }
+
+ /**
+ * 通过json字符串解析名称
+ *
+ * @param jsonStr json字符串
+ * @param result
+ * @return
+ */
+ private static String[] getCollectionChapterNameByJsonStr(String jsonStr, String[] result) {
+
+ if (StringUtils.isTrimEmpty(jsonStr)) {
+ return null;
+ }
+
JSONObject jsonObject;
//将json字符串转换成json对象
try {
diff --git a/app/src/main/java/com/molihua/hlbmerge/utils/RxFfmpegTools.java b/app/src/main/java/com/molihua/hlbmerge/utils/RxFfmpegTools.java
index 344e0f9..8debc58 100644
--- a/app/src/main/java/com/molihua/hlbmerge/utils/RxFfmpegTools.java
+++ b/app/src/main/java/com/molihua/hlbmerge/utils/RxFfmpegTools.java
@@ -1,5 +1,9 @@
package com.molihua.hlbmerge.utils;
+import com.molihua.hlbmerge.service.impl.RxFFmpegCallback;
+
+import io.microshow.rxffmpeg.RxFFmpegInvoke;
+
/**
* @ClassName: RxFfmpegTools
* @Author: molihuan
@@ -7,6 +11,15 @@
* @Description:
*/
public class RxFfmpegTools {
-
+
+
+ public static int runCommand(String cmdStr, RxFFmpegCallback ffmpegCallback) {
+ String[] cmd = cmdStr.split(" ");
+
+ //LogUtils.e(cmdStr);
+ //执行命令
+ return RxFFmpegInvoke.getInstance()
+ .runCommand(cmd, ffmpegCallback);
+ }
}
diff --git a/app/src/main/java/com/molihua/hlbmerge/utils/UriTool.java b/app/src/main/java/com/molihua/hlbmerge/utils/UriTool.java
new file mode 100644
index 0000000..e5b16b5
--- /dev/null
+++ b/app/src/main/java/com/molihua/hlbmerge/utils/UriTool.java
@@ -0,0 +1,151 @@
+package com.molihua.hlbmerge.utils;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.documentfile.provider.DocumentFile;
+import androidx.fragment.app.Fragment;
+
+import com.blankj.molihuan.utilcode.util.UriUtils;
+import com.molihuan.pathselector.utils.PermissionsTools;
+import com.molihuan.pathselector.utils.UriTools;
+import com.xuexiang.xtask.XTask;
+import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction;
+import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog;
+
+import java.util.Objects;
+
+/**
+ * @ClassName: UriTool
+ * @Author: molihuan
+ * @Date: 2022/12/24/21:28
+ * @Description:
+ */
+public class UriTool {
+
+ public static void grantedUriPermission(String path, Fragment fragment) {
+ //获取上下文
+ Context context = fragment.getContext();
+ Objects.requireNonNull(context, "context is null");
+
+ Uri uri = UriTools.path2Uri(path, false);
+ //获取权限,没有权限返回null有权限返回授权uri字符串
+ String existsPermission = PermissionsTools.existsGrantedUriPermission(uri, fragment);
+
+ if (existsPermission == null) {
+ //没有权限申请权限
+ new MaterialDialog.Builder(context)
+ .title("授权提示")
+ .content("需要授予\n" + path + "\n目录访问权限")
+ .cancelable(false)
+ .positiveText("授权")
+ .onPositive(new MaterialDialog.SingleButtonCallback() {
+ @Override
+ public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
+ //申请权限
+ PermissionsTools.goApplyUriPermissionPage(uri, fragment);
+ dialog.dismiss();
+ }
+ })
+ .negativeText("取消")
+ .onNegative(new MaterialDialog.SingleButtonCallback() {
+ @Override
+ public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
+ dialog.dismiss();
+ }
+ })
+ .show();
+ }
+ }
+
+ public static DocumentFile[] getCollectionChapterFile(Fragment fragment, String currentPath) {
+ //获取上下文
+ Context context = fragment.getContext();
+ Objects.requireNonNull(context, "context is null");
+
+ Uri uri = UriTools.path2Uri(currentPath, false);
+ //获取权限,没有权限返回null有权限返回授权uri字符串
+ String existsPermission = PermissionsTools.existsGrantedUriPermission(uri, fragment);
+
+ if (existsPermission == null) {
+ //没有权限申请权限
+ XTask.postToMain(new Runnable() {
+ @Override
+ public void run() {
+ //申请权限弹窗
+ new MaterialDialog.Builder(context)
+ .title("授权提示")
+ .content("需要授予\n" + currentPath + "\n目录访问权限")
+ .cancelable(false)
+ .positiveText("授权")
+ .onPositive(new MaterialDialog.SingleButtonCallback() {
+ @Override
+ public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
+ //申请权限
+ PermissionsTools.goApplyUriPermissionPage(uri, fragment);
+ dialog.dismiss();
+ }
+ })
+ .negativeText("取消")
+ .onNegative(new MaterialDialog.SingleButtonCallback() {
+ @Override
+ public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
+ dialog.dismiss();
+ }
+ })
+ .show();
+ }
+ });
+
+ return null;
+ }
+
+ Uri targetUri = Uri.parse(existsPermission + uri.toString().replaceFirst(UriTools.URI_PERMISSION_REQUEST_COMPLETE_PREFIX, ""));
+ DocumentFile rootDocumentFile = DocumentFile.fromSingleUri(context, targetUri);
+ Objects.requireNonNull(rootDocumentFile, "rootDocumentFile is null");
+ //创建一个 DocumentFile表示以给定的 Uri根的文档树。其实就是获取子目录的权限
+ DocumentFile pickedDir = rootDocumentFile.fromTreeUri(context, targetUri);
+
+ Objects.requireNonNull(pickedDir, "pickedDir is null");
+ DocumentFile[] documentFiles = pickedDir.listFiles();
+
+ return documentFiles;
+ }
+
+ public static Uri[] getNeedUri(DocumentFile chapterFile, Uri[] result) {
+ DocumentFile[] files = chapterFile.listFiles();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ getNeedUri(files[i], result);
+ } else {
+ switch (files[i].getName()) {
+ case "audio.m4s":
+ result[0] = files[i].getUri();
+ break;
+ case "video.m4s":
+ result[1] = files[i].getUri();
+ break;
+ case "entry.json":
+ result[2] = files[i].getUri();
+ break;
+ case "danmaku.xml":
+ result[3] = files[i].getUri();
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+
+ public static String[] getCollectionChapterName(Uri jsonUri, String[] result) {
+ //uri转byte
+ byte[] jsonByte = UriUtils.uri2Bytes(jsonUri);
+ //通过jsonByte获取名称
+ result = FileTools.getCollectionChapterName(jsonByte, result);
+ return result;
+ }
+}
diff --git a/app/src/main/java/com/molihua/hlbmerge/utils/UriTools.java b/app/src/main/java/com/molihua/hlbmerge/utils/UriTools.java
deleted file mode 100644
index 113b89f..0000000
--- a/app/src/main/java/com/molihua/hlbmerge/utils/UriTools.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.molihua.hlbmerge.utils;
-
-/**
- * @ClassName: UriTools
- * @Author: molihuan
- * @Date: 2022/12/24/21:28
- * @Description:
- */
-public class UriTools {
-}