feat:移除七牛云改用腾讯COS
This commit is contained in:
@@ -251,7 +251,7 @@ class UploadRoomAlbumDialogFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
if (requestCode == 200) {
|
||||
PhotoProvider.getResultPathListAsync(data) {
|
||||
it?.let { paths ->
|
||||
it?.mapNotNull { it.path }?.let { paths ->
|
||||
compressPhotos(paths.toMutableList())
|
||||
}
|
||||
}
|
||||
|
@@ -207,7 +207,7 @@ class PhotoDialog : BaseDialogFragment<PhotoDialogBinding>(), EasyPermissions.Pe
|
||||
REQUEST_CODE_OPEN_CAMERA_PROVIDER -> {
|
||||
if (mOnResultCallBack == null || data == null) return
|
||||
PhotoProvider.getResultPathListAsync(data) { paths ->
|
||||
val list = paths?.toMutableList() ?: ArrayList()
|
||||
val list = paths?.mapNotNull { it.path }?.toMutableList() ?: ArrayList()
|
||||
val path = list[0]
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
mJob?.cancel()
|
||||
@@ -233,7 +233,7 @@ class PhotoDialog : BaseDialogFragment<PhotoDialogBinding>(), EasyPermissions.Pe
|
||||
REQUEST_CODE_OPEN_PHOTO_PROVIDER -> {
|
||||
if (mOnResultCallBack == null || data == null) return
|
||||
PhotoProvider.getResultPathListAsync(data) { list ->
|
||||
val paths = list?.toMutableList() ?: ArrayList()
|
||||
val paths = list?.mapNotNull { it.path }?.toMutableList() ?: ArrayList()
|
||||
if (paths.isEmpty()) {
|
||||
mOnResultCallBack?.choicePhotoCallBack(paths)
|
||||
} else {
|
||||
|
@@ -86,13 +86,25 @@ object PhotoProvider {
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun photoProvider(activity: FragmentActivity, maxSelect: Int = 1, canChooseGif: Boolean = false, resultCode: Int, isClearCache: Boolean = true) {
|
||||
fun photoProvider(
|
||||
activity: FragmentActivity,
|
||||
maxSelect: Int = 1,
|
||||
canChooseGif: Boolean = false,
|
||||
resultCode: Int,
|
||||
isClearCache: Boolean = true,
|
||||
useWidth: Boolean = false
|
||||
) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
if (isClearCache && isClearByTime()) {
|
||||
withContext(Dispatchers.IO) { clearCache() }
|
||||
}
|
||||
EasyPhotos.createAlbum(activity, false, false, GlideEngine())//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93)
|
||||
EasyPhotos.createAlbum(
|
||||
activity,
|
||||
false,
|
||||
useWidth,
|
||||
GlideEngine()
|
||||
)//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93)
|
||||
.setCount(maxSelect)//参数说明:最大可选数,默认1
|
||||
.setGif(canChooseGif)
|
||||
.setPuzzleMenu(false)
|
||||
@@ -131,7 +143,7 @@ object PhotoProvider {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getResultPathListAsync(data: Intent?, resultListener: ((List<String>?) -> Unit)) {
|
||||
fun getResultPathListAsync(data: Intent?, resultListener: ((List<Photo>?) -> Unit)) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
val list: List<Photo>? = data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS)
|
||||
@@ -151,22 +163,21 @@ object PhotoProvider {
|
||||
* 1. 项目使用到BitmapFactory.decodeFile(imgPath, options)之类的方法,该方法在android Q直接使用外部path测试中发现,获取图片信息失败
|
||||
*
|
||||
*/
|
||||
private fun copyToInternalCache(photos: List<Photo>?): List<String>? {
|
||||
private fun copyToInternalCache(photos: List<Photo>?): List<Photo>? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val foldPath = getInternalPath() + File.separator
|
||||
val newPaths = ArrayList<String>()
|
||||
photos?.forEach {
|
||||
if (it.uri != null && !it.name.isNullOrEmpty()) {
|
||||
val path = "$foldPath${it.name}"
|
||||
if (FileHelper.copyFileFromUri(it.uri, path, true)) {
|
||||
newPaths.add(path)
|
||||
it.path = path
|
||||
Logger.debug(TAG, "path: ${it.path} , displayName: ${it.name} , newPath: $path ")
|
||||
}
|
||||
}
|
||||
}
|
||||
newPaths
|
||||
photos
|
||||
} else {
|
||||
photos?.takeIf { it.isNotEmpty() }?.map { it.path }
|
||||
photos
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -36,6 +36,10 @@ public class CustomItem implements Parcelable, Serializable {
|
||||
|
||||
private String format;
|
||||
|
||||
private int width;
|
||||
|
||||
private int height;
|
||||
|
||||
public String getPath(){
|
||||
return path;
|
||||
}
|
||||
@@ -66,7 +70,7 @@ public class CustomItem implements Parcelable, Serializable {
|
||||
}
|
||||
|
||||
public CustomItem(String path, int fileType) {
|
||||
this(path, fileType, "jpeg");
|
||||
this(path, fileType, "jpeg", 0, 0);
|
||||
}
|
||||
|
||||
public CustomItem() {
|
||||
@@ -82,12 +86,16 @@ public class CustomItem implements Parcelable, Serializable {
|
||||
dest.writeString(this.path);
|
||||
dest.writeInt(this.fileType);
|
||||
dest.writeString(this.format);
|
||||
dest.writeInt(this.width);
|
||||
dest.writeInt(this.height);
|
||||
}
|
||||
|
||||
protected CustomItem(Parcel in) {
|
||||
this.path = in.readString();
|
||||
this.fileType = in.readInt();
|
||||
this.format = in.readString();
|
||||
this.width = in.readInt();
|
||||
this.height = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<CustomItem> CREATOR = new Creator<CustomItem>() {
|
||||
|
@@ -22,6 +22,7 @@ import com.yizhuan.xchat_android_library.utils.ListUtils;
|
||||
import com.yizhuan.xchat_android_library.utils.ResUtil;
|
||||
import com.yizhuan.xchat_android_library.utils.file.JXFileUtils;
|
||||
import com.yizhuan.xchat_android_library.utils.image.JXImageUtils;
|
||||
import com.zhihu.matisse.internal.entity.CustomItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -48,9 +49,9 @@ public class PublishPresenter extends BaseMvpPresenter<IPublishView> {
|
||||
|
||||
private MiniWorldChooseInfo miniWorldChooseInfo = new MiniWorldChooseInfo();
|
||||
|
||||
public void publishDy(List<String> list, long worldId, String content, boolean isOriginalImage) {
|
||||
public void publishDy(List<DynamicMedia> list, long worldId, String content, boolean isOriginalImage) {
|
||||
publishBody = new PublishBody();
|
||||
List<String> uploadList = new ArrayList<>(list);
|
||||
List<DynamicMedia> uploadList = new ArrayList<>(list);
|
||||
int type = ListUtils.isListEmpty(uploadList) ? 0 : 2;
|
||||
publishBody.setType(type);
|
||||
publishBody.setUid(AuthModel.get().getCurrentUid());
|
||||
@@ -77,7 +78,7 @@ public class PublishPresenter extends BaseMvpPresenter<IPublishView> {
|
||||
});
|
||||
}
|
||||
|
||||
private Single<String> uploadImage(List<String> imagePaths) {
|
||||
private Single<String> uploadImage(List<DynamicMedia> imagePaths) {
|
||||
upload(imagePaths);
|
||||
return Single.create(emitter ->
|
||||
mImageUploadSubscribe = Observable.interval(500, TimeUnit.MILLISECONDS)
|
||||
@@ -91,22 +92,34 @@ public class PublishPresenter extends BaseMvpPresenter<IPublishView> {
|
||||
}));
|
||||
}
|
||||
|
||||
private void upload(List<String> imagePaths) {
|
||||
private void upload(List<DynamicMedia> imagePaths) {
|
||||
if (imagePaths == null || imagePaths.size() == 0) {
|
||||
return;
|
||||
}
|
||||
String file = imagePaths.get(0);
|
||||
DynamicMedia item = imagePaths.get(0);
|
||||
String file = item.getLocalFilePath();
|
||||
Single.create((SingleOnSubscribe<String>) e -> {
|
||||
long fileLength = JXFileUtils.getFileLength(file);
|
||||
LogUtil.print(ResUtil.getString(R.string.publish_presenter_publishpresenter_01) + fileLength);
|
||||
String compressFile = null;
|
||||
if (!isOriginalImage && fileLength > ImageUploadConfig.MAX_FILE_SIZE) {
|
||||
compressFile = JXImageUtils.compressImagePxAndQuality(
|
||||
JXImageUtils.CompressResult result = JXImageUtils.compressImagePxAndQuality(
|
||||
file, DirectoryHelper.get().getDynamicDir(),
|
||||
"dynamic_" + System.currentTimeMillis() + ".jpg",
|
||||
ImageUploadConfig.EXPECT_MIN_WIDTH,
|
||||
ImageUploadConfig.EXPECT_COMPRESS_SIZE);
|
||||
|
||||
if (result != null) {
|
||||
compressFile = result.getPath();
|
||||
if (result.getWidth() > 0 && item.getWidth() != result.getWidth()) {
|
||||
item.setWidth(result.getWidth());
|
||||
}
|
||||
if (result.getHeight() > 0 && item.getHeight() != result.getHeight()) {
|
||||
item.setHeight(result.getHeight());
|
||||
}
|
||||
if (result.getFormat() != null) {
|
||||
item.setFormat(result.getFormat());
|
||||
}
|
||||
}
|
||||
LogUtil.print(ResUtil.getString(R.string.publish_presenter_publishpresenter_02) + compressFile);
|
||||
}
|
||||
if (!TextUtils.isEmpty(compressFile)) {
|
||||
@@ -118,21 +131,22 @@ public class PublishPresenter extends BaseMvpPresenter<IPublishView> {
|
||||
}
|
||||
})
|
||||
.compose(RxHelper.handleSchedulers())
|
||||
.flatMap((Function<String, SingleSource<DynamicMedia>>)
|
||||
path -> FileModel.get().uploadFileReturnImageInfo(path))
|
||||
.flatMap((Function<String, SingleSource<String>>)
|
||||
path -> FileModel.get().uploadFile(path))
|
||||
.compose(bindUntilEvent(PresenterEvent.DESTROY))
|
||||
.subscribe(new DontWarnObserver<DynamicMedia>() {
|
||||
.subscribe(new DontWarnObserver<String>() {
|
||||
@Override
|
||||
public void acceptThrowable(DynamicMedia media, Throwable throwable) {
|
||||
super.acceptThrowable(media, throwable);
|
||||
public void acceptThrowable(String url, Throwable throwable) {
|
||||
super.acceptThrowable(url, throwable);
|
||||
if (throwable != null) {
|
||||
if (mImageUploadSubscribe != null) {
|
||||
mImageUploadSubscribe.dispose();
|
||||
}
|
||||
dealUploadFileError(throwable);
|
||||
} else {
|
||||
LogUtil.print(ResUtil.getString(R.string.publish_presenter_publishpresenter_04), media);
|
||||
publishBody.addDynamicMedia(media);
|
||||
item.setResUrl(url);
|
||||
LogUtil.print(ResUtil.getString(R.string.publish_presenter_publishpresenter_04), item);
|
||||
publishBody.addDynamicMedia(item);
|
||||
imagePaths.remove(0);
|
||||
upload(imagePaths);
|
||||
}
|
||||
|
@@ -54,6 +54,7 @@ import com.yizhuan.xchat_android_library.common.photo.PhotoProvider;
|
||||
import com.yizhuan.xchat_android_library.common.util.PhotoCompressUtil;
|
||||
import com.yizhuan.xchat_android_library.common.util.PhotosCompressCallback;
|
||||
import com.yizhuan.xchat_android_library.easypermisssion.EasyPermissions;
|
||||
import com.yizhuan.xchat_android_library.easyphoto.models.album.entity.Photo;
|
||||
import com.yizhuan.xchat_android_library.easyphoto.utils.settings.SettingsUtils;
|
||||
import com.yizhuan.xchat_android_library.utils.ResUtil;
|
||||
import com.yizhuan.xchat_android_library.utils.SingleToastUtil;
|
||||
@@ -297,7 +298,7 @@ public class PublishActivity extends BaseMvpActivity<IPublishView, PublishPresen
|
||||
tvPublish.setEnabled(false);
|
||||
getDialogManager().showProgressDialog(context);
|
||||
getMvpPresenter().publishDy(
|
||||
ObjectTypeHelper.customToStringList(uploadList),
|
||||
ObjectTypeHelper.customToMediaList(uploadList),
|
||||
getMvpPresenter().getWorldId(), etContent.getText().toString(), isOriginalImage);
|
||||
}
|
||||
|
||||
@@ -333,23 +334,34 @@ public class PublishActivity extends BaseMvpActivity<IPublishView, PublishPresen
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
PhotoProvider.getResultPathListAsync(data, new Function1<List<String>, Unit>() {
|
||||
PhotoProvider.getResultPathListAsync(data, new Function1<List<? extends Photo>, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(List<String> list) {
|
||||
public Unit invoke(List<? extends Photo> list) {
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
if (mJob != null) {
|
||||
mJob.cancel(null);
|
||||
}
|
||||
mJob = PhotoCompressUtil.compress(PublishActivity.this, list,
|
||||
ArrayList<String> pathList = new ArrayList<>();
|
||||
for (Photo photo : list) {
|
||||
pathList.add(photo.path);
|
||||
}
|
||||
mJob = PhotoCompressUtil.compress(PublishActivity.this, pathList,
|
||||
PhotoCompressUtil.getCompressCachePath("publish")
|
||||
, new PhotosCompressCallback() {
|
||||
@Override
|
||||
public void onSuccess(@NonNull ArrayList<String> compressedImgList) {
|
||||
List<CustomItem> pathResult = new ArrayList<>();
|
||||
for (String path : compressedImgList) {
|
||||
pathResult.add(new CustomItem(path, CustomItem.IMAGE_NORMAL, "jpeg"));
|
||||
for (int i = 0; i < compressedImgList.size(); i++) {
|
||||
if (i < list.size()) {
|
||||
Photo photo = list.get(i);
|
||||
String format = "image/jpeg";
|
||||
if (photo.type != null) {
|
||||
format = photo.type;
|
||||
}
|
||||
pathResult.add(new CustomItem(compressedImgList.get(i), CustomItem.IMAGE_NORMAL, format, photo.width, photo.height));
|
||||
}
|
||||
}
|
||||
if (pathResult.size() == 0) {
|
||||
return;
|
||||
@@ -635,6 +647,7 @@ public class PublishActivity extends BaseMvpActivity<IPublishView, PublishPresen
|
||||
maxSelect - uploadList.size(),
|
||||
true,
|
||||
REQUEST_CODE_OPEN_PHOTO_PROVIDER,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
@@ -22,6 +22,22 @@ public class ObjectTypeHelper {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public static List<DynamicMedia> customToMediaList(List<CustomItem> paramsList) {
|
||||
List<DynamicMedia> resultList = new ArrayList<>();
|
||||
if (paramsList == null) {
|
||||
return resultList;
|
||||
}
|
||||
for (CustomItem item : paramsList) {
|
||||
DynamicMedia media = new DynamicMedia();
|
||||
media.setLocalFilePath(item.getPath());
|
||||
media.setWidth(item.getWidth());
|
||||
media.setHeight(item.getHeight());
|
||||
media.setFormat(item.getFormat());
|
||||
resultList.add(media);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public static List<CustomItem> stringToCustomList(List<String> paramsList) {
|
||||
List<CustomItem> resultList = new ArrayList<>();
|
||||
if (paramsList == null) {
|
||||
|
@@ -107,6 +107,8 @@ dependencies {
|
||||
implementation 'com.liulishuo.okdownload:okhttp:1.0.7'
|
||||
|
||||
implementation 'com.tencent.liteav:LiteAVSDK_TRTC:11.4.0.13189'
|
||||
|
||||
api 'com.qcloud.cos:cos-android:5.9.23'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@@ -2,22 +2,20 @@ package com.yizhuan.xchat_android_core.file;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.netease.nim.uikit.common.util.log.LogUtil;
|
||||
import com.qiniu.android.common.FixedZone;
|
||||
import com.qiniu.android.storage.Configuration;
|
||||
import com.qiniu.android.storage.UploadManager;
|
||||
import com.chuhai.utils.AppUtils;
|
||||
import com.chuhai.utils.PathUtils;
|
||||
import com.yizhuan.xchat_android_core.R;
|
||||
import com.yizhuan.xchat_android_core.base.BaseModel;
|
||||
import com.yizhuan.xchat_android_core.bean.response.ServiceResult;
|
||||
import com.yizhuan.xchat_android_core.community.bean.DynamicMedia;
|
||||
import com.yizhuan.xchat_android_core.file.cos.CosToken;
|
||||
import com.yizhuan.xchat_android_core.exception.ErrorThrowable;
|
||||
import com.yizhuan.xchat_android_core.file.cos.CosClient;
|
||||
import com.yizhuan.xchat_android_core.utils.net.RxHelper;
|
||||
import com.yizhuan.xchat_android_library.net.rxnet.RxNet;
|
||||
import com.yizhuan.xchat_android_library.utils.ResUtil;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.GET;
|
||||
@@ -29,120 +27,50 @@ public class FileModel extends BaseModel implements IFileModel {
|
||||
}
|
||||
|
||||
private FileModel() {
|
||||
Configuration config = new Configuration.Builder()
|
||||
.zone(FixedZone.zoneAs0) // 设置区域,不指定会自动选择。指定不同区域的上传域名、备用域名、备用IP。
|
||||
.build();
|
||||
uploadManager = new UploadManager(config);
|
||||
}
|
||||
|
||||
public static FileModel get() {
|
||||
return Helper.INSTANCE;
|
||||
}
|
||||
|
||||
private UploadManager uploadManager;
|
||||
private final Api api = RxNet.create(Api.class);
|
||||
private CosToken cosToken;
|
||||
|
||||
private Single<CosToken> getCosToken() {
|
||||
if (cosToken != null && cosToken.isValid()) {
|
||||
return Single.just(cosToken);
|
||||
} else {
|
||||
return api.getCosToken().compose(RxHelper.handleSchedulers())
|
||||
.compose(RxHelper.handleBeanData()).map(cosToken -> {
|
||||
FileModel.get().cosToken = cosToken;
|
||||
return cosToken;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Single<String> uploadFile(String path) {
|
||||
|
||||
File file;
|
||||
if (TextUtils.isEmpty(path) || !((file = new File(path)).exists())) {
|
||||
return Single.error(new ErrorThrowable(path + ResUtil.getString(R.string.xchat_android_core_file_filemodel_01)));
|
||||
}
|
||||
File finalFile = file;
|
||||
return api.getUploadToken()
|
||||
.compose(RxHelper.handleSchedulers())
|
||||
.compose(RxHelper.handleBeanData())
|
||||
.flatMap(uploadToken -> Single.create(singleEmitter ->
|
||||
uploadManager.put(finalFile, uploadToken.getKey(), uploadToken.getToken() ,
|
||||
(key, info, response) -> {
|
||||
if (info.isOK()) {
|
||||
try {
|
||||
String imgUrl = response.getString("path");
|
||||
singleEmitter.onSuccess(imgUrl);
|
||||
} catch (Exception e) {
|
||||
singleEmitter.onError(e);
|
||||
}
|
||||
} else {
|
||||
singleEmitter.onError(new Throwable(info.error));
|
||||
}
|
||||
}, null)
|
||||
));
|
||||
String outName = UUID.randomUUID().toString() + PathUtils.INSTANCE.getSuffixType(finalFile.getName());
|
||||
return getCosToken().flatMap(token -> CosClient.INSTANCE.upload(AppUtils.getApp(), finalFile, outName, token).map(cosXmlResult -> cosXmlResult.accessUrl));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<DynamicMedia> uploadFileReturnImageInfo(String path) {
|
||||
return uploadFileReturnImageInfo(path, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<DynamicMedia> uploadFileReturnImageInfo(String path, String qiniuName) {
|
||||
File file;
|
||||
if (TextUtils.isEmpty(path) || !((file = new File(path)).exists())) {
|
||||
return Single.error(new ErrorThrowable(path + ResUtil.getString(R.string.xchat_android_core_file_filemodel_02)));
|
||||
}
|
||||
|
||||
File finalFile = file;
|
||||
return api.getUploadToken()
|
||||
.compose(RxHelper.handleSchedulers())
|
||||
.compose(RxHelper.handleBeanData())
|
||||
.flatMap(uploadToken -> Single.create(singleEmitter ->
|
||||
uploadManager.put(finalFile, uploadToken.getKey(), uploadToken.getToken(),
|
||||
(key, info, response) -> {
|
||||
if (info.isOK()) {
|
||||
try {
|
||||
LogUtil.print(ResUtil.getString(R.string.xchat_android_core_file_filemodel_03));
|
||||
LogUtil.print(response);
|
||||
DynamicMedia media = responseToMeia(response);
|
||||
if (media != null) {
|
||||
singleEmitter.onSuccess(media);
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
singleEmitter.onError(new Throwable("qiniu json error"));
|
||||
} else {
|
||||
singleEmitter.onError(new Throwable(info.error));
|
||||
}
|
||||
}, null)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Single<String> downloadFile(String url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private DynamicMedia responseToMeia(JSONObject response) {
|
||||
DynamicMedia media = new DynamicMedia();
|
||||
try {
|
||||
String imgNamePath = response.getString("path");
|
||||
media.setResUrl(imgNamePath);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
media.setFormat(response.getString("format"));
|
||||
media.setWidth(response.getInt("w"));
|
||||
media.setHeight(response.getInt("h"));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
LogUtil.print(ResUtil.getString(R.string.xchat_android_core_file_filemodel_04), media);
|
||||
return media;
|
||||
}
|
||||
|
||||
interface Api {
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET("/qiniu/upload/getUploadToken")
|
||||
Single<ServiceResult<UploadToken>> getUploadToken();
|
||||
|
||||
@GET("/tencent/cos/getToken")
|
||||
Single<ServiceResult<CosToken>> getCosToken();
|
||||
}
|
||||
}
|
||||
|
@@ -22,9 +22,4 @@ public interface IFileModel extends IModel {
|
||||
* @return
|
||||
*/
|
||||
Single<String> downloadFile(String url);
|
||||
|
||||
Single<DynamicMedia> uploadFileReturnImageInfo(String path);
|
||||
|
||||
Single<DynamicMedia> uploadFileReturnImageInfo(String path, String qiniuName);
|
||||
|
||||
}
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package com.yizhuan.xchat_android_core.file;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UploadToken {
|
||||
private String key;
|
||||
private String token;
|
||||
}
|
@@ -0,0 +1,116 @@
|
||||
package com.yizhuan.xchat_android_core.file.cos
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.tencent.cos.xml.CosXmlService
|
||||
import com.tencent.cos.xml.CosXmlServiceConfig
|
||||
import com.tencent.cos.xml.exception.CosXmlClientException
|
||||
import com.tencent.cos.xml.exception.CosXmlServiceException
|
||||
import com.tencent.cos.xml.listener.CosXmlResultListener
|
||||
import com.tencent.cos.xml.model.CosXmlRequest
|
||||
import com.tencent.cos.xml.model.CosXmlResult
|
||||
import com.tencent.cos.xml.transfer.COSXMLUploadTask
|
||||
import com.tencent.cos.xml.transfer.TransferConfig
|
||||
import com.tencent.cos.xml.transfer.TransferManager
|
||||
import com.yizhuan.xchat_android_core.file.cos.CosCredentialProvider
|
||||
import com.yizhuan.xchat_android_core.file.cos.CosException
|
||||
import com.yizhuan.xchat_android_core.file.cos.CosToken
|
||||
import com.yizhuan.xchat_android_library.common.application.Env
|
||||
import io.reactivex.Single
|
||||
import java.io.File
|
||||
|
||||
|
||||
/**
|
||||
* Created by Max on 2024/1/16 11:09
|
||||
* Desc:
|
||||
**/
|
||||
object CosClient {
|
||||
private var cosXmlClient: CosXmlService? = null
|
||||
private var credentialProvider: CosCredentialProvider? = null
|
||||
|
||||
private fun getCosXmlClient(context: Context, token: CosToken): CosXmlService {
|
||||
var client = this.cosXmlClient
|
||||
if (client != null && credentialProvider != null) {
|
||||
credentialProvider?.updateCredentials(token.toCredential())
|
||||
return client
|
||||
}
|
||||
// 创建 CosXmlServiceConfig 对象,根据需要修改默认的配置参数
|
||||
val serviceConfig: CosXmlServiceConfig = CosXmlServiceConfig.Builder()
|
||||
.setRegion(token.region)
|
||||
.isHttps(true) // 使用 HTTPS 请求, 默认为 HTTP 请求
|
||||
.builder()
|
||||
|
||||
val credentials = token.toCredential()
|
||||
credentialProvider = CosCredentialProvider(credentials)
|
||||
// 初始化 COS Service,获取实例
|
||||
client = CosXmlService(
|
||||
context,
|
||||
serviceConfig, credentialProvider
|
||||
)
|
||||
cosXmlClient = client
|
||||
return client
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param outName 远端文件名
|
||||
*/
|
||||
fun upload(
|
||||
context: Context,
|
||||
file: File,
|
||||
outName: String,
|
||||
token: CosToken
|
||||
): Single<CosXmlResult> {
|
||||
if (Env.isDebug()) {
|
||||
Log.e("CosClient", "upload file:${file.absolutePath} outName:${outName}")
|
||||
}
|
||||
return Single.create {
|
||||
uploadFile(context, file, outName, token).apply {
|
||||
setCosXmlResultListener(object : CosXmlResultListener {
|
||||
override fun onSuccess(request: CosXmlRequest?, result: CosXmlResult) {
|
||||
if (Env.isDebug()) {
|
||||
Log.e("CosClient", "upload onSuccess result:${result.accessUrl}")
|
||||
}
|
||||
it.onSuccess(result)
|
||||
}
|
||||
|
||||
override fun onFail(
|
||||
request: CosXmlRequest?,
|
||||
clientException: CosXmlClientException?,
|
||||
serviceException: CosXmlServiceException?
|
||||
) {
|
||||
if (Env.isDebug()) {
|
||||
Log.e("CosClient", "upload onFail clientException:$clientException")
|
||||
Log.e("CosClient", "upload onFail serviceException:$serviceException")
|
||||
}
|
||||
it.onError(CosException(clientException, serviceException))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param outName 远端文件名
|
||||
*/
|
||||
private fun uploadFile(
|
||||
context: Context,
|
||||
file: File,
|
||||
outName: String,
|
||||
token: CosToken
|
||||
): COSXMLUploadTask {
|
||||
val cosXmlService = getCosXmlClient(context, token)
|
||||
// 初始化 TransferConfig,这里使用默认配置,如果需要定制,请参考 SDK 接口文档
|
||||
val transferConfig = TransferConfig.Builder().build()
|
||||
// 初始化 TransferManager
|
||||
val transferManager = TransferManager(
|
||||
cosXmlService,
|
||||
transferConfig
|
||||
)
|
||||
return transferManager.upload(
|
||||
token.bucket, outName,
|
||||
file.absolutePath, null
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package com.yizhuan.xchat_android_core.file.cos
|
||||
|
||||
import com.tencent.qcloud.core.auth.BasicLifecycleCredentialProvider
|
||||
import com.tencent.qcloud.core.auth.QCloudLifecycleCredentials
|
||||
|
||||
/**
|
||||
* Created by Max on 2024/1/16 11:28
|
||||
* Desc:
|
||||
**/
|
||||
class CosCredentialProvider(private var credentials: QCloudLifecycleCredentials) :
|
||||
BasicLifecycleCredentialProvider() {
|
||||
|
||||
fun updateCredentials(credentials: QCloudLifecycleCredentials) {
|
||||
this.credentials = credentials
|
||||
}
|
||||
|
||||
override fun fetchNewCredentials(): QCloudLifecycleCredentials {
|
||||
return credentials
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package com.yizhuan.xchat_android_core.file.cos
|
||||
|
||||
import com.tencent.cos.xml.exception.CosXmlClientException
|
||||
import com.tencent.cos.xml.exception.CosXmlServiceException
|
||||
|
||||
/**
|
||||
* Created by Max on 2024/1/16 15:49
|
||||
* Desc:
|
||||
**/
|
||||
class CosException : Exception {
|
||||
var clientException: CosXmlClientException? = null
|
||||
var serviceException: CosXmlServiceException? = null
|
||||
|
||||
constructor(
|
||||
clientException: CosXmlClientException?,
|
||||
serviceException: CosXmlServiceException?
|
||||
) : super(clientException ?: serviceException) {
|
||||
this.clientException = clientException
|
||||
this.serviceException = serviceException
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.yizhuan.xchat_android_core.file.cos
|
||||
|
||||
import com.tencent.qcloud.core.auth.QCloudLifecycleCredentials
|
||||
import com.tencent.qcloud.core.auth.SessionQCloudCredentials
|
||||
import com.yizhuan.xchat_android_core.utils.CurrentTimeUtils
|
||||
|
||||
/**
|
||||
* Created by Max on 2024/1/16 11:44
|
||||
* Desc:
|
||||
**/
|
||||
data class CosToken(
|
||||
val secretId: String?,
|
||||
val secretKey: String?,
|
||||
val sessionToken: String?,
|
||||
val bucket: String?,
|
||||
val region: String?,
|
||||
val startTime: Long?,
|
||||
val expireTime: Long?,
|
||||
) {
|
||||
|
||||
/**
|
||||
* 是否有效
|
||||
*/
|
||||
fun isValid(): Boolean {
|
||||
if (expireTime == null) {
|
||||
return false
|
||||
}
|
||||
val currentTime = CurrentTimeUtils.getCurrentTime() / 1000
|
||||
// 预留一点安全时长
|
||||
var safeTime = 30
|
||||
if (safeTime >= (expireTime - (startTime ?: 0))) {
|
||||
safeTime = 0
|
||||
}
|
||||
return currentTime <= (expireTime - safeTime)
|
||||
}
|
||||
|
||||
fun toCredential(): QCloudLifecycleCredentials {
|
||||
return SessionQCloudCredentials(
|
||||
secretId ?: "", secretKey ?: "",
|
||||
sessionToken ?: "", startTime ?: 0, expireTime ?: 0
|
||||
)
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package com.yizhuan.xchat_android_core.community.bean;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import kotlin.jvm.Transient;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,15 @@ public class DynamicMedia {
|
||||
private String format;
|
||||
private int width;
|
||||
private int height;
|
||||
@Transient
|
||||
private String localFilePath;
|
||||
public String getLocalFilePath() {
|
||||
return localFilePath;
|
||||
}
|
||||
|
||||
public void setLocalFilePath(String localFilePath) {
|
||||
this.localFilePath = localFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是网络图片
|
||||
|
@@ -77,7 +77,6 @@ dependencies {
|
||||
def rxjava_android = "2.0.1"
|
||||
def rxlifecycle = "3.1.0"
|
||||
def loggerVersion = "2.2.0"
|
||||
def qiniu = "8.4.4"
|
||||
def SmartRefreshLayoutVersion = "1.0.3"
|
||||
def eventbusVersion = "3.3.1"
|
||||
def fragment_version = "1.6.1"
|
||||
@@ -122,8 +121,6 @@ dependencies {
|
||||
|
||||
api "com.orhanobut:logger:${loggerVersion}"
|
||||
|
||||
api "com.qiniu:qiniu-android-sdk:${qiniu}"
|
||||
|
||||
api "org.greenrobot:eventbus:${eventbusVersion}"
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
|
@@ -693,7 +693,7 @@ public class JXImageUtils {
|
||||
}
|
||||
|
||||
|
||||
public static String compressImagePxAndQuality(String inPath, File outDir, String outFileName, int expectWidth, long expectSize) {
|
||||
public static CompressResult compressImagePxAndQuality(String inPath, File outDir, String outFileName, int expectWidth, long expectSize) {
|
||||
try {
|
||||
if (outDir == null) {
|
||||
return null;
|
||||
@@ -748,14 +748,16 @@ public class JXImageUtils {
|
||||
fos.close();
|
||||
if (thumbnailFile.exists()) {
|
||||
String compressPath = thumbnailFile.getPath();
|
||||
exif = new ExifInterface(compressPath);
|
||||
if (orientation != null) {
|
||||
exif = new ExifInterface(compressPath);
|
||||
exif.setAttribute(ExifInterface.TAG_ORIENTATION, orientation);
|
||||
exif.saveAttributes();
|
||||
}
|
||||
LogUtil.print(ResUtil.getString(R.string.utils_image_jximageutils_06) + getPicRotate(compressPath));
|
||||
return compressPath;
|
||||
}
|
||||
int width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);
|
||||
int height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);
|
||||
return new CompressResult(compressPath, width, height, "image/jpeg");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e("mouse_debug", ResUtil.getString(R.string.utils_image_jximageutils_07));
|
||||
ex.printStackTrace();
|
||||
@@ -816,5 +818,34 @@ public class JXImageUtils {
|
||||
return degree;
|
||||
}
|
||||
|
||||
public static class CompressResult {
|
||||
private String path;
|
||||
private int width;
|
||||
private int height;
|
||||
private String format;
|
||||
|
||||
public CompressResult(String path, int width, int height, String format) {
|
||||
this.path = path;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.qiniu.android.utils.StringUtils;
|
||||
import com.yizhuan.xchat_android_library.common.application.BaseApp;
|
||||
import com.yizhuan.xchat_android_library.common.util.Logger;
|
||||
import com.yizhuan.xchat_android_library.utils.FP;
|
||||
@@ -878,40 +877,4 @@ public class FileHelper {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件转换成字符串
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 字符串内容
|
||||
*/
|
||||
public static String getTxtFileContent(String filePath) {
|
||||
String content = "";
|
||||
if (!StringUtils.isNullOrEmpty(filePath)) {
|
||||
File file = new File(filePath);
|
||||
if (file.isFile()) {
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
String line;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
while ((line = buffReader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
content = sb.toString();
|
||||
} catch (Exception e) {
|
||||
Logger.error(TAG, "getTxtFileContent read fail, e = " + e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
|
519
library/src/module_utils/java/com/chuhai/utils/PathUtils.kt
Normal file
519
library/src/module_utils/java/com/chuhai/utils/PathUtils.kt
Normal file
@@ -0,0 +1,519 @@
|
||||
package com.chuhai.utils
|
||||
|
||||
import android.app.Application
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* getRootPath : 获取根路径
|
||||
* getDataPath : 获取数据路径
|
||||
* getDownloadCachePath : 获取下载缓存路径
|
||||
* getInternalAppDataPath : 获取内存应用数据路径
|
||||
* getInternalAppCodeCacheDir : 获取内存应用代码缓存路径
|
||||
* getInternalAppCachePath : 获取内存应用缓存路径
|
||||
* getInternalAppDbsPath : 获取内存应用数据库路径
|
||||
* getInternalAppDbPath : 获取内存应用数据库路径
|
||||
* getInternalAppFilesPath : 获取内存应用文件路径
|
||||
* getInternalAppSpPath : 获取内存应用 SP 路径
|
||||
* getInternalAppNoBackupFilesPath: 获取内存应用未备份文件路径
|
||||
* getExternalStoragePath : 获取外存路径
|
||||
* getExternalMusicPath : 获取外存音乐路径
|
||||
* getExternalPodcastsPath : 获取外存播客路径
|
||||
* getExternalRingtonesPath : 获取外存铃声路径
|
||||
* getExternalAlarmsPath : 获取外存闹铃路径
|
||||
* getExternalNotificationsPath : 获取外存通知路径
|
||||
* getExternalPicturesPath : 获取外存图片路径
|
||||
* getExternalMoviesPath : 获取外存影片路径
|
||||
* getExternalDownloadsPath : 获取外存下载路径
|
||||
* getExternalDcimPath : 获取外存数码相机图片路径
|
||||
* getExternalDocumentsPath : 获取外存文档路径
|
||||
* getExternalAppDataPath : 获取外存应用数据路径
|
||||
* getExternalAppCachePath : 获取外存应用缓存路径
|
||||
* getExternalAppFilesPath : 获取外存应用文件路径
|
||||
* getExternalAppMusicPath : 获取外存应用音乐路径
|
||||
* getExternalAppPodcastsPath : 获取外存应用播客路径
|
||||
* getExternalAppRingtonesPath : 获取外存应用铃声路径
|
||||
* getExternalAppAlarmsPath : 获取外存应用闹铃路径
|
||||
* getExternalAppNotificationsPath: 获取外存应用通知路径
|
||||
* getExternalAppPicturesPath : 获取外存应用图片路径
|
||||
* getExternalAppMoviesPath : 获取外存应用影片路径
|
||||
* getExternalAppDownloadPath : 获取外存应用下载路径
|
||||
* getExternalAppDcimPath : 获取外存应用数码相机图片路径
|
||||
* getExternalAppDocumentsPath : 获取外存应用文档路径
|
||||
* getExternalAppObbPath : 获取外存应用 OBB 路径
|
||||
* 路径 工具类 By https://github.com/Blankj/AndroidUtilCode -> PathUtils.java
|
||||
* Created by Max on 2018/12/12.
|
||||
*/
|
||||
object PathUtils {
|
||||
|
||||
/**
|
||||
* Return the path of /system.
|
||||
*
|
||||
* @return the path of /system
|
||||
*/
|
||||
val rootPath: String
|
||||
get() = Environment.getRootDirectory().absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /data.
|
||||
*
|
||||
* @return the path of /data
|
||||
*/
|
||||
val dataPath: String
|
||||
get() = Environment.getDataDirectory().absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /cache.
|
||||
*
|
||||
* @return the path of /cache
|
||||
*/
|
||||
val downloadCachePath: String
|
||||
get() = Environment.getDownloadCacheDirectory().absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package.
|
||||
*
|
||||
* @return the path of /data/data/package
|
||||
*/
|
||||
fun getInternalAppDataPath(application: Application): String {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
application.applicationInfo.dataDir
|
||||
} else application.dataDir.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/code_cache.
|
||||
*
|
||||
* @return the path of /data/data/package/code_cache
|
||||
*/
|
||||
fun getInternalAppCodeCacheDir(application: Application): String {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
application.applicationInfo.dataDir + "/code_cache"
|
||||
} else application.codeCacheDir.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/cache.
|
||||
*
|
||||
* @return the path of /data/data/package/cache
|
||||
*/
|
||||
fun getInternalAppCachePath(application: Application): String {
|
||||
return application.cacheDir.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/databases.
|
||||
*
|
||||
* @return the path of /data/data/package/databases
|
||||
*/
|
||||
fun getInternalAppDbsPath(application: Application): String {
|
||||
return application.applicationInfo.dataDir + "/databases"
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/databases/name.
|
||||
*
|
||||
* @param name The name of database.
|
||||
* @return the path of /data/data/package/databases/name
|
||||
*/
|
||||
fun getInternalAppDbPath(application: Application, name: String?): String {
|
||||
return application.getDatabasePath(name).absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/files.
|
||||
*
|
||||
* @return the path of /data/data/package/files
|
||||
*/
|
||||
fun getInternalAppFilesPath(application: Application): String {
|
||||
return application.filesDir.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/shared_prefs.
|
||||
*
|
||||
* @return the path of /data/data/package/shared_prefs
|
||||
*/
|
||||
fun getInternalAppSpPath(application: Application): String {
|
||||
return application.applicationInfo.dataDir + "shared_prefs"
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /data/data/package/no_backup.
|
||||
*
|
||||
* @return the path of /data/data/package/no_backup
|
||||
*/
|
||||
fun getInternalAppNoBackupFilesPath(application: Application): String {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
application.applicationInfo.dataDir + "no_backup"
|
||||
} else application.noBackupFilesDir.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0.
|
||||
*
|
||||
* @return the path of /storage/emulated/0
|
||||
*/
|
||||
val externalStoragePath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStorageDirectory().absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Music.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Music
|
||||
*/
|
||||
val externalMusicPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_MUSIC
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Podcasts.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Podcasts
|
||||
*/
|
||||
val externalPodcastsPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PODCASTS
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Ringtones.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Ringtones
|
||||
*/
|
||||
val externalRingtonesPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_RINGTONES
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Alarms.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Alarms
|
||||
*/
|
||||
val externalAlarmsPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_ALARMS
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Notifications.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Notifications
|
||||
*/
|
||||
val externalNotificationsPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_NOTIFICATIONS
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Pictures.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Pictures
|
||||
*/
|
||||
val externalPicturesPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PICTURES
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Movies.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Movies
|
||||
*/
|
||||
val externalMoviesPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_MOVIES
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Download.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Download
|
||||
*/
|
||||
val externalDownloadsPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/DCIM.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/DCIM
|
||||
*/
|
||||
val externalDcimPath: String?
|
||||
get() = if (isExternalStorageDisable) null else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DCIM
|
||||
).absolutePath
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Documents.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Documents
|
||||
*/
|
||||
val externalDocumentsPath: String?
|
||||
get() {
|
||||
if (isExternalStorageDisable) return null
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
Environment.getExternalStorageDirectory().absolutePath + "/Documents"
|
||||
} else Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOCUMENTS
|
||||
).absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package
|
||||
*/
|
||||
fun getExternalAppDataPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.externalCacheDir?.parentFile?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/cache.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/cache
|
||||
*/
|
||||
fun getExternalAppCachePath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.externalCacheDir?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files
|
||||
*/
|
||||
fun getExternalAppFilesPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(null)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Music.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Music
|
||||
*/
|
||||
fun getExternalAppMusicPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_MUSIC
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Podcasts.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Podcasts
|
||||
*/
|
||||
fun getExternalAppPodcastsPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_PODCASTS
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Ringtones.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Ringtones
|
||||
*/
|
||||
fun getExternalAppRingtonesPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_RINGTONES
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Alarms.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Alarms
|
||||
*/
|
||||
fun getExternalAppAlarmsPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_ALARMS
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Notifications.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Notifications
|
||||
*/
|
||||
fun getExternalAppNotificationsPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_NOTIFICATIONS
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Pictures.
|
||||
*
|
||||
* @return path of /storage/emulated/0/Android/data/package/files/Pictures
|
||||
*/
|
||||
fun getExternalAppPicturesPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_PICTURES
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Movies.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Movies
|
||||
*/
|
||||
fun getExternalAppMoviesPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_MOVIES
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Download.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Download
|
||||
*/
|
||||
fun getExternalAppDownloadPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_DOWNLOADS
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/DCIM.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/DCIM
|
||||
*/
|
||||
fun getExternalAppDcimPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_DCIM
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/data/package/files/Documents.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/data/package/files/Documents
|
||||
*/
|
||||
fun getExternalAppDocumentsPath(application: Application): String? {
|
||||
if (isExternalStorageDisable) return null
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
application.getExternalFilesDir(null)?.absolutePath + "/Documents"
|
||||
} else application.getExternalFilesDir(
|
||||
Environment.DIRECTORY_DOCUMENTS
|
||||
)?.absolutePath
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of /storage/emulated/0/Android/obb/package.
|
||||
*
|
||||
* @return the path of /storage/emulated/0/Android/obb/package
|
||||
*/
|
||||
fun getExternalAppObbPath(application: Application): String? {
|
||||
return if (isExternalStorageDisable) null else application.obbDir.absolutePath
|
||||
}
|
||||
|
||||
private val isExternalStorageDisable: Boolean
|
||||
private get() = Environment.MEDIA_MOUNTED != Environment.getExternalStorageState()
|
||||
|
||||
/**
|
||||
* 判断sub是否在parent之下的文件或子文件夹<br></br>
|
||||
*
|
||||
* @param parent
|
||||
* @param sub
|
||||
* @return
|
||||
*/
|
||||
fun isSub(parent: File, sub: File): Boolean {
|
||||
return try {
|
||||
sub.absolutePath.startsWith(parent.absolutePath)
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子绝对路径与父绝对路径的相对路径
|
||||
*
|
||||
* @param parentPath
|
||||
* @param subPath
|
||||
* @return
|
||||
*/
|
||||
fun getRelativePath(parentPath: String?, subPath: String?): String? {
|
||||
return try {
|
||||
if (parentPath == null || subPath == null) {
|
||||
return null
|
||||
}
|
||||
if (subPath.startsWith(parentPath)) {
|
||||
subPath.substring(parentPath.length)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接两个路径
|
||||
*
|
||||
* @param pathA 路径A
|
||||
* @param pathB 路径B
|
||||
* @return 拼接后的路径
|
||||
*/
|
||||
fun plusPath(pathA: String?, pathB: String?): String? {
|
||||
if (pathA == null) {
|
||||
return pathB
|
||||
}
|
||||
if (pathB == null) {
|
||||
return pathA
|
||||
}
|
||||
return plusPathNotNull(pathA, pathB)
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接两个路径
|
||||
*
|
||||
* @param pathA 路径A
|
||||
* @param pathB 路径B
|
||||
* @return 拼接后的路径
|
||||
*/
|
||||
fun plusPathNotNull(pathA: String, pathB: String): String {
|
||||
val pathAEndSeparator = pathA.endsWith(File.separator)
|
||||
val pathBStartSeparator = pathB.startsWith(File.separator)
|
||||
return if (pathAEndSeparator && pathBStartSeparator) {
|
||||
pathA + pathB.substring(1)
|
||||
} else if (pathAEndSeparator || pathBStartSeparator) {
|
||||
pathA + pathB
|
||||
} else {
|
||||
pathA + File.separator + pathB
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取后缀名称
|
||||
* @param path 路径
|
||||
* @return 后缀格式 .mp4 .gif 等
|
||||
*/
|
||||
fun getSuffixType(path: String): String? {
|
||||
if (path.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
val dotIndex = path.indexOfLast {
|
||||
'.' == it
|
||||
}
|
||||
val separatorIndex = path.indexOfLast {
|
||||
'/' == it
|
||||
}
|
||||
if (dotIndex >= 0 && dotIndex > separatorIndex) {
|
||||
val suffix = path.substring(dotIndex)
|
||||
val askIndex = suffix.indexOfLast {
|
||||
'?' == it
|
||||
}
|
||||
return if (askIndex >= 0) {
|
||||
suffix.substring(0, askIndex)
|
||||
} else {
|
||||
suffix
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user