1.1.9 显示本地视频封面,增加本地视频删除

This commit is contained in:
2026-03-27 09:35:56 +08:00
parent 6f0f7c4c09
commit 73892596b1
6 changed files with 326 additions and 120 deletions

View File

@@ -18,8 +18,8 @@ android {
//There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature.
minSdkVersion 23
targetSdkVersion 29
versionCode 19
versionName "1.1.8"
versionCode 20
versionName "1.1.9"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -1,6 +1,7 @@
package com.hainaos.vc.activity.category.online;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -29,7 +30,12 @@ import com.hjq.toast.Toaster;
import com.tencent.mmkv.MMKV;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class CategoryVideoActivity extends BaseMvvmActivity<CategoryVideoViewModel, ActivityCategoryVideoBinding> {
private static final String TAG = "CategoryActivity";
@@ -118,6 +124,34 @@ public class CategoryVideoActivity extends BaseMvvmActivity<CategoryVideoViewMod
if (baseResponse.code == 200) {
VideoListData videoListData = baseResponse.data;
List<CategoryVideoInfo> categoryVideoInfos = videoListData.getData();
File file = new File(FileUtils.getHainaVideoPath(CategoryVideoActivity.this) + mCategoryInfo.getFolder());
if (file.exists()) {
String[] strings = file.list();
Log.e(TAG, "getViedoList: " + Arrays.toString(strings));
if (strings != null) {
List<String> paths = new ArrayList<>(Arrays.asList(strings));
ArrayList<CategoryVideoInfo> localVideoInfos = paths.stream()
.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return FileUtils.isVideoFile(s);
}
})
.map(new Function<String, CategoryVideoInfo>() {
@Override
public CategoryVideoInfo apply(String s) {
CategoryVideoInfo categoryVideoInfo = new CategoryVideoInfo();
categoryVideoInfo.setName(FileUtils.getFileNameWithoutExtension(s));
categoryVideoInfo.setFile_url(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath());
return categoryVideoInfo;
}
}).collect(Collectors.toCollection(ArrayList::new));
categoryVideoInfos.addAll(localVideoInfos);
}
}
mCategoryVideoAdapter.setData(categoryVideoInfos);

View File

@@ -6,7 +6,7 @@ import androidx.lifecycle.MutableLiveData;
import com.hainaos.vc.base.mvvm.BaseViewModel;
import com.hainaos.vc.bean.BaseResponse;
import com.hainaos.vc.bean.LocalVideoInfo;
import com.hainaos.vc.bean.CategoryVideoInfo;
import com.hainaos.vc.bean.VideoListData;
import com.hainaos.vc.bean.VideoUpdate;
import com.hainaos.vc.config.CommonConfig;
@@ -46,7 +46,7 @@ public class CategoryVideoViewModel extends BaseViewModel<ActivityCategoryVideoB
}
@Deprecated
public MutableLiveData<ArrayList<LocalVideoInfo>> mLocalVideoInfosData = new MutableLiveData<>();
public MutableLiveData<ArrayList<CategoryVideoInfo>> mLocalVideoInfosData = new MutableLiveData<>();
@Deprecated
public void getViedoList(String dir) {
@@ -56,12 +56,12 @@ public class CategoryVideoViewModel extends BaseViewModel<ActivityCategoryVideoB
Log.e(TAG, "getViedoList: " + Arrays.toString(strings));
if (strings != null) {
List<String> paths = new ArrayList<>(Arrays.asList(strings));
ArrayList<LocalVideoInfo> localVideoInfos = paths.stream().map(new Function<String, LocalVideoInfo>() {
ArrayList<CategoryVideoInfo> localVideoInfos = paths.stream().map(new Function<String, CategoryVideoInfo>() {
@Override
public LocalVideoInfo apply(String s) {
LocalVideoInfo localVideoInfo = new LocalVideoInfo();
localVideoInfo.setFile_name(FileUtils.getFileNameWithoutExtension(s));
localVideoInfo.setLocalPath(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath());
public CategoryVideoInfo apply(String s) {
CategoryVideoInfo localVideoInfo = new CategoryVideoInfo();
localVideoInfo.setName(FileUtils.getFileNameWithoutExtension(s));
localVideoInfo.setFile_url(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath());
return localVideoInfo;
}
}).collect(Collectors.toCollection(ArrayList::new));

View File

@@ -24,12 +24,14 @@ import com.arialyy.annotations.Download;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.task.DownloadTask;
import com.bumptech.glide.Glide;
import com.hainaos.vc.R;
import com.hainaos.vc.activity.player.DecryptionPlayerActivity;
import com.hainaos.vc.activity.preview.VideoPreviewActivity;
import com.hainaos.vc.bean.CategoryVideoInfo;
import com.hainaos.vc.config.Permissions;
import com.hainaos.vc.dialog.PermissionsDialog;
import com.hainaos.vc.utils.FFmpegUtils;
import com.hainaos.vc.utils.FileUtils;
import com.hainaos.vc.utils.GlideLoadUtils;
import com.hainaos.vc.utils.TimeUtils;
@@ -43,6 +45,8 @@ import com.shehuan.niv.NiceImageView;
import java.io.File;
import java.util.List;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import me.jessyan.autosize.AutoSizeCompat;
public class CategoryVideoAdapter extends RecyclerView.Adapter<CategoryVideoAdapter.VideoHolder> {
@@ -82,7 +86,61 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter<CategoryVideoAdap
if (!TextUtils.isEmpty(name)) {
holder.tv_title.setText(name);
}
String url = categoryVideoInfo.getFile_url();
if (FileUtils.isLocalFileUriType(url)) {
File file = new File(url);
if (file.exists()) {
String dirPaht = file.getParent();
String videoFileNameWithoutEx = FileUtils.getFileNameWithoutExtension(url);
File localCoverFile = new File(dirPaht + File.separator + videoFileNameWithoutEx + ".png");
if (localCoverFile.exists()) {
GlideLoadUtils.getInstance().glideLoad(mContext, localCoverFile, holder.video_image, R.drawable.picture_split);
} else {
Glide.with(mContext).load(localCoverFile).centerCrop().error(R.drawable.picture_split).into(holder.video_image);
}
String fileSize = Formatter.formatFileSize(mContext, file.length());
if (url.endsWith(".hnv")) {
holder.tv_duration.setText("视频时长: 00:00");
} else {
FFmpegUtils.getDurationInMilliseconds(url, new Observer<Integer>() {
@Override
public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
}
@Override
public void onNext(@io.reactivex.rxjava3.annotations.NonNull Integer integer) {
holder.tv_duration.setText("视频时长: " + TimeUtils.TimeFormat(integer * 1000));
}
@Override
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
holder.tv_size.setText("视频大小: " + fileSize);
holder.tv_download.setText("删除");
holder.tv_download.setBackground(mContext.getDrawable(R.drawable.bg_delete_button));
holder.tv_download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// if (file.exists()) {
showDeleteLocalDialog(file.getAbsolutePath(), position);
// }
}
});
}
} else {
String cover = categoryVideoInfo.getCover();
String md5 = categoryVideoInfo.getMd5();
long sizeBytes = categoryVideoInfo.getFile_size();
@@ -139,7 +197,6 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter<CategoryVideoAdap
}
}
GlideLoadUtils.getInstance().glideLoad(mContext, cover, holder.video_image);
holder.tv_duration.setText("视频时长: " + TimeUtils.TimeFormat(categoryVideoInfo.getDuration() * 1000));
@@ -188,6 +245,7 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter<CategoryVideoAdap
}
}
});
holder.video_image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -209,6 +267,8 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter<CategoryVideoAdap
});
}
}
private PermissionsDialog mPermissionsDialog;
private void showPermissionsDialog(Context context) {
@@ -284,6 +344,34 @@ public class CategoryVideoAdapter extends RecyclerView.Adapter<CategoryVideoAdap
dialog.show();
}
private void showDeleteLocalDialog(String path, int position) {
CustomDialog dialog = new CustomDialog(mContext);
dialog.setTitle("删除文件")
.setMessage("确定要删除文件 " + FileUtils.getFileName(path) + "")
.setPositive("确定")
.setNegtive("取消")
.setOnClickBottomListener(new CustomDialog.OnClickBottomListener() {
@Override
public void onPositiveClick() {
dialog.dismiss();
File file = new File(path);
if (file.delete()) {
mLocalVideoInfos.remove(position);
notifyDataSetChanged();
ToastUtil.show("删除成功");
} else {
ToastUtil.show("删除失败,检查权限是否开启");
}
}
@Override
public void onNegtiveClick() {
dialog.dismiss();
}
});
dialog.show();
}
public void removeItem(int position) {
if (null != mLocalVideoInfos.get(position)) {
mLocalVideoInfos.remove(position);

View File

@@ -101,6 +101,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
final String localPath = localVideoInfo.getLocalPath();
Log.e(TAG, "onBindViewHolder: " + localPath);
String videoFileName = FileUtils.getFileName(localPath);
String videoFileNameWithoutEx = FileUtils.getFileNameWithoutExtension(localPath);
holder.title.setText(videoFileName);
File file = new File(localPath);
@@ -109,6 +110,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
if (file.getName().endsWith(".hnv")) {
String dirPaht = file.getParent();
Log.e(TAG, "onBindViewHolder: dirPaht = " + dirPaht);
File localCoverFile = new File(dirPaht + File.separator + videoFileNameWithoutEx + ".png");
if (mCoverMap != null) {
String coverUrl = mCoverMap.get(videoFileName);
Log.e(TAG, "onBindViewHolder: coverUrl = " + coverUrl);
@@ -123,11 +125,19 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
FileUtils.ariaDownloadCover(mContext, coverFile.getParent(), coverUrl);
}
} else {
holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split));
}
if (localCoverFile.exists()) {
Glide.with(mContext).load(localCoverFile).centerCrop().error(R.drawable.picture_split).into(holder.video_image);
} else {
holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split));
}
}
} else {
if (localCoverFile.exists()) {
Glide.with(mContext).load(localCoverFile).centerCrop().error(R.drawable.picture_split).into(holder.video_image);
} else {
holder.video_image.setImageDrawable(mContext.getDrawable(R.drawable.picture_split));
}
}
} else {
Glide.with(mContext).load(file).centerCrop().error(R.drawable.picture_split).into(holder.video_image);
holder.duration.setText(TimeUtils.TimeFormat(localVideoInfo.getDuration() * 1000));

View File

@@ -2,6 +2,7 @@ package com.hainaos.vc.utils;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
@@ -17,6 +18,8 @@ import com.hainaos.vc.service.DownloadService;
import java.io.File;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.Set;
public class FileUtils {
private static final String TAG = "FileUtils";
@@ -40,6 +43,77 @@ public class FileUtils {
return name;
}
public static boolean isLocalFileUriType(String uriString) {
if (TextUtils.isEmpty(uriString)) {
return false;
}
if (uriString.startsWith("/")) {
return true;
}
// 将字符串解析为 Uri 对象
Uri uri = Uri.parse(uriString);
// 获取 Scheme
String scheme = uri.getScheme();
if (scheme != null) {
Log.e(TAG, "isLocalFileUriType: " + scheme);
switch (scheme.toLowerCase()) {
case "http":
case "https":
return false;
case "content":
case "file":
return true;
default:
return false;
}
} else {
return false;
}
}
private static Set<String> videoFormat = new HashSet<String>() {{
this.add(".hnv");
this.add(".mp4");
this.add(".avi");
this.add(".mkv");
this.add(".flv");
}};
private static Set<String> pictureFormat = new HashSet<String>() {{
this.add(".png");
this.add(".jpg");
this.add(".jpeg");
this.add(".bmp");
}};
public static boolean isVideoFile(String fileName) {
if (TextUtils.isEmpty(fileName)) {
return false;
} else {
if (!fileName.startsWith(".")) {
return videoFormat.contains(getFileType(fileName));
} else {
return videoFormat.contains(fileName);
}
}
}
public static String getFileType(String url) {
if (TextUtils.isEmpty(url)) {
return "";
}
Log.e(TAG, "getFileType: " + url);
if (!url.contains("/")) {
if (url.contains(".")) {
return url.substring(url.indexOf("."));
} else {
return "";
}
} else {
String fileName = url.substring(url.lastIndexOf("/"));
return fileName.substring(fileName.indexOf("."));
}
}
/**
* 转换文件大小 MB
*/