diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 673f3f2be..7bb73c189 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -204,7 +204,6 @@
-
diff --git a/app/src/main/java/com/seafile/seadroid2/SeafException.java b/app/src/main/java/com/seafile/seadroid2/SeafException.java
index 75c7c2d77..15f12c0fe 100644
--- a/app/src/main/java/com/seafile/seadroid2/SeafException.java
+++ b/app/src/main/java/com/seafile/seadroid2/SeafException.java
@@ -34,6 +34,7 @@ public class SeafException extends Exception {
public static final SeafException notFoundException = new SeafException(404, "Not found");
public static final SeafException notFoundUserException = new SeafException(20, "Not logged in");
public static final SeafException notLoggedInException = new SeafException(21, "Not logged in");
+ public static final SeafException transferFileException = new SeafException(22, "The file transfer is abnormal");
public static final SeafException OUT_OF_QUOTA = new SeafException(HTTP_ABOVE_QUOTA, SeadroidApplication.getAppContext().getString(R.string.above_quota));
public static final SeafException REQUEST_EXCEPTION = new SeafException(400, "Request Failed");
diff --git a/app/src/main/java/com/seafile/seadroid2/account/Account.java b/app/src/main/java/com/seafile/seadroid2/account/Account.java
index cc176c260..215fa791a 100644
--- a/app/src/main/java/com/seafile/seadroid2/account/Account.java
+++ b/app/src/main/java/com/seafile/seadroid2/account/Account.java
@@ -103,7 +103,7 @@ public String getSpaceUsed() {
/**
* in fact, the value should be less than 0.
- * however, in some cases, it may be 0, and should also return unlimited.
+ * however, in some cases, it may be 0, and should also return non-limit.
* even if the non-limit is returned, App does not need to verify "Out of quota" status.
* and the "Out of quota" error will be returned in the file upload result.
*/
diff --git a/app/src/main/java/com/seafile/seadroid2/account/AccountUtils.java b/app/src/main/java/com/seafile/seadroid2/account/AccountUtils.java
index 439fba31a..4df312d1a 100644
--- a/app/src/main/java/com/seafile/seadroid2/account/AccountUtils.java
+++ b/app/src/main/java/com/seafile/seadroid2/account/AccountUtils.java
@@ -9,6 +9,7 @@
import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl;
+import com.seafile.seadroid2.preferences.ContextStackPreferenceHelper;
import com.seafile.seadroid2.preferences.Settings;
import com.seafile.seadroid2.ssl.CertsManager;
import com.seafile.seadroid2.ui.camera_upload.CameraUploadManager;
@@ -17,11 +18,14 @@ public class AccountUtils {
public static void logout(Account account) {
- // turn off the gesture lock anyway
+ // turn off the gesture lock
GestureLockSharePreferenceHelper.disable();
Settings.initUserSettings();
+ // clear
+ ContextStackPreferenceHelper.clearStack();
+
NotificationUtils.cancelAll();
// sign out operations
@@ -57,6 +61,9 @@ public static void switchAccount(Account account) {
NotificationUtils.cancelAll();
+ // clear
+ ContextStackPreferenceHelper.clearStack();
+
//
Settings.initUserSettings();
diff --git a/app/src/main/java/com/seafile/seadroid2/config/GlideLoadConfig.java b/app/src/main/java/com/seafile/seadroid2/config/GlideLoadConfig.java
index 785a181a8..c8cf72948 100644
--- a/app/src/main/java/com/seafile/seadroid2/config/GlideLoadConfig.java
+++ b/app/src/main/java/com/seafile/seadroid2/config/GlideLoadConfig.java
@@ -1,5 +1,8 @@
package com.seafile.seadroid2.config;
+import androidx.annotation.DrawableRes;
+
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.request.RequestOptions;
@@ -38,12 +41,33 @@ public static RequestOptions getAvatarOptions() {
.override(WidgetUtils.getThumbnailWidth(), WidgetUtils.getThumbnailWidth());
}
+ private final static RequestOptions _cacheableThumbnailOptions = new RequestOptions()
+ .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
+ .error(R.drawable.icon_image_error_filled)
+ .override(128);
+
+ /**
+ * Get cacheable thumbnail options, width and height are both 128
+ */
+ public static RequestOptions getCacheableThumbnailOptions() {
+ return _cacheableThumbnailOptions;
+ }
+
public static RequestOptions getOptions() {
return new RequestOptions()
+ .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.fallback(R.drawable.file_image)
.placeholder(R.drawable.file_image);
}
+
+ public static RequestOptions getCustomDrawableOptions(@DrawableRes int resId) {
+ return new RequestOptions()
+ .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
+ .fallback(resId)
+ .placeholder(resId);
+ }
+
public static RequestOptions getOptions(String key) {
return new RequestOptions()
.fallback(R.drawable.file_image)
diff --git a/app/src/main/java/com/seafile/seadroid2/config/OriGlideUrl.java b/app/src/main/java/com/seafile/seadroid2/config/OriGlideUrl.java
new file mode 100644
index 000000000..bd76802b2
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/config/OriGlideUrl.java
@@ -0,0 +1,38 @@
+package com.seafile.seadroid2.config;
+
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.load.model.Headers;
+import com.seafile.seadroid2.framework.util.SLogs;
+
+import java.net.URL;
+
+public class OriGlideUrl extends GlideUrl {
+ private String oriKey;
+
+ public OriGlideUrl(URL url) {
+ super(url);
+ }
+
+ public OriGlideUrl(String url) {
+ super(url);
+ }
+
+ public OriGlideUrl(String url, String oriKey) {
+ super(url);
+ this.oriKey = oriKey;
+ }
+
+
+ public OriGlideUrl(URL url, Headers headers) {
+ super(url, headers);
+ }
+
+ public OriGlideUrl(String url, Headers headers) {
+ super(url, headers);
+ }
+
+ @Override
+ public String getCacheKey() {
+ return oriKey;
+ }
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/context/NavContext.java b/app/src/main/java/com/seafile/seadroid2/context/NavContext.java
index 590b8d29e..91770f282 100644
--- a/app/src/main/java/com/seafile/seadroid2/context/NavContext.java
+++ b/app/src/main/java/com/seafile/seadroid2/context/NavContext.java
@@ -5,7 +5,9 @@
import com.seafile.seadroid2.framework.data.model.BaseModel;
import com.seafile.seadroid2.framework.data.db.entities.DirentModel;
import com.seafile.seadroid2.framework.data.db.entities.RepoModel;
+import com.seafile.seadroid2.framework.data.model.ContextModel;
import com.seafile.seadroid2.framework.util.Utils;
+import com.seafile.seadroid2.preferences.ContextStackPreferenceHelper;
import java.util.Stack;
@@ -32,6 +34,9 @@ public void clear() {
}
}
+ /**
+ * Push a model to the stack
+ */
public void push(BaseModel model) {
if (model instanceof RepoModel) {
//clear
@@ -39,14 +44,70 @@ public void push(BaseModel model) {
//push
navStack.push(model);
+
+ saveToSp();
+
} else if (model instanceof DirentModel) {
//stack
navStack.push(model);
+ saveToSp();
+
} else {
throw new IllegalArgumentException("model must be RepoMode or DirentsModel.");
}
}
+ public void restoreNavContextFromSp() {
+
+ navStack.clear();
+
+ Stack stack = ContextStackPreferenceHelper.getStack();
+ if (stack != null && !stack.isEmpty()) {
+ for (ContextModel contextModel : stack) {
+ if (contextModel.type.equals("repo")) {
+ RepoModel repoModel = new RepoModel();
+ repoModel.repo_id = contextModel.repo_id;
+ repoModel.repo_name = contextModel.repo_name;
+ navStack.push(repoModel);
+ } else if (contextModel.type.equals("dirent")) {
+ DirentModel direntModel = new DirentModel();
+ direntModel.repo_id = contextModel.repo_id;
+ direntModel.repo_name = contextModel.repo_name;
+ direntModel.full_path = contextModel.full_path;
+ direntModel.parent_dir = Utils.getParentPath(direntModel.full_path);
+ direntModel.name = Utils.getFileNameFromPath(contextModel.full_path);
+ direntModel.uid = direntModel.getUID();
+ navStack.push(direntModel);
+ }
+ }
+ }
+
+ }
+
+ private void saveToSp() {
+ Stack stack = new Stack<>();
+ if (!navStack.isEmpty()) {
+ for (BaseModel baseModel : navStack) {
+ ContextModel contextModel = new ContextModel();
+
+ if (baseModel instanceof RepoModel e) {
+ contextModel.repo_id = e.repo_id;
+ contextModel.repo_name = e.repo_name;
+ contextModel.type = "repo";
+ contextModel.full_path = "/";
+ } else if (baseModel instanceof DirentModel e) {
+ contextModel.repo_id = e.repo_id;
+ contextModel.repo_name = e.repo_name;
+ contextModel.type = "dirent";
+ contextModel.full_path = e.full_path;
+ }
+ stack.add(contextModel);
+ }
+ }
+
+ ContextStackPreferenceHelper.saveStack(stack);
+ }
+
public void pop() {
if (navStack.empty()) {
return;
@@ -54,6 +115,9 @@ public void pop() {
//stack
navStack.pop();
+
+ saveToSp();
+
}
public void switchToPath(RepoModel repoModel, String full_path) {
@@ -87,6 +151,8 @@ public void switchToPath(RepoModel repoModel, String full_path) {
for (DirentModel model : stack) {
navStack.push(model);
}
+
+ saveToSp();
}
/**
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java b/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java
index 86585bf64..dd645b45c 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java
@@ -130,8 +130,11 @@ public interface FileTransferDAO {
@Query("select * from file_transfer_list where repo_id = :repoId and transfer_action = :transfer_action order by created_at asc limit :limit offset :offset")
List getPageListSync(String repoId, TransferAction transfer_action, int limit, int offset);
- @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = :transferAction and full_path = :full_path and data_status = 0 order by created_at")
- List getListByFullPathSync(String related_account, TransferAction transferAction, String full_path);
+ @Query("select * from file_transfer_list where repo_id = :repoId and transfer_action = :transferAction and full_path = :full_path and data_status = 0 order by created_at")
+ List getListByFullPathSync(String repoId, TransferAction transferAction, String full_path);
+
+ @Query("select * from file_transfer_list where repo_id = :repoId and transfer_action = :transferAction and full_path = :full_path and data_status = 0 order by created_at")
+ Single> getListByFullPathAsync(String repoId, TransferAction transferAction, String full_path);
@Query("select COUNT(*) from file_transfer_list where repo_id = :repoId and full_path = :fullPath and transfer_action = :transfer_action and data_source = :feature and data_status = 0 ")
int checkOneByFullPath(String repoId, String fullPath, TransferAction transfer_action, TransferDataSource feature);
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/db/entities/FileTransferEntity.java b/app/src/main/java/com/seafile/seadroid2/framework/data/db/entities/FileTransferEntity.java
index 0ca8f6f12..46d39a1c7 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/db/entities/FileTransferEntity.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/db/entities/FileTransferEntity.java
@@ -361,44 +361,6 @@ public static FileTransferEntity convertDirentModel2This(boolean is_block, boole
return entity;
}
- public static FileTransferEntity convertDirentFileModel2This(RepoModel repoModel, String full_path, boolean is_auto_transfer, DirentFileModel direntModel) {
- FileTransferEntity entity = new FileTransferEntity();
- entity.full_path = full_path;
-// entity.target_path = direntModel.full_path;
- entity.data_source = TransferDataSource.DOWNLOAD;
- entity.repo_id = repoModel.repo_id;
- entity.repo_name = repoModel.repo_name;
- entity.related_account = repoModel.related_account;
-
-
- entity.file_id = direntModel.id;
- entity.setParent_path(Utils.getParentPath(full_path));
- entity.file_name = direntModel.name;
- entity.file_format = FileTools.getFileExtension(entity.full_path);
- entity.mime_type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(entity.file_format);
- entity.file_size = direntModel.size;
- entity.file_md5 = null;
-
- entity.is_auto_transfer = is_auto_transfer;
-
-// entity.is_block = repoModel.canLocalDecrypt();
- entity.file_strategy = ExistingFileStrategy.AUTO;
-
- entity.is_copy_to_local = true;
-
- long now = System.currentTimeMillis();
- entity.created_at = now;
- entity.modified_at = direntModel.mtime * 1000;
- entity.action_end_at = 0L;
-
- entity.transfer_action = TransferAction.DOWNLOAD;
- entity.transfer_status = TransferStatus.WAITING;
- entity.transfer_result = TransferResult.NO_RESULT;
-
- entity.uid = entity.getUID();
-
- return entity;
- }
public static FileTransferEntity convertDirentRecursiveModel2This(RepoModel repoModel, DirentRecursiveFileModel model) {
@@ -444,7 +406,7 @@ public static FileTransferEntity convertDirentRecursiveModel2This(RepoModel repo
return entity;
}
- public static FileTransferEntity convert2ThisForUploadFileSyncWorker(Account account, RepoModel repoModel, File file, String backupPath) {
+ public static FileTransferEntity convert2ThisForUploadFileSyncWorker(Account account, File file, String backupPath) {
if (!file.isFile()) {
return null;
}
@@ -466,8 +428,8 @@ public static FileTransferEntity convert2ThisForUploadFileSyncWorker(Account acc
entity.mime_type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(entity.file_format);
// entity.is_block = repoModel.encrypted;
- entity.repo_id = repoModel.repo_id;
- entity.repo_name = repoModel.repo_name;
+// entity.repo_id = repoModel.repo_id;
+// entity.repo_name = repoModel.repo_name;
entity.related_account = account.getSignature();
entity.data_source = TransferDataSource.FOLDER_BACKUP;
entity.created_at = System.currentTimeMillis();
@@ -489,7 +451,7 @@ public static FileTransferEntity convert2ThisForUploadFileSyncWorker(Account acc
}
- public static FileTransferEntity convert2ThisForUploadMediaSyncWorker(Account account, String repo_id, String repo_name, File file, String parenPath, long dateAdd, boolean isRemoteExists) {
+ public static FileTransferEntity convert2ThisForUploadMediaSyncWorker(Account account, File file, String parenPath, long dateAdd, boolean isRemoteExists) {
long now = System.currentTimeMillis();
FileTransferEntity entity = new FileTransferEntity();
@@ -502,8 +464,8 @@ public static FileTransferEntity convert2ThisForUploadMediaSyncWorker(Account ac
entity.file_md5 = FileUtils.getFileMD5ToString(entity.full_path).toLowerCase();
entity.mime_type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(entity.file_format);
// entity.is_block = false; //album backup is not store in encrypted repo.
- entity.repo_id = repo_id;
- entity.repo_name = repo_name;
+// entity.repo_id = repo_id;
+// entity.repo_name = repo_name;
entity.related_account = account.getSignature();
entity.created_at = now;
entity.modified_at = now;
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/ContextModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/ContextModel.java
new file mode 100644
index 000000000..cce811099
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/ContextModel.java
@@ -0,0 +1,13 @@
+package com.seafile.seadroid2.framework.data.model;
+
+public class ContextModel {
+ public String repo_id;
+ public String repo_name; //repo_name
+
+ public String type; //repo/dirent
+
+ /**
+ * parent_dir + name
+ */
+ public String full_path;
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java
index 0b63f210d..13a9549dd 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java
@@ -4,23 +4,23 @@
public class FileProfileConfigModel {
public UserWrapperModel users;
- public MetadataConfigModel metadata;
public FileDetailModel detail;
+ public MetadataConfigModel metadataConfigModel;
- public UserWrapperModel getUsers() {
- return users;
+ public MetadataConfigModel getMetadataConfigModel() {
+ return metadataConfigModel;
}
- public void setUsers(UserWrapperModel users) {
- this.users = users;
+ public void setMetadataConfigModel(MetadataConfigModel metadataConfigModel) {
+ this.metadataConfigModel = metadataConfigModel;
}
- public MetadataConfigModel getMetadata() {
- return metadata;
+ public UserWrapperModel getUsers() {
+ return users;
}
- public void setMetadata(MetadataConfigModel metadata) {
- this.metadata = metadata;
+ public void setUsers(UserWrapperModel users) {
+ this.users = users;
}
public FileDetailModel getDetail() {
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/MetadataConfigModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/MetadataConfigModel.java
index 78fbf7894..74fe5d623 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/MetadataConfigModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/MetadataConfigModel.java
@@ -2,4 +2,8 @@
public class MetadataConfigModel {
public boolean enabled;
+ //public boolean tags_enabled;
+ //public String tags_lang;
+ //public String details_settings;
+ //public boolean ocr_enabled;
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocPageOptionsModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocPageOptionsModel.java
index 74e1c0119..cdb715378 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocPageOptionsModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocPageOptionsModel.java
@@ -13,6 +13,8 @@ public class SDocPageOptionsModel implements Parcelable {
public boolean isLocked;
public boolean isStarred;
+ public boolean enableMetadataManagement;
+
@Override
public String toString() {
return "SDocPageOptionsModel{" +
@@ -42,6 +44,7 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.repoName);
dest.writeByte(this.isLocked ? (byte) 1 : (byte) 0);
dest.writeByte(this.isStarred ? (byte) 1 : (byte) 0);
+ dest.writeByte(this.enableMetadataManagement ? (byte) 1 : (byte) 0);
}
public SDocPageOptionsModel() {
@@ -56,6 +59,7 @@ protected SDocPageOptionsModel(Parcel in) {
this.repoName = in.readString();
this.isLocked = in.readByte() != 0;
this.isStarred = in.readByte() != 0;
+ this.enableMetadataManagement = in.readByte() != 0;
}
public static final Creator CREATOR = new Creator() {
@@ -69,180 +73,4 @@ public SDocPageOptionsModel[] newArray(int size) {
return new SDocPageOptionsModel[size];
}
};
-}
-
-//
-//
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataStoreKeys.java b/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataStoreKeys.java
index 243f74ebf..35871b1be 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataStoreKeys.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataStoreKeys.java
@@ -36,4 +36,6 @@ public class DataStoreKeys {
public static final String KEY_DARK_MODE = "key_dark_mode";
public static final String KEY_SERVER_CERT_INFO = "key_server_cert_info";
+
+ public static final String KEY_NAV_CONTEXT_STACK = "key_nav_context_stack";
}
\ No newline at end of file
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java b/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java
index 18a4d3b0f..ebf7543f9 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java
@@ -294,6 +294,7 @@ public void onStop(FileAlterationObserver observer) {
public void onDestroy() {
super.onDestroy();
+ SLogs.e("file monitor service destroy");
stopFolderMonitor();
//
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/util/GlideCache.java b/app/src/main/java/com/seafile/seadroid2/framework/util/GlideCache.java
index f69075797..e18e22d25 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/util/GlideCache.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/util/GlideCache.java
@@ -45,8 +45,7 @@ public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder
File[] externalMediaDirs = SeadroidApplication.getAppContext().getExternalMediaDirs();
String rootPath = externalMediaDirs[0].getAbsolutePath();
File dirPath = new File(rootPath + "/GlideCache/");
- builder.setDiskCache(new DiskLruCacheFactory(dirPath.getAbsolutePath(), 1024 * 1024 * 100));
- GlideApp.tearDown();
+ builder.setDiskCache(new DiskLruCacheFactory(dirPath.getAbsolutePath(), 1024 * 1024 * 500));
}
@Override
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/util/ThumbnailUtils.java b/app/src/main/java/com/seafile/seadroid2/framework/util/ThumbnailUtils.java
new file mode 100644
index 000000000..28218c789
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/util/ThumbnailUtils.java
@@ -0,0 +1,11 @@
+package com.seafile.seadroid2.framework.util;
+
+import com.blankj.utilcode.util.EncodeUtils;
+
+public class ThumbnailUtils {
+
+ public static String convertThumbnailUrl(String serverUrl, String repoId, String fullPath) {
+ String newFilePath = EncodeUtils.urlEncode(fullPath);
+ return String.format("%sapi2/repos/%s/thumbnail/?p=%s&size=%s", serverUrl, repoId, newFilePath, 128);
+ }
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java
index bb5a51740..0bce10fdb 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java
@@ -2,6 +2,7 @@
import android.text.TextUtils;
+import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.ExistingWorkPolicy;
@@ -149,6 +150,7 @@ private OneTimeWorkRequest getMediaUploadRequest() {
return oneTimeRequestBuilder(UploadMediaFileAutomaticallyWorker.class)
.setConstraints(constraints)
+ .setBackoffCriteria(BackoffPolicy.LINEAR, 5, TimeUnit.SECONDS)
.setInitialDelay(1, TimeUnit.SECONDS)
.setId(UploadMediaFileAutomaticallyWorker.UID)
.build();
@@ -204,6 +206,7 @@ private OneTimeWorkRequest getFolderUploadRequest() {
return oneTimeRequestBuilder(UploadFolderFileAutomaticallyWorker.class)
.setConstraints(constraints)
+ .setBackoffCriteria(BackoffPolicy.LINEAR, 5, TimeUnit.SECONDS)
.setInitialDelay(1, TimeUnit.SECONDS)
.setId(UploadFolderFileAutomaticallyWorker.UID)
.build();
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java
index 6adf0e260..a747ff15b 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java
@@ -41,11 +41,16 @@ public class TransferEvent {
/**
* because of an OUT_OF_QUOTA error, the current upload worker was canceled
*/
- public static final String EVENT_CANCEL_OUT_OF_QUOTA = "transfer_cancel_with_out_of_quota";
+ public static final String EVENT_CANCEL_WITH_OUT_OF_QUOTA = "transfer_cancel_with_out_of_quota";
/**
* because of an NETWORK error, the current upload worker was canceled
*/
public static final String EVENT_CANCEL_WITH_NETWORK_ERR = "transfer_cancel_with_network_err";
+ /**
+ * Manual or passive cancellation
+ */
+ public static final String EVENT_CANCEL_WITH_BY_STOPPED = "transfer_cancel_with_stopped";
+
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java
index 976508f3d..b108685fd 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java
@@ -90,7 +90,7 @@ public String isInterrupt(TransferResult result) {
} else if (result == TransferResult.FILE_NOT_FOUND) {
// finishFlagEvent = null;
} else if (result == TransferResult.OUT_OF_QUOTA) {
- finishFlagEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA;
+ finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA;
} else if (result == TransferResult.NETWORK_CONNECTION) {
finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_NETWORK_ERR;
} else if (result == TransferResult.SSL_EXCEPTION) {
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java
index 04662712e..541ab61af 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java
@@ -49,6 +49,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.file.Files;
import java.security.NoSuchAlgorithmException;
@@ -102,7 +103,14 @@ private TransferResult parseTransferException(Exception e) {
return TransferResult.SSL_EXCEPTION;
} else if (e instanceof SocketTimeoutException) {
return TransferResult.NETWORK_CONNECTION;
+ } else if (e instanceof SocketException) {
+// SocketException exception = (SocketException) e;
+// SLogs.e(exception);
+ return TransferResult.USER_CANCELLED;
} else if (e instanceof IOException) {
+ if (TextUtils.equals("Canceled", e.getMessage())) {
+ return TransferResult.USER_CANCELLED;
+ }
return TransferResult.NETWORK_CONNECTION;
}
@@ -140,7 +148,7 @@ public String isInterrupt(TransferResult result) {
} else if (result == TransferResult.FILE_NOT_FOUND) {
// finishFlagEvent = null;
} else if (result == TransferResult.OUT_OF_QUOTA) {
- finishFlagEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA;
+ finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA;
} else if (result == TransferResult.NETWORK_CONNECTION) {
finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_NETWORK_ERR;
} else if (result == TransferResult.SSL_EXCEPTION) {
@@ -151,6 +159,8 @@ public String isInterrupt(TransferResult result) {
finishFlagEvent = TransferEvent.EVENT_FINISH;
} else if (result == TransferResult.UNKNOWN) {
finishFlagEvent = TransferEvent.EVENT_FINISH;
+ } else if (result == TransferResult.USER_CANCELLED) {
+ finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_BY_STOPPED;
}
return finishFlagEvent;
@@ -361,6 +371,11 @@ public void onStopped() {
// cancelNotification();
+ SLogs.e("BaseUploadWorker onStopped");
+ currentTransferEntity.transfer_status = TransferStatus.CANCELLED;
+ currentTransferEntity.transfer_result = TransferResult.USER_CANCELLED;
+ AppDatabase.getInstance().fileTransferDAO().update(currentTransferEntity);
+
if (newCall != null && !newCall.isCanceled()) {
newCall.cancel();
}
@@ -376,59 +391,67 @@ private void notifyProgress(String fileName, int percent) {
showForegroundAsync(f);
}
+ private FileTransferEntity currentTransferEntity;
+
public void transferFile(Account account, FileTransferEntity transferEntity) throws IOException, SeafException, JSONException {
SLogs.d("start transfer, full_path: " + transferEntity.full_path);
+ currentTransferEntity = transferEntity;
List repoModels = AppDatabase.getInstance().repoDao().getByIdSync(transferEntity.repo_id);
if (CollectionUtils.isEmpty(repoModels)) {
- SLogs.d("no repo for repoId: " + transferEntity.repo_id);
+ SLogs.d("no repo for repoId: " + currentTransferEntity.repo_id);
- transferEntity.transfer_status = TransferStatus.FAILED;
- transferEntity.transfer_result = TransferResult.CANCELLED;
- AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
+ currentTransferEntity.transfer_status = TransferStatus.FAILED;
+ currentTransferEntity.transfer_result = TransferResult.CANCELLED;
+ AppDatabase.getInstance().fileTransferDAO().update(currentTransferEntity);
return;
}
//update modified_at field
- transferEntity.modified_at = System.currentTimeMillis();
- AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
- notifyProgress(transferEntity.file_name, 0);
- SLogs.d("start transfer, target_path: " + transferEntity.target_path);
+ currentTransferEntity.modified_at = System.currentTimeMillis();
+ AppDatabase.getInstance().fileTransferDAO().update(currentTransferEntity);
+//
+ //show notification
+ notifyProgress(currentTransferEntity.file_name, 0);
+ SLogs.d("start transfer, target_path: " + currentTransferEntity.target_path);
RepoModel repo = repoModels.get(0);
- if (repo.canLocalDecrypt()) {
- uploadBlockFile(account, repo, transferEntity);
- } else {
- uploadFile(account, repo, transferEntity);
- }
+ uploadFile(account, repo);
+
+// RepoModel repo = repoModels.get(0);
+// if (repo.canLocalDecrypt()) {
+// uploadBlockFile(account, repo, transferEntity);
+// } else {
+// uploadFile(account, repo, transferEntity);
+// }
}
/**
* upload file
*/
- private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity transferEntity) throws IOException, SeafException {
+ private void uploadFile(Account account, RepoModel repoModel) throws IOException, SeafException {
if (isStopped()) {
return;
}
- File file = new File(transferEntity.full_path);
+ File file = new File(currentTransferEntity.full_path);
if (!file.exists()) {
throw SeafException.notFoundException;
}
- ExistingFileStrategy fileStrategy = transferEntity.file_strategy;
+ ExistingFileStrategy fileStrategy = currentTransferEntity.file_strategy;
if (fileStrategy == ExistingFileStrategy.AUTO) {
- fileStrategy = checkRemoteFileExists(account, repoModel, transferEntity);
+ fileStrategy = checkRemoteFileExists(account, repoModel, currentTransferEntity);
}
if (fileStrategy == ExistingFileStrategy.SKIP) {
- SLogs.d("folder backup: skip file(remote exists): " + transferEntity.target_path);
+ SLogs.d("folder backup: skip file(remote exists): " + currentTransferEntity.target_path);
- transferEntity.transfer_status = TransferStatus.SUCCEEDED;
- transferEntity.transfer_result = TransferResult.TRANSMITTED;
- AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
+ currentTransferEntity.transfer_status = TransferStatus.SUCCEEDED;
+ currentTransferEntity.transfer_result = TransferResult.TRANSMITTED;
+ AppDatabase.getInstance().fileTransferDAO().update(currentTransferEntity);
return;
}
@@ -437,8 +460,8 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
- if (transferEntity.file_strategy == ExistingFileStrategy.REPLACE) {
- builder.addFormDataPart("target_file", transferEntity.target_path);
+ if (currentTransferEntity.file_strategy == ExistingFileStrategy.REPLACE) {
+ builder.addFormDataPart("target_file", currentTransferEntity.target_path);
} else {
//parent_dir: / is repo root
builder.addFormDataPart("parent_dir", "/");
@@ -446,7 +469,7 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
// parent_dir is the root directory.
// when select the root of the repo, relative_path is null.
- String dir = transferEntity.getParent_path();
+ String dir = currentTransferEntity.getParent_path();
dir = StringUtils.removeStart(dir, "/");
//
builder.addFormDataPart("relative_path", dir);
@@ -454,11 +477,11 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
//
- fileTransferProgressListener.setFileTransferEntity(transferEntity);
+ fileTransferProgressListener.setFileTransferEntity(currentTransferEntity);
//db
- transferEntity.transfer_status = TransferStatus.IN_PROGRESS;
- AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
+ currentTransferEntity.transfer_status = TransferStatus.IN_PROGRESS;
+ AppDatabase.getInstance().fileTransferDAO().update(currentTransferEntity);
ProgressRequestBody progressRequestBody = new ProgressRequestBody(file, fileTransferProgressListener);
@@ -467,7 +490,7 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
RequestBody requestBody = builder.build();
//get upload link
- String uploadUrl = getFileUploadUrl(transferEntity.repo_id, transferEntity.getParent_path(), transferEntity.file_strategy == ExistingFileStrategy.REPLACE);
+ String uploadUrl = getFileUploadUrl(currentTransferEntity.repo_id, currentTransferEntity.getParent_path(), currentTransferEntity.file_strategy == ExistingFileStrategy.REPLACE);
if (TextUtils.isEmpty(uploadUrl)) {
throw SeafException.networkException;
}
@@ -507,7 +530,7 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
String fileId = str.replace("\"", "");
SLogs.d("result,file ID:" + str);
- updateSuccess(transferEntity, fileId, file);
+ updateSuccess(fileId, file);
} catch (Exception e) {
throw e;
}
@@ -744,37 +767,35 @@ private void commitUpload(String link, List blkIds, FileTransferEntity t
String fileId = response.body().string();
- updateSuccess(transferEntity, fileId, file);
+ updateSuccess(fileId, file);
} catch (Exception e) {
throw e;
}
}
- private void updateSuccess(FileTransferEntity transferEntity, String fileId, File file) {
+ private void updateSuccess(String fileId, File file) {
//db
- transferEntity.file_id = fileId;
- transferEntity.transferred_size = file.length();
- transferEntity.action_end_at = System.currentTimeMillis();
- transferEntity.modified_at = transferEntity.action_end_at;
- transferEntity.file_original_modified_at = file.lastModified();
- transferEntity.transfer_result = TransferResult.TRANSMITTED;
- transferEntity.transfer_status = TransferStatus.SUCCEEDED;
+ currentTransferEntity.file_id = fileId;
+ currentTransferEntity.transferred_size = file.length();
+ currentTransferEntity.action_end_at = System.currentTimeMillis();
+ currentTransferEntity.modified_at = currentTransferEntity.action_end_at;
+ currentTransferEntity.file_original_modified_at = file.lastModified();
+ currentTransferEntity.transfer_result = TransferResult.TRANSMITTED;
+ currentTransferEntity.transfer_status = TransferStatus.SUCCEEDED;
- AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
+ AppDatabase.getInstance().fileTransferDAO().update(currentTransferEntity);
//update
- List direntList = AppDatabase.getInstance().direntDao().getListByFullPathSync(transferEntity.repo_id, transferEntity.full_path);
+ List direntList = AppDatabase.getInstance().direntDao().getListByFullPathSync(currentTransferEntity.repo_id, currentTransferEntity.full_path);
if (!CollectionUtils.isEmpty(direntList)) {
DirentModel direntModel = direntList.get(0);
- direntModel.last_modified_at = transferEntity.modified_at;
+ direntModel.last_modified_at = currentTransferEntity.modified_at;
direntModel.id = fileId;
- direntModel.size = transferEntity.file_size;
- direntModel.transfer_status = transferEntity.transfer_status;
+ direntModel.size = currentTransferEntity.file_size;
+ direntModel.transfer_status = currentTransferEntity.transfer_status;
AppDatabase.getInstance().direntDao().update(direntModel);
}
-
-
}
private final int BUFFER_SIZE = 2 * 1024 * 1024;
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java
index 576941ec5..9c8850697 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java
@@ -126,8 +126,8 @@ private Data getOutData() {
}
private boolean checkCanScan() {
- boolean isOpenBackup = FolderBackupSharePreferenceHelper.readBackupSwitch();
- if (!isOpenBackup) {
+ boolean isTurnOn = FolderBackupSharePreferenceHelper.readBackupSwitch();
+ if (!isTurnOn) {
return false;
}
@@ -212,7 +212,7 @@ private void compareToLocalAndInsert(Account account, RepoModel repoModel, Strin
List tList = CollectionUtils.newArrayList();
for (File file : subFiles) {
- FileTransferEntity fEntity = FileTransferEntity.convert2ThisForUploadFileSyncWorker(account, repoModel, file, backupPath);
+ FileTransferEntity fEntity = FileTransferEntity.convert2ThisForUploadFileSyncWorker(account, file, backupPath);
if (fEntity != null) {
tList.add(fEntity);
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java
index a54daf2a8..6f0224a1d 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java
@@ -97,7 +97,6 @@ public Result doWork() {
return Result.success(getOutData());
}
- //todo
String title = getApplicationContext().getString(R.string.settings_camera_upload_info_title);
String subTitle = getApplicationContext().getString(R.string.is_scanning);
@@ -517,7 +516,7 @@ private void checkAndInsert(String parent, List> fi
String parentPath = Utils.pathJoin(parent, "/");
- FileTransferEntity fileTransferEntity = FileTransferEntity.convert2ThisForUploadMediaSyncWorker(account, repoConfig.getRepoID(), repoConfig.getRepoName(), file, parentPath, absPathPair.getThird(), isRemoteExists);
+ FileTransferEntity fileTransferEntity = FileTransferEntity.convert2ThisForUploadMediaSyncWorker(account, file, parentPath, absPathPair.getThird(), isRemoteExists);
transferList.add(fileTransferEntity);
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java
index 6333bf534..4eaebe57e 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java
@@ -98,7 +98,7 @@ private ListenableWorker.Result start() {
getGeneralNotificationHelper().showErrorNotification(R.string.above_quota, R.string.settings_folder_backup_info_title);
AppDatabase.getInstance().fileTransferDAO().cancelWithFileBackup(TransferResult.OUT_OF_QUOTA);
- finishFlagEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA;
+ finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA;
break;
}
} catch (Exception e) {
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java
index 174e2813f..2af843848 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java
@@ -27,6 +27,7 @@
import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl;
import com.seafile.seadroid2.framework.worker.TransferEvent;
import com.seafile.seadroid2.framework.worker.TransferWorker;
+import com.seafile.seadroid2.ui.folder_backup.RepoConfig;
import java.util.List;
import java.util.UUID;
@@ -65,36 +66,46 @@ public void onStopped() {
super.onStopped();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- SLogs.e("文件夹备份已停止:" + getStopReason());
+ SLogs.e("Folder backup stopped, reason:" + getStopReason());
}
}
+ private boolean isFirstShow = true;
+ private void startShowNotification(){
+ if (!isFirstShow) {
+ return;
+ }
+
+ isFirstShow = false;
+ ForegroundInfo foregroundInfo = notificationManager.getForegroundNotification();
+ showForegroundAsync(foregroundInfo);
+
+
+ sendEvent(TransferEvent.EVENT_TRANSFERRING, TransferDataSource.FILE_BACKUP);
+ }
+
private Result start() {
// notificationManager.cancel();
+ SLogs.d("start upload file worker");
Account account = SupportAccountManager.getInstance().getCurrentAccount();
if (account == null) {
return Result.success();
}
- boolean isEnable = FolderBackupSharePreferenceHelper.readBackupSwitch();
- if (!isEnable) {
+ boolean canExec = can();
+ if (!canExec) {
return Result.success();
}
- boolean isUploaded = false;
-
-
- ForegroundInfo foregroundInfo = notificationManager.getForegroundNotification();
- showForegroundAsync(foregroundInfo);
+ if (repoConfig == null) {
+ return Result.success();
+ }
-// notificationManager.showNotification();
+ boolean isUploaded = false;
String finishFlagEvent = null;
- SLogs.d("start upload file worker");
- sendEvent(TransferEvent.EVENT_TRANSFERRING, TransferDataSource.FILE_BACKUP);
-
while (true) {
if (isStopped()) {
break;
@@ -113,9 +124,14 @@ private Result start() {
break;
}
- FileTransferEntity transferEntity = transferList.get(0);
+ startShowNotification();
+
isUploaded = true;
+ FileTransferEntity transferEntity = transferList.get(0);
+ transferEntity.repo_id = repoConfig.getRepoID();
+ transferEntity.repo_name = repoConfig.getRepoName();
+
try {
transferFile(account, transferEntity);
@@ -126,15 +142,19 @@ private Result start() {
TransferResult transferResult = onException(transferEntity, e);
- notifyError(transferResult);
+ if (!isStopped()) {
+
+ notifyError(transferResult);
- sendTransferEvent(transferEntity, false);
+ sendTransferEvent(transferEntity, false);
+ }
String finishFlag = isInterrupt(transferResult);
if (!TextUtils.isEmpty(finishFlag)) {
finishFlagEvent = finishFlag;
break;
}
+
}
}
@@ -170,4 +190,25 @@ private Result start() {
return Result.success(outputData);
}
+ private RepoConfig repoConfig;
+
+ private boolean can() {
+ boolean isTurnOn = FolderBackupSharePreferenceHelper.readBackupSwitch();
+ if (!isTurnOn) {
+ return false;
+ }
+
+ List backupPaths = FolderBackupSharePreferenceHelper.readBackupPathsAsList();
+ if (CollectionUtils.isEmpty(backupPaths)) {
+ return false;
+ }
+
+ repoConfig = FolderBackupSharePreferenceHelper.readRepoConfig();
+ if (repoConfig == null) {
+ return false;
+ }
+
+ return true;
+ }
+
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java
index dd568ac18..9a6c6f590 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java
@@ -22,12 +22,14 @@
import com.seafile.seadroid2.enums.TransferDataSource;
import com.seafile.seadroid2.enums.TransferResult;
import com.seafile.seadroid2.framework.datastore.sp_livedata.AlbumBackupSharePreferenceHelper;
+import com.seafile.seadroid2.framework.datastore.sp_livedata.FolderBackupSharePreferenceHelper;
import com.seafile.seadroid2.framework.notification.AlbumBackupNotificationHelper;
import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl;
import com.seafile.seadroid2.framework.worker.TransferEvent;
import com.seafile.seadroid2.framework.worker.TransferWorker;
+import com.seafile.seadroid2.ui.folder_backup.RepoConfig;
import java.util.List;
import java.util.UUID;
@@ -54,9 +56,24 @@ public BaseTransferNotificationHelper getNotification() {
return albumNotificationHelper;
}
+ boolean isFirstShow = true;
+ private void startShowNotification(){
+ if (!isFirstShow) {
+ return;
+ }
+
+ //send start transfer event
+ sendEvent(TransferEvent.EVENT_TRANSFERRING, TransferDataSource.ALBUM_BACKUP);
+
+ // show foreground notification
+ ForegroundInfo foregroundInfo = albumNotificationHelper.getForegroundNotification();
+ showForegroundAsync(foregroundInfo);
+ }
+
@NonNull
@Override
public ListenableWorker.Result doWork() {
+ SLogs.d("start upload media worker");
Account account = SupportAccountManager.getInstance().getCurrentAccount();
if (account == null) {
@@ -66,17 +83,14 @@ public ListenableWorker.Result doWork() {
return ListenableWorker.Result.success();
}
- boolean isEnable = AlbumBackupSharePreferenceHelper.readBackupSwitch();
- if (!isEnable) {
- return ListenableWorker.Result.success();
+ boolean canExec = can();
+ if (!canExec) {
+ return Result.success();
}
- //send start transfer event
- sendEvent(TransferEvent.EVENT_TRANSFERRING, TransferDataSource.ALBUM_BACKUP);
-
- // show foreground notification
- ForegroundInfo foregroundInfo = albumNotificationHelper.getForegroundNotification();
- showForegroundAsync(foregroundInfo);
+ if (repoConfig == null) {
+ return Result.success();
+ }
//
String finishFlagEvent = null;
@@ -86,8 +100,6 @@ public ListenableWorker.Result doWork() {
break;
}
- SLogs.d("start upload media worker");
-
List transferList = AppDatabase
.getInstance()
.fileTransferDAO()
@@ -99,11 +111,15 @@ public ListenableWorker.Result doWork() {
break;
}
- FileTransferEntity transferEntity = transferList.get(0);
+ startShowNotification();
isUploaded = true;
- try {
+ FileTransferEntity transferEntity = transferList.get(0);
+ transferEntity.repo_id = repoConfig.getRepoID();
+ transferEntity.repo_name = repoConfig.getRepoName();
+
+ try {
transferFile(account, transferEntity);
sendTransferEvent(transferEntity, true);
@@ -113,9 +129,11 @@ public ListenableWorker.Result doWork() {
TransferResult transferResult = onException(transferEntity, e);
- notifyError(transferResult);
+ if (!isStopped()) {
+ notifyError(transferResult);
- sendTransferEvent(transferEntity, false);
+ sendTransferEvent(transferEntity, false);
+ }
String finishFlag = isInterrupt(transferResult);
if (!TextUtils.isEmpty(finishFlag)) {
@@ -156,4 +174,20 @@ public ListenableWorker.Result doWork() {
.build();
return Result.success(outputData);
}
+
+ private RepoConfig repoConfig;
+
+ private boolean can() {
+ boolean isTurnOn = AlbumBackupSharePreferenceHelper.readBackupSwitch();
+ if (!isTurnOn) {
+ return false;
+ }
+
+ repoConfig = AlbumBackupSharePreferenceHelper.readRepoConfig();
+ if (repoConfig == null) {
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/app/src/main/java/com/seafile/seadroid2/listener/FileTransferProgressListener.java b/app/src/main/java/com/seafile/seadroid2/listener/FileTransferProgressListener.java
index 67ea45d50..426afc6cd 100644
--- a/app/src/main/java/com/seafile/seadroid2/listener/FileTransferProgressListener.java
+++ b/app/src/main/java/com/seafile/seadroid2/listener/FileTransferProgressListener.java
@@ -43,10 +43,26 @@ public void onProgressNotify(long cur, long total) {
fileTransferEntity.transferred_size = cur;
- int percent = (int) ((float) cur / (float) total * 100);
+ int percent = calcu(cur, total);
progressListener.onProgressNotify(fileTransferEntity, percent, cur, total);
}
+ public int onProgress(long cur, long total) {
+
+ long nowt = System.currentTimeMillis();
+ if (nowt - temp < 1000) {
+ return -1;
+ }
+
+ temp = nowt;
+ return calcu(cur, total);
+ }
+
+ public int calcu(long cur, long total) {
+ int percent = (int) ((float) cur / (float) total * 100);
+ return percent;
+ }
+
public interface TransferProgressListener {
void onProgressNotify(FileTransferEntity fileTransferEntity, int percent, long transferredSize, long totalSize);
}
diff --git a/app/src/main/java/com/seafile/seadroid2/preferences/ContextStackPreferenceHelper.java b/app/src/main/java/com/seafile/seadroid2/preferences/ContextStackPreferenceHelper.java
new file mode 100644
index 000000000..ae26f1a30
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/preferences/ContextStackPreferenceHelper.java
@@ -0,0 +1,35 @@
+package com.seafile.seadroid2.preferences;
+
+import com.blankj.utilcode.util.GsonUtils;
+import com.google.gson.reflect.TypeToken;
+import com.seafile.seadroid2.framework.data.model.ContextModel;
+import com.seafile.seadroid2.framework.datastore.DataStoreKeys;
+
+import java.lang.reflect.Type;
+import java.util.Stack;
+
+public class ContextStackPreferenceHelper {
+ private static final String STACK_KEY = DataStoreKeys.KEY_NAV_CONTEXT_STACK;
+
+ // 保存 Stack 到 SharedPreferences
+ public static void saveStack(Stack stack) {
+ String json = GsonUtils.toJson(stack); // 将 Stack 转换为 JSON 字符串
+ Settings.getCommonPreferences().edit().putString(STACK_KEY, json).apply();
+ }
+
+ public static void clearStack() {
+ Settings.getCommonPreferences().edit().remove(STACK_KEY).apply();
+ }
+
+ // 从 SharedPreferences 中获取 Stack
+ public static Stack getStack() {
+ String json = Settings.getCommonPreferences().getString(STACK_KEY, null);
+ if (json == null) {
+ return new Stack<>(); // 返回空栈
+ }
+
+ Type type = new TypeToken>() {
+ }.getType();
+ return GsonUtils.fromJson(json, type); // 从 JSON 恢复 Stack
+ }
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/CameraUploadManager.java b/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/CameraUploadManager.java
index eef46c498..7b049fabe 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/CameraUploadManager.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/CameraUploadManager.java
@@ -8,6 +8,7 @@
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
import com.seafile.seadroid2.framework.util.SLogs;
+import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl;
import java.util.List;
@@ -122,6 +123,8 @@ public void disableCameraUpload() {
ContentResolver.cancelSync(account.getAndroidAccount(), AUTHORITY);
ContentResolver.setIsSyncable(account.getAndroidAccount(), AUTHORITY, 0);
}
+
+ BackgroundJobManagerImpl.getInstance().cancelAllMediaWorker();
}
/**
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewModel.java
similarity index 68%
rename from app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentViewModel.java
rename to app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewModel.java
index 960c0a30f..aa5893611 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewModel.java
@@ -1,4 +1,4 @@
-package com.seafile.seadroid2.ui.sdoc;
+package com.seafile.seadroid2.ui.docs_comment;
import android.content.ContentResolver;
import android.net.Uri;
@@ -8,7 +8,6 @@
import com.blankj.utilcode.util.CloneUtils;
import com.blankj.utilcode.util.CollectionUtils;
-import com.blankj.utilcode.util.RegexUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
@@ -31,6 +30,7 @@
import com.seafile.seadroid2.framework.util.StringUtils;
import com.seafile.seadroid2.framework.util.Utils;
import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
+import com.seafile.seadroid2.ui.sdoc.DocsCommentService;
import com.seafile.seadroid2.view.rich_edittext.RichEditText;
import java.util.Comparator;
@@ -53,166 +53,17 @@
public class DocsCommentViewModel extends BaseViewModel {
- private final MutableLiveData _fileProfileConfigLiveData = new MutableLiveData<>();
- private final MutableLiveData _fileRecordLiveData = new MutableLiveData<>();
private final MutableLiveData _fileCommentLiveData = new MutableLiveData<>();
- private final MutableLiveData> _sdocElementListLiveData = new MutableLiveData<>();
private final MutableLiveData _postCommentLiveData = new MutableLiveData<>();
public MutableLiveData getPostCommentLiveData() {
return _postCommentLiveData;
}
- public MutableLiveData getFileDetailLiveData() {
- return _fileProfileConfigLiveData;
- }
-
- public MutableLiveData getSdocRecordLiveData() {
- return _fileRecordLiveData;
- }
-
public MutableLiveData getSdocCommentLiveData() {
return _fileCommentLiveData;
}
- public MutableLiveData> getSdocElementLiveData() {
- return _sdocElementListLiveData;
- }
-
- public void loadFileConfig(String repoId, String path) {
- Single userSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getRelatedUsers(repoId);
- Single metadataSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getMetadata(repoId);
- Single detailSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getFileDetail(repoId, path);
-
- Single s = Single.zip(detailSingle, userSingle, metadataSingle, new Function3() {
- @Override
- public FileProfileConfigModel apply(FileDetailModel docDetailModel, UserWrapperModel userWrapperModel, MetadataConfigModel metadataConfigModel) throws Exception {
- FileProfileConfigModel configModel = new FileProfileConfigModel();
- configModel.setDetail(docDetailModel);
- configModel.setUsers(userWrapperModel);
- configModel.setMetadata(metadataConfigModel);
- return configModel;
- }
- });
-
- addSingleDisposable(s, new Consumer() {
- @Override
- public void accept(FileProfileConfigModel fileProfileConfigModel) throws Exception {
- getFileDetailLiveData().setValue(fileProfileConfigModel);
- }
- });
- }
-
- public void loadRecords(String repoId, String path) {
- if (TextUtils.isEmpty(path) || TextUtils.equals("/", path)) {
- return;
- }
-
- String parent_dir;
- String name;
-
- // 1. /a/b/c/t.txt
- // 2. /a/t.txt
- // 3. /t.txt
- // 4. t.txt
- // 5. /
- if (path.contains("/")) {
- parent_dir = path.substring(0, path.lastIndexOf("/"));
- name = path.substring(path.lastIndexOf("/") + 1);
- } else {
- parent_dir = null;
- name = path;
- }
-
- if (TextUtils.isEmpty(parent_dir)) {
- parent_dir = "/";
- }
-
- Single single = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getRecords(repoId, parent_dir, name);
- addSingleDisposable(single, new Consumer() {
- @Override
- public void accept(FileRecordWrapperModel fileRecordWrapperModel) throws Exception {
- getSdocRecordLiveData().setValue(fileRecordWrapperModel);
- }
- });
- }
-
- public static final List _AllowedElementTypes = List.of("header1", "header2", "header3");
-
- public void loadSdocElements(SDocPageOptionsModel pageOptionsModel) {
- if (TextUtils.isEmpty(pageOptionsModel.seadocServerUrl)) {
- return;
- }
- getRefreshLiveData().setValue(true);
-
- String sdocServerUrl = pageOptionsModel.seadocServerUrl;
- if (!sdocServerUrl.endsWith("/")) {
- sdocServerUrl = sdocServerUrl + "/";
- }
-
- Account curAccount = SupportAccountManager.getInstance().getCurrentAccount();
- Account partialAccount = CloneUtils.deepClone(curAccount, Account.class);
- partialAccount.setToken(pageOptionsModel.seadocAccessToken);
- partialAccount.setServer(sdocServerUrl);
-
- Single single = HttpIO.getInstanceByAccount(partialAccount).execute(DocsCommentService.class).getElements(pageOptionsModel.docUuid);
- addSingleDisposable(single, new Consumer() {
- @Override
- public void accept(SDocOutlineWrapperModel wrapperModel) throws Exception {
-
- if (wrapperModel == null || wrapperModel.elements == null) {
- getSdocElementLiveData().setValue(null);
- return;
- }
-
- List newList = wrapperModel.elements.stream().filter(new Predicate() {
- @Override
- public boolean test(OutlineItemModel sDocModel) {
- if (!_AllowedElementTypes.contains(sDocModel.type)) {
- return false;
- }
-
- if (TextUtils.isEmpty(sDocModel.text) && CollectionUtils.isEmpty(sDocModel.children)) {
- return false;
- }
-
- return true;
- }
- }).map(new Function() {
- @Override
- public OutlineItemModel apply(OutlineItemModel sDocModel) {
- if (!TextUtils.isEmpty(sDocModel.text)) {
- return sDocModel;
- }
-
- if (CollectionUtils.isEmpty(sDocModel.children)) {
- return sDocModel;
- }
-
- String text = "";
- for (OutlineItemModel child : sDocModel.children) {
- if (!TextUtils.isEmpty(child.text)) {
- String nt = StringUtils.trim(child.text, "\n").trim();
- text = text.concat(nt);
- }
- }
- sDocModel.text = text;
- return sDocModel;
- }
- }).collect(Collectors.toList());
-
- getSdocElementLiveData().setValue(newList);
- getRefreshLiveData().setValue(false);
- }
- }, new Consumer() {
- @Override
- public void accept(Throwable throwable) throws Exception {
- SLogs.e(throwable);
- getRefreshLiveData().setValue(false);
- }
- });
- }
-
public void loadDocComments(SDocPageOptionsModel pageOptionsModel) {
if (TextUtils.isEmpty(pageOptionsModel.seadocServerUrl)) {
return;
@@ -374,7 +225,7 @@ private List getImageMdResult(String s) {
return models;
}
- public void markResolve(String sdocServerUrl,String token, String sdocUid, long commentId, Consumer consumer) {
+ public void markResolve(String sdocServerUrl, String token, String sdocUid, long commentId, Consumer consumer) {
getRefreshLiveData().setValue(true);
if (!sdocServerUrl.endsWith("/")) {
@@ -406,7 +257,7 @@ public void accept(Throwable throwable) {
});
}
- public void delete(String sdocServerUrl,String token, String sdocUid, long commentId, Consumer consumer) {
+ public void delete(String sdocServerUrl, String token, String sdocUid, long commentId, Consumer consumer) {
getRefreshLiveData().setValue(true);
if (!sdocServerUrl.endsWith("/")) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentsActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentsActivity.java
index 1df2df0b9..85739856c 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentsActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentsActivity.java
@@ -1,6 +1,5 @@
package com.seafile.seadroid2.ui.docs_comment;
-import android.animation.ValueAnimator;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -11,15 +10,12 @@
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
-import android.view.animation.Animation;
-import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.KeyboardUtils;
@@ -28,8 +24,6 @@
import com.chad.library.adapter4.QuickAdapterHelper;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.seafile.seadroid2.R;
-import com.seafile.seadroid2.account.Account;
-import com.seafile.seadroid2.account.SupportAccountManager;
import com.seafile.seadroid2.databinding.ActivityDocCommentBinding;
import com.seafile.seadroid2.databinding.ToolbarActionbarBinding;
import com.seafile.seadroid2.framework.data.model.docs_comment.DocsCommentModel;
@@ -37,10 +31,6 @@
import com.seafile.seadroid2.framework.data.model.sdoc.SDocPageOptionsModel;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.ui.base.BaseMediaSelectorActivity;
-import com.seafile.seadroid2.ui.bottomsheetmenu.BottomSheetHelper;
-import com.seafile.seadroid2.ui.bottomsheetmenu.BottomSheetMenuFragment;
-import com.seafile.seadroid2.ui.bottomsheetmenu.OnMenuClickListener;
-import com.seafile.seadroid2.ui.sdoc.DocsCommentViewModel;
import com.seafile.seadroid2.view.rich_edittext.RichEditText;
import java.util.List;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java
index 8703ecb37..fba8aabb6 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java
@@ -57,6 +57,7 @@
import com.seafile.seadroid2.framework.data.model.dirents.DirentFileModel;
import com.seafile.seadroid2.framework.file_monitor.FileSyncService;
import com.seafile.seadroid2.framework.helper.NightModeHelper;
+import com.seafile.seadroid2.framework.util.GlideApp;
import com.seafile.seadroid2.framework.util.PermissionUtil;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.util.TakeCameras;
@@ -505,7 +506,7 @@ private void refreshToolbarTitle() {
private void bindService() {
Intent syncIntent = new Intent(this, FileSyncService.class);
bindService(syncIntent, syncConnection, Context.BIND_AUTO_CREATE);
- startService(syncIntent);
+// startService(syncIntent); //It doesn't need to run in the background
}
private final ServiceConnection syncConnection = new ServiceConnection() {
@@ -1208,7 +1209,7 @@ private void doSelectedMultiFile(List uriList) {
mainViewModel.checkLocalDirent(curAccount, this, repoModel, parent_dir, uriList, new Consumer>() {
@Override
- public void accept(List newUris) throws Exception {
+ public void accept(List newUris) {
dismissProgressDialog();
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/main/MainViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/main/MainViewModel.java
index 691070670..e1692f1b4 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/main/MainViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/main/MainViewModel.java
@@ -28,6 +28,7 @@
import com.seafile.seadroid2.framework.datastore.DataManager;
import com.seafile.seadroid2.framework.util.Utils;
import com.seafile.seadroid2.framework.worker.ExistingFileStrategy;
+import com.seafile.seadroid2.preferences.Settings;
import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
import com.seafile.seadroid2.context.NavContext;
import com.seafile.seadroid2.framework.data.ServerInfo;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/PhotoViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/media/PhotoViewModel.java
new file mode 100644
index 000000000..48a5fed35
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/PhotoViewModel.java
@@ -0,0 +1,259 @@
+package com.seafile.seadroid2.ui.media;
+
+import android.text.TextUtils;
+
+import androidx.lifecycle.MutableLiveData;
+
+import com.blankj.utilcode.util.CollectionUtils;
+import com.blankj.utilcode.util.FileUtils;
+import com.seafile.seadroid2.SeafException;
+import com.seafile.seadroid2.account.Account;
+import com.seafile.seadroid2.account.SupportAccountManager;
+import com.seafile.seadroid2.enums.TransferAction;
+import com.seafile.seadroid2.enums.TransferResult;
+import com.seafile.seadroid2.enums.TransferStatus;
+import com.seafile.seadroid2.framework.data.db.AppDatabase;
+import com.seafile.seadroid2.framework.data.db.entities.DirentModel;
+import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity;
+import com.seafile.seadroid2.framework.datastore.DataManager;
+import com.seafile.seadroid2.framework.http.HttpIO;
+import com.seafile.seadroid2.framework.util.SLogs;
+import com.seafile.seadroid2.framework.worker.ExistingFileStrategy;
+import com.seafile.seadroid2.listener.FileTransferProgressListener;
+import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
+import com.seafile.seadroid2.ui.file.FileService;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.file.Path;
+import java.util.List;
+
+import io.reactivex.Single;
+import io.reactivex.SingleEmitter;
+import io.reactivex.SingleOnSubscribe;
+import io.reactivex.SingleSource;
+import io.reactivex.functions.BiFunction;
+import io.reactivex.functions.Consumer;
+import io.reactivex.functions.Function;
+import kotlin.Pair;
+import okhttp3.Call;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+public class PhotoViewModel extends BaseViewModel {
+ private final MutableLiveData _downloadedUrlLiveData = new MutableLiveData<>();
+ private final MutableLiveData _originalUrlLiveData = new MutableLiveData<>();
+
+ private final MutableLiveData> _checkLocalLiveData = new MutableLiveData<>();
+
+ public MutableLiveData getDownloadedPathLiveData() {
+ return _downloadedUrlLiveData;
+ }
+
+ public MutableLiveData getOriginalUrlLiveData() {
+ return _originalUrlLiveData;
+ }
+
+ public MutableLiveData> getCheckLocalLiveData() {
+ return _checkLocalLiveData;
+ }
+
+ public void checkLocal(String repoId, String fullPath) {
+ Single> direntSingle = AppDatabase.getInstance().direntDao().getListByFullPathAsync(repoId, fullPath);
+ Single> transferSingle = AppDatabase.getInstance().fileTransferDAO().getListByFullPathAsync(repoId, TransferAction.DOWNLOAD, fullPath);
+ Single> rSingle = Single.zip(direntSingle, transferSingle, new BiFunction, List, Pair>() {
+ @Override
+ public Pair apply(List direntModels, List fileTransferEntities) throws Exception {
+ if (CollectionUtils.isEmpty(direntModels)) {
+ return null;
+ }
+
+ if (CollectionUtils.isEmpty(fileTransferEntities)) {
+ return new Pair<>(direntModels.get(0), null);
+ }
+
+ return new Pair<>(direntModels.get(0), fileTransferEntities.get(0));
+ }
+ });
+
+ addSingleDisposable(rSingle, new Consumer>() {
+ @Override
+ public void accept(Pair pair) throws Exception {
+ getCheckLocalLiveData().setValue(pair);
+ }
+ });
+
+ }
+
+ private final int SEGMENT_SIZE = 8192;
+ private final FileTransferProgressListener fileTransferProgressListener = new FileTransferProgressListener();
+
+ public void requestOriginalUrl(DirentModel direntModel) {
+ Single downloadUrlSingle = HttpIO.getCurrentInstance()
+ .execute(FileService.class)
+ .getFileDownloadLinkAsync(direntModel.repo_id, direntModel.full_path);
+
+ addSingleDisposable(downloadUrlSingle, new Consumer() {
+ @Override
+ public void accept(String dlink) throws Exception {
+ //
+ dlink = StringUtils.replace(dlink, "\"", "");
+ int i = dlink.lastIndexOf('/');
+ if (i == -1) {
+ return;
+ }
+
+ dlink = dlink.substring(0, i) + "/" + URLEncoder.encode(dlink.substring(i + 1), "UTF-8");
+
+ getOriginalUrlLiveData().setValue(dlink);
+ }
+ });
+ }
+
+ public void download(DirentModel direntModel) {
+ Single downloadUrlSingle = HttpIO.getCurrentInstance()
+ .execute(FileService.class)
+ .getFileDownloadLinkAsync(direntModel.repo_id, direntModel.full_path);
+
+ Single downloadedFilePathSingle = downloadUrlSingle.flatMap(new Function>() {
+ @Override
+ public SingleSource apply(String dlink) throws Exception {
+ //
+ dlink = StringUtils.replace(dlink, "\"", "");
+ int i = dlink.lastIndexOf('/');
+ if (i == -1) {
+ return null;
+ }
+
+ dlink = dlink.substring(0, i) + "/" + URLEncoder.encode(dlink.substring(i + 1), "UTF-8");
+
+ return Single.just(dlink);
+ }
+ }).flatMap(new Function>() {
+ @Override
+ public SingleSource apply(String s) throws Exception {
+ if (TextUtils.isEmpty(s)) {
+ //download url is null
+ throw SeafException.networkException;
+ }
+
+ FileTransferEntity transferEntity = FileTransferEntity.convertDirentModel2This(false, direntModel);
+
+ return getDownloadSingle(transferEntity, s);
+ }
+ }).flatMap(new Function>() {
+ @Override
+ public SingleSource apply(FileTransferEntity transferEntity) throws Exception {
+ return Single.just(transferEntity.target_path);
+ }
+ });
+
+ addSingleDisposable(downloadedFilePathSingle, new Consumer() {
+ @Override
+ public void accept(String s) {
+ getDownloadedPathLiveData().setValue(s);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(Throwable throwable) throws Exception {
+ SeafException seafException = getExceptionByThrowable(throwable);
+ getSeafExceptionLiveData().setValue(seafException);
+ }
+ });
+ }
+
+ private Single getDownloadSingle(FileTransferEntity transferEntity, String dlink) {
+ return Single.create(new SingleOnSubscribe() {
+ @Override
+ public void subscribe(SingleEmitter emitter) throws Exception {
+
+ Account currentAccount = SupportAccountManager.getInstance().getCurrentAccount();
+ File localFile = DataManager.getLocalRepoFile(currentAccount, transferEntity);
+
+ transferEntity.target_path = localFile.getAbsolutePath();
+ AppDatabase.getInstance().fileTransferDAO().insert(transferEntity);
+
+ Request request = new Request.Builder()
+ .url(dlink)
+ .get()
+ .build();
+
+ Call newCall = HttpIO.getCurrentInstance().getOkHttpClient().getOkClient().newCall(request);
+
+ try (Response response = newCall.execute()) {
+ if (!response.isSuccessful()) {
+ emitter.onError(SeafException.networkException);
+ return;
+ }
+
+ ResponseBody responseBody = response.body();
+ if (responseBody == null) {
+ emitter.onError(SeafException.networkException);
+ return;
+ }
+
+ long fileSize = responseBody.contentLength();
+ if (fileSize == -1) {
+ SLogs.d("download file error -> contentLength is -1");
+ SLogs.d(localFile.getAbsolutePath());
+
+ fileSize = transferEntity.file_size;
+ }
+
+ File tempFile = DataManager.createTempFile();
+ try (InputStream inputStream = responseBody.byteStream();
+ FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) {
+
+ long totalBytesRead = 0;
+
+ int bytesRead;
+ byte[] buffer = new byte[SEGMENT_SIZE];
+ while ((bytesRead = inputStream.read(buffer, 0, buffer.length)) != -1) {
+ fileOutputStream.write(buffer, 0, bytesRead);
+ totalBytesRead += bytesRead;
+
+ int p = fileTransferProgressListener.onProgress(totalBytesRead, fileSize);
+ SLogs.e(transferEntity.file_name + ", progress: " + p);
+ }
+ int p = fileTransferProgressListener.onProgress(fileSize, fileSize);
+ SLogs.e(transferEntity.file_name + ", progress: " + p);
+ }
+
+ //important
+ Path path = java.nio.file.Files.move(tempFile.toPath(), localFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ boolean isSuccess = path.toFile().exists();
+ if (isSuccess) {
+ SLogs.e("move file success: " + path);
+ transferEntity.transferred_size = fileSize;
+ transferEntity.action_end_at = System.currentTimeMillis();
+ transferEntity.file_original_modified_at = transferEntity.action_end_at;
+ transferEntity.transfer_result = TransferResult.TRANSMITTED;
+ transferEntity.transfer_status = TransferStatus.SUCCEEDED;
+
+ transferEntity.file_md5 = FileUtils.getFileMD5ToString(transferEntity.target_path).toLowerCase();
+
+ AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
+
+ emitter.onSuccess(transferEntity);
+ } else {
+ SLogs.e("move file failed: " + path);
+
+ transferEntity.transfer_result = TransferResult.FILE_ERROR;
+ transferEntity.transfer_status = TransferStatus.FAILED;
+ AppDatabase.getInstance().fileTransferDAO().update(transferEntity);
+
+ emitter.onError(SeafException.transferFileException);
+ }
+ } catch (Exception e) {
+ emitter.onError(e);
+ }
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewActivity.java
deleted file mode 100644
index 5d67f4232..000000000
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewActivity.java
+++ /dev/null
@@ -1,314 +0,0 @@
-package com.seafile.seadroid2.ui.media.image_preview;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-
-import androidx.activity.OnBackPressedCallback;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.Observer;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.blankj.utilcode.util.BarUtils;
-import com.blankj.utilcode.util.CollectionUtils;
-import com.blankj.utilcode.util.NetworkUtils;
-import com.blankj.utilcode.util.ToastUtils;
-import com.seafile.seadroid2.R;
-import com.seafile.seadroid2.databinding.ActivityImagePreviewBinding;
-import com.seafile.seadroid2.framework.data.db.entities.DirentModel;
-import com.seafile.seadroid2.framework.data.db.entities.RepoModel;
-import com.seafile.seadroid2.framework.data.db.entities.StarredModel;
-import com.seafile.seadroid2.framework.data.model.activities.ActivityModel;
-import com.seafile.seadroid2.framework.data.model.search.SearchModel;
-import com.seafile.seadroid2.framework.util.Objs;
-import com.seafile.seadroid2.ui.adapter.ViewPager2Adapter;
-import com.seafile.seadroid2.ui.base.BaseActivityWithVM;
-import com.seafile.seadroid2.ui.dialog_fragment.DeleteFileDialogFragment;
-import com.seafile.seadroid2.ui.dialog_fragment.listener.OnRefreshDataListener;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import io.reactivex.functions.Consumer;
-
-@Deprecated
-public class ImagePreviewActivity extends BaseActivityWithVM {
- private ActivityImagePreviewBinding binding;
- private ViewPager2Adapter adapter;
- private DirentModel currentDirent;
- private List direntList;
- private boolean isDataOperated = false;
-
- public static Intent startThisFromRepo(Context context, DirentModel direntModel) {
- Intent intent = new Intent(context, ImagePreviewActivity.class);
- intent.putExtra("dirent", direntModel);
- intent.putExtra("query_db", true);
- return intent;
- }
-
- public static Intent startThisFromStarred(Context context, StarredModel starredModel) {
- Intent intent = new Intent(context, ImagePreviewActivity.class);
- intent.putExtra("dirent", StarredModel.convert2DirentModel(starredModel));
- return intent;
- }
-
- public static Intent startThisFromActivity(Context context, ActivityModel starredModel) {
- Intent intent = new Intent(context, ImagePreviewActivity.class);
- intent.putExtra("dirent", ActivityModel.convert2DirentModel(starredModel));
- return intent;
- }
-
-
- public static void startThisFromSearch(Context context, SearchModel starredModel) {
- Intent intent = new Intent(context, ImagePreviewActivity.class);
- intent.putExtra("dirent", SearchModel.convert2DirentModel(starredModel));
- context.startActivity(intent);
- }
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- binding = ActivityImagePreviewBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
-
- BarUtils.setNavBarVisibility(this, false);
- BarUtils.setStatusBarVisibility(this, false);
-
- initData();
-
- initView();
- initViewModel();
-
- getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
- @Override
- public void handleOnBackPressed() {
- if (isDataOperated) {
- setResult(RESULT_OK);
- }
- finish();
- }
- });
- }
-
- @Override
- protected void onPostCreate(@Nullable Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
-
- loadData();
- }
-
- private void initData() {
-
- if (getIntent() == null) {
- throw new IllegalArgumentException("Intent is null");
- }
-
- currentDirent = getIntent().getParcelableExtra("dirent");
- }
-
- private void initView() {
- View.OnClickListener onClickListener = v -> {
- int id = v.getId();
- if (id == R.id.gallery_download_photo) {
- downloadFile();
- } else if (id == R.id.gallery_delete_photo) {
- deleteFile();
- } else if (id == R.id.gallery_star_photo) {
- starFile();
- } else if (id == R.id.gallery_share_photo) {
- shareFile();
- }
- };
-
- binding.galleryDownloadPhoto.setOnClickListener(onClickListener);
- binding.galleryDeletePhoto.setOnClickListener(onClickListener);
- binding.galleryStarPhoto.setOnClickListener(onClickListener);
- binding.gallerySharePhoto.setOnClickListener(onClickListener);
- }
-
- private void initViewModel() {
- getViewModel().getRefreshLiveData().observe(this, new Observer() {
- @Override
- public void onChanged(Boolean aBoolean) {
- if (aBoolean) {
- showProgressDialog();
- } else {
- dismissProgressDialog();
- }
- }
- });
-
- getViewModel().getStarLiveData().observe(this, new Observer() {
- @Override
- public void onChanged(Boolean aBoolean) {
- isDataOperated = true;
-
- if (aBoolean) {
-
- }else{
-
- }
- ToastUtils.showLong(aBoolean ? R.string.star_file_succeed : R.string.star_file_failed);
- }
- });
-
- getViewModel().getListLiveData().observe(this, new Observer>() {
- @Override
- public void onChanged(List direntModels) {
-
- if (CollectionUtils.isEmpty(direntModels)) {
- direntModels = CollectionUtils.newArrayList(currentDirent);
- }
-
- direntList = direntModels;
-
- notifyFragmentList();
- }
- });
- }
-
- private void loadData() {
- getViewModel().getRepoModelFromDB(currentDirent.repo_id, new Consumer() {
- @Override
- public void accept(RepoModel repoModel) {
- if (!repoModel.hasWritePermission()) {
- binding.galleryDeletePhoto.setVisibility(View.GONE);
- }
-
- getViewModel().loadData(currentDirent.repo_id, currentDirent.parent_dir);
-
- }
- });
- }
-
- private void notifyFragmentList() {
- if (CollectionUtils.isEmpty(direntList)) {
- return;
- }
-
- adapter = new ViewPager2Adapter(this);
- List fragments = new ArrayList<>();
- for (DirentModel direntModel : direntList) {
- PhotoFragment photoFragment = PhotoFragment.newInstance(direntModel);
- photoFragment.setOnPhotoTapListener((view, x, y) -> hideOrShowToolBar());
- fragments.add(photoFragment);
- }
-
- adapter.addFragments(fragments);
-
- binding.pager.setAdapter(adapter);
- binding.pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
- @Override
- public void onPageSelected(int position) {
- super.onPageSelected(position);
-
- String fs = String.format(Locale.ROOT, "%d/%d", (position + 1), direntList.size());
- binding.galleryPageIndex.setText(fs);
-
- DirentModel model = direntList.get(position);
- binding.galleryPageName.setText(model.name);
- }
- });
-
- navToSelectedPage();
- }
-
- private boolean showToolBar = false;
-
- private void hideOrShowToolBar() {
- binding.galleryToolBar.setVisibility(!showToolBar ? View.VISIBLE : View.GONE);
- binding.pageIndexContainer.setVisibility(!showToolBar ? View.VISIBLE : View.GONE);
- showToolBar = !showToolBar;
- }
-
- /**
- * Dynamically navigate to the starting page index selected by user
- * by default the starting page index is 0
- */
- private void navToSelectedPage() {
- int size = direntList.size();
- int mPageIndex = -1;
- for (int i = 0; i < size; i++) {
- if (direntList.get(i).name.equals(currentDirent.name)) {
- binding.pager.setCurrentItem(i);
- binding.galleryPageIndex.setText(String.valueOf(i + 1));
- mPageIndex = i;
- break;
- }
- }
-
- if (mPageIndex != -1) {
- binding.galleryPageIndex.setText(String.format(Locale.ROOT, "%d/%d", (mPageIndex + 1), size));
- }
- }
-
- private DirentModel getSelectedDirent() {
- int index = binding.pager.getCurrentItem();
- return direntList.get(index);
- }
-
- private void deleteFile() {
-
- int position = binding.pager.getCurrentItem();
-
- DirentModel direntModel = getSelectedDirent();
-
- DeleteFileDialogFragment dialogFragment = DeleteFileDialogFragment.newInstance(CollectionUtils.newArrayList(direntModel.uid));
- dialogFragment.setRefreshListener(new OnRefreshDataListener() {
- @Override
- public void onActionStatus(boolean isDone) {
- if (isDone) {
- isDataOperated = true;
-
- ToastUtils.showLong(R.string.delete_successful);
- adapter.removeFragment(position);
- adapter.notifyItemRemoved(position);
-
- if (adapter.getItemCount() == 0) {
- setResult(RESULT_OK);
- finish();
- } else {
- String fs = String.format(Locale.ROOT, "%d/%d", (position + 1), adapter.getFragments().size());
- binding.galleryPageIndex.setText(fs);
- }
- }
- }
- });
- dialogFragment.show(getSupportFragmentManager(), DeleteFileDialogFragment.class.getSimpleName());
- }
-
- private void starFile() {
- if (!NetworkUtils.isConnected()) {
- ToastUtils.showLong(R.string.network_down);
- return;
- }
-
- DirentModel direntModel = getSelectedDirent();
- if (direntModel.starred) {
- getViewModel().unStar(direntModel.repo_id, direntModel.full_path);
- } else {
- getViewModel().star(direntModel.repo_id, direntModel.full_path);
- }
- }
-
- private void shareFile() {
- DirentModel direntModel = getSelectedDirent();
- Objs.showCreateShareLinkDialog(this, getSupportFragmentManager(), direntModel, false);
- }
-
-
- private void downloadFile() {
- isDataOperated = true;
-
- DirentModel direntModel = getSelectedDirent();
- getViewModel().download(direntModel.repo_id, direntModel.full_path);
- }
-
-
-
-}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewViewModel.java
index b3a380029..dc5d9a2d5 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/ImagePreviewViewModel.java
@@ -64,16 +64,14 @@ public void getFileDetail(String repoId, String path) {
getRefreshLiveData().setValue(true);
Single userSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getRelatedUsers(repoId);
- Single metadataSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getMetadata(repoId);
Single detailSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getFileDetail(repoId, path);
- Single s = Single.zip(detailSingle, userSingle, metadataSingle, new Function3() {
+ Single s = Single.zip(detailSingle, userSingle, new BiFunction() {
@Override
- public FileProfileConfigModel apply(FileDetailModel docDetailModel, UserWrapperModel userWrapperModel, MetadataConfigModel metadataConfigModel) throws Exception {
+ public FileProfileConfigModel apply(FileDetailModel docDetailModel, UserWrapperModel userWrapperModel) throws Exception {
FileProfileConfigModel configModel = new FileProfileConfigModel();
configModel.setDetail(docDetailModel);
configModel.setUsers(userWrapperModel);
- configModel.setMetadata(metadataConfigModel);
return configModel;
}
});
@@ -86,34 +84,12 @@ public void accept(FileProfileConfigModel fileProfileConfigModel) throws Excepti
}
}, new Consumer() {
@Override
- public void accept(Throwable throwable) throws Exception {
+ public void accept(Throwable throwable) {
getRefreshLiveData().setValue(false);
}
});
}
- public void getRepoModelFromDB(String repoId, Consumer consumer) {
- //from db
- Single> singleDb = AppDatabase.getInstance().repoDao().getRepoById(repoId);
- addSingleDisposable(singleDb, new Consumer>() {
- @Override
- public void accept(List repoModels) throws Exception {
- if (consumer != null) {
- if (CollectionUtils.isEmpty(repoModels)) {
- //no data in sqlite, request RepoApi again
- consumer.accept(null);
- } else {
- consumer.accept(repoModels.get(0));
- }
- }
- }
- }, new Consumer() {
- @Override
- public void accept(Throwable throwable) throws Exception {
- SLogs.e(throwable);
- }
- });
- }
public void load(String repoId, String parentPath, String name, boolean isLoadOtherImagesInSameDirectory) {
if (TextUtils.isEmpty(repoId) || TextUtils.isEmpty(parentPath) || TextUtils.isEmpty(name)) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/PhotoFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/PhotoFragment.java
index dd865c41c..db0aeff56 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/PhotoFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/PhotoFragment.java
@@ -6,43 +6,47 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.webkit.MimeTypeMap;
import android.widget.ImageView;
-import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.lifecycle.Observer;
-import com.blankj.utilcode.util.EncodeUtils;
-import com.blankj.utilcode.util.SizeUtils;
+import com.blankj.utilcode.util.EncryptUtils;
+import com.blankj.utilcode.util.FileUtils;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
+import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.request.RequestListener;
-import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
+import com.bumptech.glide.signature.ObjectKey;
import com.github.chrisbanes.photoview.OnPhotoTapListener;
import com.seafile.seadroid2.R;
-import com.seafile.seadroid2.account.Account;
-import com.seafile.seadroid2.account.SupportAccountManager;
-import com.seafile.seadroid2.compat.ContextCompatKt;
+import com.seafile.seadroid2.SeafException;
+import com.seafile.seadroid2.config.OriGlideUrl;
import com.seafile.seadroid2.databinding.FragmentPhotoViewBinding;
import com.seafile.seadroid2.framework.data.db.entities.DirentModel;
-import com.seafile.seadroid2.framework.datastore.DataManager;
+import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity;
import com.seafile.seadroid2.framework.util.GlideApp;
-import com.seafile.seadroid2.ui.base.fragment.BaseFragment;
+import com.seafile.seadroid2.framework.util.GlideRequest;
+import com.seafile.seadroid2.framework.util.SLogs;
+import com.seafile.seadroid2.framework.util.ThumbnailUtils;
+import com.seafile.seadroid2.ui.base.fragment.BaseFragmentWithVM;
+import com.seafile.seadroid2.ui.media.PhotoViewModel;
-import java.io.File;
+import kotlin.Pair;
-public class PhotoFragment extends BaseFragment {
-
- private Account account;
+public class PhotoFragment extends BaseFragmentWithVM {
private String repoId, repoName, fullPath;
private String imageUrl;
private OnPhotoTapListener onPhotoTapListener;
private FragmentPhotoViewBinding binding;
-
+ private String serverUrl;
public void setOnPhotoTapListener(OnPhotoTapListener onPhotoTapListener) {
this.onPhotoTapListener = onPhotoTapListener;
@@ -56,35 +60,25 @@ public static PhotoFragment newInstance(String url) {
return fragment;
}
- public static PhotoFragment newInstance(String repoId, String repoName, String fullPath) {
-
+ public static PhotoFragment newInstance(String serverUrl, String repoId, String repoName, String fullPath) {
Bundle args = new Bundle();
args.putString("repoId", repoId);
args.putString("repoName", repoName);
args.putString("fullPath", fullPath);
-
+ args.putString("serverUrl", serverUrl);
PhotoFragment fragment = new PhotoFragment();
fragment.setArguments(args);
return fragment;
}
- public static PhotoFragment newInstance(DirentModel direntModel) {
- Bundle args = new Bundle();
-
- args.putString("repoId", direntModel.repo_id);
- args.putString("repoName", direntModel.repo_name);
- args.putString("fullPath", direntModel.full_path);
- PhotoFragment fragment = new PhotoFragment();
- fragment.setArguments(args);
- return fragment;
+ public static PhotoFragment newInstance(String serverUrl, DirentModel direntModel) {
+ return newInstance(serverUrl, direntModel.repo_id, direntModel.repo_name, direntModel.full_path);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- account = SupportAccountManager.getInstance().getCurrentAccount();
-
Bundle args = getArguments();
if (args == null) {
return;
@@ -94,6 +88,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
repoName = args.getString("repoName");
fullPath = args.getString("fullPath");
imageUrl = args.getString("image_url");
+ serverUrl = args.getString("serverUrl");
if (TextUtils.isEmpty(repoId) && TextUtils.isEmpty(imageUrl)) {
throw new IllegalStateException("the args is invalid");
@@ -124,52 +119,83 @@ public void onPhotoTap(ImageView view, float x, float y) {
}
});
- loadImage();
- }
+ intViewModel();
- private void loadImage() {
if (!TextUtils.isEmpty(imageUrl)) {
- glideLoad(imageUrl);
- return;
+ loadSingleUrl(imageUrl);
+ } else {
+ loadThumbnailAndRequestRawUrl();
}
+ }
- File file = DataManager.getLocalRepoFile(account, repoId, repoName, fullPath);
- if (file.exists()) {
- binding.progressBar.setVisibility(View.GONE);
+ private void intViewModel() {
+ getViewModel().getSeafExceptionLiveData().observe(getViewLifecycleOwner(), new Observer() {
+ @Override
+ public void onChanged(SeafException e) {
+ binding.photoView.setImageResource(R.drawable.icon_image_error_filled);
+ binding.progressBar.setVisibility(View.GONE);
+ }
+ });
- GlideApp.with(requireContext())
- .load(file)
- .into(binding.photoView);
- return;
- }
+ getViewModel().getCheckLocalLiveData().observe(getViewLifecycleOwner(), new Observer>() {
+ @Override
+ public void onChanged(Pair pair) {
+ DirentModel direntModel = pair.getFirst();
- String url = getUrl();
- if (url == null) {
- binding.photoView.setImageResource(R.drawable.icon_image_error_filled);
- return;
- }
+ if (direntModel == null) {
+ binding.photoView.setImageResource(R.drawable.icon_image_error_filled);
+ binding.progressBar.setVisibility(View.GONE);
+ return;
+ }
+
+ FileTransferEntity transferEntity = pair.getSecond();
+ if (transferEntity != null && FileUtils.isFileExists(transferEntity.target_path)) {
+ //no exists local file
+ if (isGif(fullPath)) {
+ loadOriGifUrl(transferEntity.target_path);
+ } else {
+ loadOriUrl(transferEntity.target_path);
+ }
+ } else {
+ if (isGif(fullPath)) {
+ getViewModel().download(direntModel);
+ } else {
+ getViewModel().requestOriginalUrl(direntModel);
+ }
+ }
+ }
+ });
+
+ getViewModel().getOriginalUrlLiveData().observe(getViewLifecycleOwner(), new Observer() {
+ @Override
+ public void onChanged(String oriUrl) {
+ loadOriUrl(oriUrl);
+ }
+ });
- glideLoad(url);
+ getViewModel().getDownloadedPathLiveData().observe(getViewLifecycleOwner(), new Observer() {
+ @Override
+ public void onChanged(String rawPath) {
+ loadSingleUrl(rawPath);
+ }
+ });
}
- private void glideLoad(String url) {
- RequestOptions opt = new RequestOptions()
- .skipMemoryCache(true)
- .error(R.drawable.icon_image_error_filled)
- .diskCacheStrategy(DiskCacheStrategy.NONE);
- GlideApp.with(requireContext())
+ private void loadSingleUrl(String url) {
+ GlideApp.with(this)
.load(url)
- .apply(opt)
- .fitCenter()
+ .error(R.drawable.icon_image_error_filled)
+ .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
+ .transition(DrawableTransitionOptions.withCrossFade())
.listener(new RequestListener() {
@Override
- public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
+ public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) {
binding.progressBar.setVisibility(View.GONE);
return false;
}
@Override
- public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
+ public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) {
binding.progressBar.setVisibility(View.GONE);
return false;
}
@@ -177,20 +203,100 @@ public boolean onResourceReady(Drawable resource, Object model, Target
.into(binding.photoView);
}
- private String getUrl() {
- Account account = SupportAccountManager.getInstance().getCurrentAccount();
- if (account == null) {
- return null;
+ private void loadThumbnailAndRequestRawUrl() {
+ getViewModel().checkLocal(repoId, fullPath);
+ }
+
+ private void loadOriUrl(String oriUrl) {
+ String thumbnailUrl = convertThumbnailUrl(fullPath);
+ String thumbKey = EncryptUtils.encryptMD5ToString(thumbnailUrl);
+ // load thumbnail first
+ GlideRequest thumbnailRequest = GlideApp.with(this)
+ .load(thumbnailUrl)
+ .diskCacheStrategy(DiskCacheStrategy.ALL)
+ .signature(new ObjectKey(thumbKey))
+ .addListener(new RequestListener() {
+ @Override
+ public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) {
+ return false;
+ }
+
+ @Override
+ public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) {
+// SLogs.e("缩略图:" + dataSource.name() + ": " + isFirstResource + ": " + thumbKey + ": " + thumbnailUrl);
+ return false;
+ }
+ });
+
+ String oriCacheKey = EncryptUtils.encryptMD5ToString(repoId + fullPath);
+ GlideApp.with(this)
+ .load(new OriGlideUrl(oriUrl, oriCacheKey))
+ .thumbnail(thumbnailRequest)
+ .diskCacheStrategy(DiskCacheStrategy.ALL)
+ .error(R.drawable.icon_image_error_filled)
+ .fallback(R.drawable.icon_image_error_filled)
+ .transition(DrawableTransitionOptions.withCrossFade())
+ .listener(new RequestListener() {
+ @Override
+ public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) {
+ binding.progressBar.setVisibility(View.GONE);
+ return false;
+ }
+
+ @Override
+ public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) {
+ binding.progressBar.setVisibility(View.GONE);
+ // 图片加载成功
+// SLogs.e("原图:" + dataSource.name() + ": " + isFirstResource + ": " + oriCacheKey + ": " + oriUrl);
+ return false;
+ }
+ })
+ .into(binding.photoView);
+ }
+
+
+ private void loadOriGifUrl(String rawUrl) {
+ GlideApp.with(this)
+ .asGif()
+ .load(rawUrl)
+ .diskCacheStrategy(DiskCacheStrategy.NONE)//
+ .error(R.drawable.icon_image_error_filled)
+ .fallback(R.drawable.icon_image_error_filled)
+ .placeholder(binding.photoView.getDrawable())
+ .listener(new RequestListener() {
+ @Override
+ public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target target, boolean isFirstResource) {
+ binding.progressBar.setVisibility(View.GONE);
+ return false;
+ }
+
+ @Override
+ public boolean onResourceReady(@NonNull GifDrawable resource, @NonNull Object model, Target target, @NonNull DataSource dataSource, boolean isFirstResource) {
+ binding.progressBar.setVisibility(View.GONE);
+ // 图片加载成功
+ SLogs.e(dataSource.name() + ": " + isFirstResource + ": " + rawUrl);
+ return false;
+ }
+ })
+ .into(binding.photoView);
+ }
+
+ private boolean isGif(String fileName) {
+ if (TextUtils.isEmpty(fileName)) {
+ return false;
}
-// //https://dev.seafile.com/seafhttp/repos/4809a6f3-250c-4435-bdd8-b68f34c128d1/files//6f64603fd19f9ec45d05ec379e69e22.gif/?op=download
-// //https://dev.seafile.com/seahub/repo/4809a6f3-250c-4435-bdd8-b68f34c128d1/raw/6f64603fd19f9ec45d05ec379e69e22.gif
-// if (direntModel.name.toLowerCase().endsWith(".gif")) {
-// return String.format(Locale.ROOT, "%srepo/%s/raw/%s", account.getServer(), direntModel.repo_id, direntModel.name);
-// }
+ String f = MimeTypeMap.getFileExtensionFromUrl(fileName);
+ String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(f);
+ return mime != null && mime.equalsIgnoreCase("image/gif");
+ }
-// return String.format("%srepo/%s/raw%s", account.getServer(), repoId, fileFullPath);
- int size = SizeUtils.dp2px(300);
- return String.format("%sapi2/repos/%s/thumbnail/?p=%s&size=%s", account.getServer(), repoId, EncodeUtils.urlEncode(fullPath), size);
+ private String convertThumbnailUrl(String fullPath) {
+ if (TextUtils.isEmpty(serverUrl)) {
+ return null;
+ }
+
+ return ThumbnailUtils.convertThumbnailUrl(serverUrl, repoId, fullPath);
}
+
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselAdapter.java
index 04e15a79a..9b6e2a5b4 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselAdapter.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselAdapter.java
@@ -31,19 +31,25 @@
import androidx.recyclerview.widget.RecyclerView;
import com.blankj.utilcode.util.EncodeUtils;
+import com.blankj.utilcode.util.EncryptUtils;
import com.blankj.utilcode.util.ScreenUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.signature.ObjectKey;
import com.google.common.base.Strings;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
import com.seafile.seadroid2.framework.data.db.entities.DirentModel;
+import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.framework.util.GlideApp;
+import com.seafile.seadroid2.framework.util.ThumbnailUtils;
public class CarouselAdapter extends ListAdapter {
+ boolean isLogin = SupportAccountManager.getInstance().isLogin();
+
private static final DiffUtil.ItemCallback DIFF_CALLBACK =
new DiffUtil.ItemCallback<>() {
@Override
@@ -129,40 +135,49 @@ private void bind(CarouselItemViewHolder holder, int pos) {
holder.imageView.setVisibility(View.VISIBLE);
holder.itemView.getLayoutParams().width = itemWidth;
- String url = getUrl(model.repo_id, model.full_path);
- if (url == null) {
- holder.imageView.setImageResource(R.drawable.icon_image_error_filled);
+
+ String thumbnailUrl = convertThumbnailUrl(model.repo_id, model.full_path);
+ if (TextUtils.isEmpty(thumbnailUrl)) {
+ holder.imageView.setImageResource(R.drawable.shape_solid_grey100_radius_4);
return;
}
-
- RequestOptions opt = new RequestOptions()
- .skipMemoryCache(true)
- .error(R.drawable.icon_image_error_filled)
- .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC);
+ String thumbKey = EncryptUtils.encryptMD5ToString(thumbnailUrl);
GlideApp.with(holder.imageView)
- .load(url)
+ .load(thumbnailUrl)
+ .signature(new ObjectKey(thumbKey))
.apply(opt)
.fitCenter()
.into(holder.imageView);
}
- private String getUrl(String repoId, String fullPath) {
- Account account = SupportAccountManager.getInstance().getCurrentAccount();
- if (account == null) {
+ private final RequestOptions opt = new RequestOptions()
+ .placeholder(R.drawable.shape_solid_grey100_radius_4)
+ .fallback(R.drawable.shape_solid_grey100_radius_4)
+ .error(R.drawable.icon_format_pic)
+ .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC);
+
+ private String convertThumbnailUrl(String repoId, String fullPath) {
+ String serverUrl = getServerUrl();
+ if (TextUtils.isEmpty(serverUrl)) {
return null;
}
-// //https://dev.seafile.com/seafhttp/repos/4809a6f3-250c-4435-bdd8-b68f34c128d1/files//6f64603fd19f9ec45d05ec379e69e22.gif/?op=download
-// //https://dev.seafile.com/seahub/repo/4809a6f3-250c-4435-bdd8-b68f34c128d1/raw/6f64603fd19f9ec45d05ec379e69e22.gif
-// if (direntModel.name.toLowerCase().endsWith(".gif")) {
-// return String.format(Locale.ROOT, "%srepo/%s/raw/%s", account.getServer(), direntModel.repo_id, direntModel.name);
-// }
-
-// return String.format("%srepo/%s/raw%s", account.getServer(), repoId, fileFullPath);
- int size = SizeUtils.dp2px(300);
- return String.format("%sapi2/repos/%s/thumbnail/?p=%s&size=%s", account.getServer(), repoId, EncodeUtils.urlEncode(fullPath), size);
+ return ThumbnailUtils.convertThumbnailUrl(serverUrl, repoId, fullPath);
}
+ private String serverUrl;
+
+ private String getServerUrl() {
+ if (!isLogin) {
+ return null;
+ }
+
+ if (TextUtils.isEmpty(serverUrl)) {
+ serverUrl = HttpIO.getCurrentInstance().getServerUrl();
+ }
+
+ return serverUrl;
+ }
public static class CarouselItemViewHolder extends RecyclerView.ViewHolder {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselImagePreviewActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselImagePreviewActivity.java
index 0a4f0bb6f..7ea911e93 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselImagePreviewActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselImagePreviewActivity.java
@@ -3,6 +3,7 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Pair;
@@ -21,13 +22,16 @@
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.blankj.utilcode.util.BarUtils;
import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.NetworkUtils;
+import com.blankj.utilcode.util.ScreenUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.seafile.seadroid2.R;
+import com.seafile.seadroid2.account.SupportAccountManager;
import com.seafile.seadroid2.compat.ContextCompatKt;
import com.seafile.seadroid2.context.CopyMoveContext;
import com.seafile.seadroid2.databinding.ActivityCarouselImagePreviewBinding;
@@ -38,7 +42,9 @@
import com.seafile.seadroid2.framework.data.model.activities.ActivityModel;
import com.seafile.seadroid2.framework.data.model.sdoc.FileProfileConfigModel;
import com.seafile.seadroid2.framework.data.model.search.SearchModel;
+import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.framework.util.Objs;
+import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.util.Utils;
import com.seafile.seadroid2.ui.adapter.ViewPager2Adapter;
import com.seafile.seadroid2.ui.base.BaseActivityWithVM;
@@ -49,6 +55,7 @@
import com.seafile.seadroid2.ui.media.image_preview.ImagePreviewViewModel;
import com.seafile.seadroid2.ui.media.image_preview.PhotoFragment;
import com.seafile.seadroid2.ui.selector.ObjSelectorActivity;
+import com.seafile.seadroid2.view.snap_recyclerview.GravitySnapHelper;
import java.util.ArrayList;
import java.util.HashMap;
@@ -62,11 +69,14 @@ public class CarouselImagePreviewActivity extends BaseActivityWithVM direntList;
private List carouselDirentList;
- private boolean isLightMode = true;
+ private boolean isHide = false;
+ private boolean isNightMode = false;
private boolean isDataOperated = false;
private String repoId, repoName, parentDir, name;
private boolean load_other_images_in_same_directory = false;
+ private int carouselItemWidth = 0;
+ private int carouselItemMargin = 0;
// public static Intent startThisFromDocsComment(Context context, String url) {
// Intent intent = new Intent(context, CarouselImagePreviewActivity.class);
@@ -125,15 +135,22 @@ protected void onCreate(Bundle savedInstanceState) {
// full screen
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ isNightMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES;
+
//init status bar
- int color = ContextCompatKt.getColorCompat(this, R.color.material_grey_100_translucent);
+ int color = ContextCompatKt.getColorCompat(this, R.color.bar_background_color);
BarUtils.setStatusBarColor(this, color);
- BarUtils.setStatusBarLightMode(this, isLightMode);
+ BarUtils.setStatusBarLightMode(this, !isNightMode);
//init toolbar margin top
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) binding.toolbarActionbar.getLayoutParams();
layoutParams.topMargin = BarUtils.getStatusBarHeight();
+
+ carouselItemWidth = getResources().getDimensionPixelSize(R.dimen.carousel_item_width);
+ carouselItemMargin = getResources().getDimensionPixelSize(R.dimen.carousel_item_margin);
+
Toolbar toolbar = getActionBarToolbar();
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
@@ -162,9 +179,10 @@ public void handleOnBackPressed() {
initView();
- initAdapter();
- initCarouselAdapter();
- bindPager();
+ initPager();
+ initCarouselRecyclerView();
+
+// bindPager();
initViewModel();
@@ -260,7 +278,7 @@ public void onChanged(FileProfileConfigModel configModel) {
});
}
- private void initAdapter() {
+ private void initPager() {
adapter = new ViewPager2Adapter(this);
binding.pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
@@ -269,13 +287,20 @@ public void onPageSelected(int position) {
notifyCurrentStarredStatus();
}
});
+ binding.pager.setOffscreenPageLimit(7);
binding.pager.setAdapter(adapter);
+
+ //
+ if (isNightMode) {
+ int color = ContextCompatKt.getColorCompat(this, R.color.bar_background_color);
+ binding.pager.setBackgroundColor(color);
+ }
}
private final LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
private final GravitySnapHelper gravitySnapHelper = new GravitySnapHelper(Gravity.CENTER);
- private void initCarouselAdapter() {
+ private void initCarouselRecyclerView() {
carouselAdapter = new CarouselAdapter(this, new CarouselAdapter.CarouselItemListener() {
@Override
public void onItemClicked(DirentModel item, int snapPosition) {
@@ -288,11 +313,49 @@ public void onItemClicked(DirentModel item, int snapPosition) {
binding.recyclerView.addOnScrollListener(new CenterScaleXYRecyclerViewScrollListener(this));
+ int screenWidth = ScreenUtils.getAppScreenWidth();//1080/3=360
+ int sidePadding = (screenWidth - carouselItemWidth) / 2 - carouselItemMargin * 2;//170-4=166
+ binding.recyclerView.addItemDecoration(new LinearEdgeDecoration(sidePadding, sidePadding, RecyclerView.HORIZONTAL, false));
+
gravitySnapHelper.attachToRecyclerView(binding.recyclerView);
}
private void bindPager() {
- PagerSnapBinders.bind(binding.pager, gravitySnapHelper);
+ bindPager(binding.pager, gravitySnapHelper);
+ }
+
+ private int whoScroll = -1;
+
+ public void bindPager(ViewPager2 pager, GravitySnapHelper snapHelper) {
+ pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
+ @Override
+ public void onPageSelected(int position) {
+ super.onPageSelected(position);
+ if (whoScroll == 1) {
+ whoScroll = -1;
+ return;
+ }
+
+ whoScroll = 0;
+ SLogs.e("currentPagerPosition: " + position);
+ snapHelper.smoothScrollToPosition(position);
+ }
+ });
+
+ snapHelper.setSnapListener(new GravitySnapHelper.SnapListener() {
+ @Override
+ public void onSnap(int snapPosition) {
+
+ if (whoScroll == 0) {
+ whoScroll = -1;
+ return;
+ }
+
+ whoScroll = 1;
+ SLogs.e("currentSnapPosition: " + snapPosition);
+ pager.setCurrentItem(snapPosition, false);
+ }
+ });
}
private void submitData(Pair> pair) {
@@ -311,10 +374,9 @@ private void submitData(Pair> pair) {
direntList = pair.second;
//
-
List fragments = new ArrayList<>();
for (DirentModel direntModel : direntList) {
- PhotoFragment photoFragment = PhotoFragment.newInstance(direntModel);
+ PhotoFragment photoFragment = PhotoFragment.newInstance(getServerUrl(), direntModel);
photoFragment.setOnPhotoTapListener((view, x, y) -> hideOrShowToolBar());
fragments.add(photoFragment);
}
@@ -323,9 +385,9 @@ private void submitData(Pair> pair) {
adapter.notifyItemRangeInserted(0, direntList.size());
carouselDirentList = new ArrayList<>();
- carouselDirentList.add(new DirentModel());
+// carouselDirentList.add(new DirentModel());
carouselDirentList.addAll(direntList);
- carouselDirentList.add(new DirentModel());
+// carouselDirentList.add(new DirentModel());
carouselAdapter.submitList(carouselDirentList);
@@ -334,27 +396,44 @@ private void submitData(Pair> pair) {
public void run() {
navToSelectedPage();
}
- }, 100);
+ }, 50);
+ }
+
+ private String server_url;
+ private final boolean isLogin = SupportAccountManager.getInstance().isLogin();
+
+ private String getServerUrl() {
+ if (!TextUtils.isEmpty(server_url)) {
+ return server_url;
+ }
+
+ if (!isLogin) {
+ return null;
+ }
+
+ server_url = HttpIO.getCurrentInstance().getServerUrl();
+ return server_url;
}
private void hideOrShowToolBar() {
- binding.galleryToolBar.setVisibility(isLightMode ? View.GONE : View.VISIBLE);
- binding.recyclerView.setVisibility(isLightMode ? View.GONE : View.VISIBLE);
- binding.toolbarActionbar.setVisibility(isLightMode ? View.INVISIBLE : View.VISIBLE);
+ binding.galleryToolBar.setVisibility(isHide ? View.VISIBLE : View.GONE);
+ binding.recyclerView.setVisibility(isHide ? View.VISIBLE : View.GONE);
+ binding.toolbarActionbar.setVisibility(isHide ? View.VISIBLE : View.INVISIBLE);
- if (isLightMode) {
- binding.pager.setBackgroundColor(ContextCompatKt.getColorCompat(this, R.color.material_grey_919));
+ if (isNightMode) {
+ //The background color has been set in the #initPager(), and no longer updated in night mode
} else {
- binding.pager.setBackgroundColor(ContextCompatKt.getColorCompat(this, R.color.material_grey_100));
- }
+ int color = ContextCompatKt.getColorCompat(this, isHide ? R.color.material_grey_100 : R.color.material_grey_911);
+ binding.pager.setBackgroundColor(color);
- int color = ContextCompatKt.getColorCompat(this, isLightMode ? R.color.material_grey_919_ff : R.color.material_grey_100_translucent);
- BarUtils.setNavBarColor(this, color);
- BarUtils.setStatusBarColor(this, color);
- BarUtils.setStatusBarLightMode(this, !isLightMode);
- BarUtils.setNavBarLightMode(this, !isLightMode);
+ BarUtils.setNavBarColor(this, color);
+ BarUtils.setStatusBarColor(this, color);
+
+ BarUtils.setStatusBarLightMode(this, isHide);
+ BarUtils.setNavBarLightMode(this, isHide);
+ }
- isLightMode = !isLightMode;
+ isHide = !isHide;
}
/**
@@ -373,8 +452,12 @@ private void navToSelectedPage() {
}
if (index != -1) {
- binding.pager.setCurrentItem(index);
+ int x = (carouselItemWidth + carouselItemMargin * 2) * index;
+ binding.recyclerView.scrollBy(x, 0);
+ binding.pager.setCurrentItem(index, false);
}
+
+ bindPager();
}
private void notifyCurrentStarredStatus() {
@@ -384,9 +467,9 @@ private void notifyCurrentStarredStatus() {
}
if (direntModel.starred) {
- binding.galleryStarPhoto.setImageResource(R.drawable.baseline_star_filled_24);
+ binding.galleryStarPhoto.setImageResource(R.drawable.baseline_starred_filled_24);
} else {
- binding.galleryStarPhoto.setImageResource(R.drawable.baseline_star_outline_24);
+ binding.galleryStarPhoto.setImageResource(R.drawable.baseline_starred_outline_24);
}
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/PagerSnapBinders.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/PagerSnapBinders.java
deleted file mode 100644
index 0d227c48d..000000000
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/PagerSnapBinders.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.seafile.seadroid2.ui.media.image_preview2;
-
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.seafile.seadroid2.framework.util.SLogs;
-
-public class PagerSnapBinders {
- private static int whoScroll = -1;
-
- public static void bind(ViewPager2 pager, GravitySnapHelper snapHelper) {
-
- pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
- @Override
- public void onPageSelected(int position) {
- super.onPageSelected(position);
- if (whoScroll == 1) {
- whoScroll = -1;
- return;
- }
-
- whoScroll = 0;
-
- SLogs.e("currentPagerPosition: " + position);
- position++;
- snapHelper.smoothScrollToPosition(position);
- }
- });
-
- snapHelper.setSnapListener(new GravitySnapHelper.SnapListener() {
- @Override
- public void onSnap(int snapPosition) {
-
- if (whoScroll == 0) {
- whoScroll = -1;
- return;
- }
-
- whoScroll = 1;
-
- SLogs.e("currentSnapPosition: " + snapPosition);
-
- snapPosition--;
- pager.setCurrentItem(snapPosition, true);
- }
- });
- }
-
-}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickAdapter.java
index 929eee320..eb57606ed 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickAdapter.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickAdapter.java
@@ -16,8 +16,13 @@
import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.EncodeUtils;
+import com.blankj.utilcode.util.EncryptUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.SizeUtils;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.signature.ObjectKey;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
@@ -41,6 +46,8 @@
import com.seafile.seadroid2.framework.data.model.search.SearchModel;
import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.framework.util.GlideApp;
+import com.seafile.seadroid2.framework.util.GlideOptions;
+import com.seafile.seadroid2.framework.util.ThumbnailUtils;
import com.seafile.seadroid2.framework.util.Utils;
import com.seafile.seadroid2.ui.base.adapter.BaseMultiAdapter;
import com.seafile.seadroid2.ui.repo.vh.AccountViewHolder;
@@ -369,7 +376,7 @@ private void onBindDirents(DirentViewHolder holder, DirentModel model, @NonNull
// holder.binding.getRoot().setBackground(AnimatedStateListDrawableCompatUtils.createDrawableCompat(getContext()));
- if (repoEncrypted || !Utils.isViewableImage(model.name)) {
+ if (model.isDir() || repoEncrypted || (!Utils.isViewableImage(model.name) && !Utils.isVideoFile(model.name))) {
holder.binding.itemIcon.setImageResource(model.getIcon());
} else {
loadImage(model, holder.binding.itemIcon);
@@ -473,7 +480,7 @@ private void onBindDirentsGrid(DirentGridViewHolder holder, DirentModel model, @
holder.binding.itemOutline.setVisibility(View.VISIBLE);
}
- if (repoEncrypted || !Utils.isViewableImage(model.name)) {
+ if (model.isDir() || repoEncrypted || (!Utils.isViewableImage(model.name) && !Utils.isVideoFile(model.name))) {
holder.binding.itemIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
holder.binding.itemIcon.setImageResource(model.getIcon());
} else {
@@ -521,7 +528,7 @@ private void onBindDirentsGallery(DirentGalleryViewHolder holder, DirentModel mo
}
// holder.binding.getRoot().setBackground(AnimatedStateListDrawableCompatUtils.createDrawableCompat(getContext()));
- if (repoEncrypted || !Utils.isViewableImage(model.name)) {
+ if (model.isDir() || repoEncrypted || (!Utils.isViewableImage(model.name) && !Utils.isVideoFile(model.name))) {
holder.binding.itemIcon.setImageResource(model.getIcon());
} else {
loadImage(model, holder.binding.itemIcon);
@@ -551,7 +558,8 @@ private void onBindSearch(DirentViewHolder holder, SearchModel model) {
// holder.binding.getRoot().setBackground(AnimatedStateListDrawableCompatUtils.createDrawableCompat(getContext()));
- if (repoEncrypted || !Utils.isViewableImage(model.name)) {
+
+ if (repoEncrypted || (!Utils.isViewableImage(model.name) && !Utils.isVideoFile(model.name))) {
holder.binding.itemIcon.setImageResource(model.getIcon());
} else {
DirentModel direntModel = new DirentModel();
@@ -570,39 +578,32 @@ private void onBindSearch(DirentViewHolder holder, SearchModel model) {
}
private void loadImage(DirentModel direntModel, ImageView imageView) {
-
- if (direntModel.name.toLowerCase().endsWith(".gif")) {
- imageView.setImageResource(direntModel.getIcon());
- } else {
- String url = convertThumbnailUrl(direntModel);
- if (TextUtils.isEmpty(url)) {
- GlideApp.with(getContext()).load(R.drawable.file_image)
- .apply(GlideLoadConfig.getOptions())
- .into(imageView);
- } else {
- GlideApp.with(getContext()).load(url)
- .apply(GlideLoadConfig.getOptions())
- .into(imageView);
- }
+ String thumbnailUrl = convertThumbnailUrl(direntModel);
+ if (TextUtils.isEmpty(thumbnailUrl)) {
+ GlideApp.with(getContext())
+ .load(direntModel.getIcon())
+ .apply(GlideLoadConfig.getCacheableThumbnailOptions())
+ .into(imageView);
+ return;
}
- }
- private String convertThumbnailUrl(DirentModel direntModel) {
- return convertThumbnailUrl(direntModel, 128);
- }
+ String thumbKey = EncryptUtils.encryptMD5ToString(thumbnailUrl);
- private String convertMiddleUrl(DirentModel direntModel) {
- return convertThumbnailUrl(direntModel, 256);
+ GlideApp.with(getContext())
+ .load(thumbnailUrl)
+ .signature(new ObjectKey(thumbKey))
+ .apply(GlideLoadConfig.getCustomDrawableOptions(direntModel.getIcon()))
+ .into(imageView);
}
private String server_url;
+ private final boolean isLogin = SupportAccountManager.getInstance().isLogin();
private String getServerUrl() {
if (!TextUtils.isEmpty(server_url)) {
return server_url;
}
- boolean isLogin = SupportAccountManager.getInstance().isLogin();
if (!isLogin) {
return null;
}
@@ -611,14 +612,12 @@ private String getServerUrl() {
return server_url;
}
- private String convertThumbnailUrl(DirentModel direntModel, int size) {
+ private String convertThumbnailUrl(DirentModel direntModel) {
String serverUrl = getServerUrl();
if (TextUtils.isEmpty(serverUrl)) {
return null;
}
-
- String newFilePath = EncodeUtils.urlEncode(direntModel.full_path);
- return String.format(Locale.ROOT, "%sapi2/repos/%s/thumbnail/?p=%s&size=%d", serverUrl, direntModel.repo_id, newFilePath, size);
+ return ThumbnailUtils.convertThumbnailUrl(serverUrl, direntModel.repo_id, direntModel.full_path);
}
public void setOnActionMode(boolean on) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java
index 5a1bdbce3..e6bec8389 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java
@@ -150,7 +150,11 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = LayoutFastRvBinding.inflate(inflater, container, false);
- binding.swipeRefreshLayout.setOnRefreshListener(() -> loadData(true));
+
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> {
+ removeScrolledPosition();
+ loadData(true);
+ });
return binding.getRoot();
}
@@ -172,9 +176,19 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
@Override
public void onFirstResume() {
super.onFirstResume();
+
+ restoreNavContext();
+
loadData(true);
}
+ private void restoreNavContext() {
+ NavContext navContext = getNavContext();
+ navContext.restoreNavContextFromSp();
+ mainViewModel.getOnNavContextChangeListenerLiveData().setValue(true);
+ }
+
+
@Override
public void onOtherResume() {
super.onOtherResume();
@@ -192,6 +206,15 @@ private void initRv() {
.build();
binding.rv.addItemDecoration(decoration);
+ binding.rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (RecyclerView.SCROLL_STATE_IDLE == newState){
+ saveScrollPosition();
+ }
+ }
+ });
//layout manager
binding.rv.setLayoutManager(getGridLayoutManager());
@@ -299,7 +322,6 @@ private void initAdapter() {
binding.rv.setAdapter(adapter);
}
-
private void initViewModel() {
getViewModel().getRefreshLiveData().observe(getViewLifecycleOwner(), new Observer() {
@Override
@@ -713,7 +735,7 @@ private void switchRecyclerViewLayout(FileViewType newViewType) {
}
//If SPAN_COUNT is updated, then the data in the ScrollPosition is meaningless
- removeScrollPositionExcludeRoot();
+ removeScrolledPositionExcludeRoot();
lastViewType = newViewType;
}
@@ -811,7 +833,6 @@ public void loadData() {
}
public void loadData(boolean forceRefresh) {
- removeCurrentScrollPosition();
if (forceRefresh) {
long now = TimeUtils.getNowMills();
@@ -855,9 +876,9 @@ private void showEmptyTip() {
if (FileViewType.GALLERY == type) {
showErrorView(R.string.no_album_type_data);
} else if (getNavContext().inRepo()) {
- showErrorView(R.string.no_repo);
- } else {
showErrorView(R.string.dir_empty);
+ } else {
+ showErrorView(R.string.no_repo);
}
}
@@ -877,6 +898,12 @@ private void showErrorView(int textRes) {
private void showErrorView(String msg) {
adapter.submitList(null);
TextView tipView = TipsViews.getTipTextView(requireContext());
+ tipView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ reloadData();
+ }
+ });
tipView.setText(msg);
adapter.setStateView(tipView);
adapter.setStateViewEnable(true);
@@ -884,8 +911,6 @@ private void showErrorView(String msg) {
private void navTo(BaseModel model) {
//save
- saveScrollPosition();
-
if (model instanceof RepoModel model1) {
getNavContext().push(model1);
@@ -928,7 +953,7 @@ public boolean backTo() {
adapter.setOnActionMode(false);
} else {
//
- removeCurrentScrollPosition();
+ removeScrolledPosition();
//
getNavContext().pop();
getViewModel().loadData(getNavContext(), false);
@@ -986,8 +1011,9 @@ private void saveScrollPosition() {
final int index = gridLayoutManager.findFirstVisibleItemPosition();
final ScrollState state = new ScrollState(index, top);
+ SLogs.d(state.toString());
- removeCurrentScrollPosition();
+ removeScrolledPosition();
if (!getNavContext().inRepo()) {
scrollPositions.put(KEY_REPO_SCROLL_POSITION, state);
@@ -997,7 +1023,7 @@ private void saveScrollPosition() {
}
}
- private void removeScrollPositionExcludeRoot() {
+ private void removeScrolledPositionExcludeRoot() {
if (!scrollPositions.isEmpty()) {
ScrollState rootState = scrollPositions.get(KEY_REPO_SCROLL_POSITION);
scrollPositions.clear();
@@ -1005,7 +1031,7 @@ private void removeScrollPositionExcludeRoot() {
}
}
- private void removeCurrentScrollPosition() {
+ private void removeScrolledPosition() {
if (!getNavContext().inRepo()) {
scrollPositions.remove(KEY_REPO_SCROLL_POSITION);
} else {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java
index e80886d16..337e89a97 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java
@@ -240,6 +240,7 @@ public void accept(List direntModels) throws Exception {
private void loadDirentsFromRemote(Account account, NavContext context) {
if (!NetworkUtils.isConnected()) {
getRefreshLiveData().setValue(false);
+ getSeafExceptionLiveData().setValue(SeafException.networkException);
return;
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/ScrollState.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/ScrollState.java
index 9951c5e6e..be6c0d0d4 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/repo/ScrollState.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/ScrollState.java
@@ -8,4 +8,12 @@ public ScrollState(int index, int top) {
this.index = index;
this.top = top;
}
+
+ @Override
+ public String toString() {
+ return "ScrollState{" +
+ "index=" + index +
+ ", top=" + top +
+ '}';
+ }
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentService.java b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentService.java
index 19f3df13d..f411fe28e 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentService.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentService.java
@@ -38,7 +38,7 @@ public interface DocsCommentService {
Single getMetadata(@Path("repo_id") String repoId);
@GET("api/v2.1/repos/{repo_id}/metadata/record/")
- Single getRecords(@Path("repo_id") String repoId, @Query("parent_dir") String parentDir, @Query("name") String name);
+ Single getRecords(@Path("repo_id") String repoId, @Query("parent_dir") String parentDir, @Query("name") String name, @Query("file_name") String fileName);
//
@GET("api/v1/docs/{uuid}/comment/")
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocViewModel.java
new file mode 100644
index 000000000..602210998
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocViewModel.java
@@ -0,0 +1,201 @@
+package com.seafile.seadroid2.ui.sdoc;
+
+import android.text.TextUtils;
+
+import androidx.lifecycle.MutableLiveData;
+
+import com.blankj.utilcode.util.CloneUtils;
+import com.blankj.utilcode.util.CollectionUtils;
+import com.seafile.seadroid2.account.Account;
+import com.seafile.seadroid2.account.SupportAccountManager;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileDetailModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileProfileConfigModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileRecordWrapperModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.MetadataConfigModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.OutlineItemModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.SDocOutlineWrapperModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.SDocPageOptionsModel;
+import com.seafile.seadroid2.framework.data.model.user.UserWrapperModel;
+import com.seafile.seadroid2.framework.http.HttpIO;
+import com.seafile.seadroid2.framework.util.SLogs;
+import com.seafile.seadroid2.framework.util.StringUtils;
+import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import io.reactivex.Single;
+import io.reactivex.functions.BiFunction;
+import io.reactivex.functions.Consumer;
+import io.reactivex.functions.Function3;
+
+public class SDocViewModel extends BaseViewModel {
+
+ private final MutableLiveData _fileProfileConfigLiveData = new MutableLiveData<>();
+ private final MutableLiveData _fileRecordLiveData = new MutableLiveData<>();
+ private final MutableLiveData> _sdocElementListLiveData = new MutableLiveData<>();
+
+ public MutableLiveData getFileDetailLiveData() {
+ return _fileProfileConfigLiveData;
+ }
+
+ public MutableLiveData getSdocRecordLiveData() {
+ return _fileRecordLiveData;
+ }
+
+ public MutableLiveData> getSdocElementLiveData() {
+ return _sdocElementListLiveData;
+ }
+
+ public void loadFileDetail(String repoId, String path, boolean isMetadataEnable) {
+
+ Single userSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getRelatedUsers(repoId);
+
+ //Even if isMetadataEnable is enabled, you still need to check whether the enable field of MetadataConfigModel is available
+ Single metadataSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getMetadata(repoId);
+ Single detailSingle = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getFileDetail(repoId, path);
+
+ Single s;
+ if (isMetadataEnable) {
+ s = Single.zip(detailSingle, userSingle, metadataSingle, new Function3() {
+ @Override
+ public FileProfileConfigModel apply(FileDetailModel fileDetailModel, UserWrapperModel userWrapperModel, MetadataConfigModel metadataConfigModel) throws Exception {
+ FileProfileConfigModel configModel = new FileProfileConfigModel();
+ configModel.setDetail(fileDetailModel);
+ configModel.setUsers(userWrapperModel);
+ configModel.setMetadataConfigModel(metadataConfigModel);
+ return configModel;
+ }
+ });
+ } else {
+ s = Single.zip(detailSingle, userSingle, new BiFunction() {
+ @Override
+ public FileProfileConfigModel apply(FileDetailModel fileDetailModel, UserWrapperModel userWrapperModel) throws Exception {
+ FileProfileConfigModel configModel = new FileProfileConfigModel();
+ configModel.setDetail(fileDetailModel);
+ configModel.setUsers(userWrapperModel);
+ return configModel;
+ }
+ });
+ }
+
+ addSingleDisposable(s, new Consumer() {
+ @Override
+ public void accept(FileProfileConfigModel fileProfileConfigModel) throws Exception {
+ getFileDetailLiveData().setValue(fileProfileConfigModel);
+ }
+ });
+ }
+
+ public void loadRecords(String repoId, String path) {
+ if (TextUtils.isEmpty(path) || TextUtils.equals("/", path)) {
+ return;
+ }
+
+ String parent_dir;
+ String name;
+
+ // 1. /a/b/c/t.txt
+ // 2. /a/t.txt
+ // 3. /t.txt
+ // 4. t.txt
+ // 5. /
+ if (path.contains("/")) {
+ parent_dir = path.substring(0, path.lastIndexOf("/"));
+ name = path.substring(path.lastIndexOf("/") + 1);
+ } else {
+ parent_dir = null;
+ name = path;
+ }
+
+ if (TextUtils.isEmpty(parent_dir)) {
+ parent_dir = "/";
+ }
+
+ Single single = HttpIO.getCurrentInstance().execute(DocsCommentService.class).getRecords(repoId, parent_dir, name, name);
+ addSingleDisposable(single, new Consumer() {
+ @Override
+ public void accept(FileRecordWrapperModel fileRecordWrapperModel) throws Exception {
+ getSdocRecordLiveData().setValue(fileRecordWrapperModel);
+ }
+ });
+ }
+
+ public static final List _AllowedElementTypes = List.of("header1", "header2", "header3");
+
+ public void loadSdocElements(SDocPageOptionsModel pageOptionsModel) {
+ if (TextUtils.isEmpty(pageOptionsModel.seadocServerUrl)) {
+ return;
+ }
+ getRefreshLiveData().setValue(true);
+
+ String sdocServerUrl = pageOptionsModel.seadocServerUrl;
+ if (!sdocServerUrl.endsWith("/")) {
+ sdocServerUrl = sdocServerUrl + "/";
+ }
+
+ Account curAccount = SupportAccountManager.getInstance().getCurrentAccount();
+ Account partialAccount = CloneUtils.deepClone(curAccount, Account.class);
+ partialAccount.setToken(pageOptionsModel.seadocAccessToken);
+ partialAccount.setServer(sdocServerUrl);
+
+ Single single = HttpIO.getInstanceByAccount(partialAccount).execute(DocsCommentService.class).getElements(pageOptionsModel.docUuid);
+ addSingleDisposable(single, new Consumer() {
+ @Override
+ public void accept(SDocOutlineWrapperModel wrapperModel) throws Exception {
+
+ if (wrapperModel == null || wrapperModel.elements == null) {
+ getSdocElementLiveData().setValue(null);
+ return;
+ }
+
+ List newList = wrapperModel.elements.stream().filter(new Predicate() {
+ @Override
+ public boolean test(OutlineItemModel sDocModel) {
+ if (!_AllowedElementTypes.contains(sDocModel.type)) {
+ return false;
+ }
+
+ if (TextUtils.isEmpty(sDocModel.text) && CollectionUtils.isEmpty(sDocModel.children)) {
+ return false;
+ }
+
+ return true;
+ }
+ }).map(new Function() {
+ @Override
+ public OutlineItemModel apply(OutlineItemModel sDocModel) {
+ if (!TextUtils.isEmpty(sDocModel.text)) {
+ return sDocModel;
+ }
+
+ if (CollectionUtils.isEmpty(sDocModel.children)) {
+ return sDocModel;
+ }
+
+ String text = "";
+ for (OutlineItemModel child : sDocModel.children) {
+ if (!TextUtils.isEmpty(child.text)) {
+ String nt = StringUtils.trim(child.text, "\n").trim();
+ text = text.concat(nt);
+ }
+ }
+ sDocModel.text = text;
+ return sDocModel;
+ }
+ }).collect(Collectors.toList());
+
+ getSdocElementLiveData().setValue(newList);
+ getRefreshLiveData().setValue(false);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(Throwable throwable) throws Exception {
+ SLogs.e(throwable);
+ getRefreshLiveData().setValue(false);
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocWebViewActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocWebViewActivity.java
index b992c2ff6..2b3430698 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocWebViewActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocWebViewActivity.java
@@ -27,7 +27,6 @@
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
-import com.seafile.seadroid2.annotation.Todo;
import com.seafile.seadroid2.databinding.ActivitySeaWebviewProBinding;
import com.seafile.seadroid2.databinding.ToolbarActionbarProgressBarBinding;
import com.seafile.seadroid2.enums.WebViewPreviewType;
@@ -42,11 +41,11 @@
import com.seafile.seadroid2.ui.docs_comment.DocsCommentsActivity;
import com.seafile.seadroid2.ui.file_profile.FileProfileDialog;
import com.seafile.seadroid2.ui.sdoc.outline.SDocOutlineDialog;
+import com.seafile.seadroid2.view.webview.OnWebPageListener;
import com.seafile.seadroid2.view.webview.PreloadWebView;
import com.seafile.seadroid2.view.webview.SeaWebView;
-@Todo
-public class SDocWebViewActivity extends BaseActivityWithVM {
+public class SDocWebViewActivity extends BaseActivityWithVM {
private ActivitySeaWebviewProBinding binding;
private ToolbarActionbarProgressBarBinding toolBinding;
@@ -56,6 +55,7 @@ public class SDocWebViewActivity extends BaseActivityWithVM() {
@Override
public void onChanged(FileRecordWrapperModel fileRecordWrapperModel) {
@@ -196,7 +202,6 @@ public void onChanged(FileRecordWrapperModel fileRecordWrapperModel) {
});
}
-
private void showOutlineDialog() {
readSDocOutlineList(new Consumer() {
@Override
@@ -229,12 +234,22 @@ private void showProfileDialog() {
return;
}
- if (configModel.metadata.enabled) {
- getViewModel().loadRecords(repoId, path);
- } else {
- FileProfileDialog dialog = FileProfileDialog.newInstance(configModel.detail, configModel.users.user_list);
- dialog.show(getSupportFragmentManager(), FileProfileDialog.class.getSimpleName());
- }
+ readSDocPageOptionsData(new Consumer() {
+ @Override
+ public void accept(SDocPageOptionsModel model) {
+ if (model.enableMetadataManagement) {
+ if (configModel != null && configModel.metadataConfigModel != null && configModel.metadataConfigModel.enabled) {
+ getViewModel().loadRecords(repoId, path);
+ } else if (configModel != null) {
+ FileProfileDialog dialog = FileProfileDialog.newInstance(configModel.detail, configModel.users.user_list);
+ dialog.show(getSupportFragmentManager(), FileProfileDialog.class.getSimpleName());
+ }
+ } else {
+ FileProfileDialog dialog = FileProfileDialog.newInstance(configModel.detail, configModel.users.user_list);
+ dialog.show(getSupportFragmentManager(), FileProfileDialog.class.getSimpleName());
+ }
+ }
+ });
}
private void showCommentsActivity() {
@@ -247,6 +262,10 @@ public void accept(SDocPageOptionsModel model) {
}
private void readSDocPageOptionsData(Consumer continuation) {
+ if (pageOptionsData != null) {
+ continuation.accept(pageOptionsData);
+ return;
+ }
String js =
"(function() {" +
" if (window.app && window.app.pageOptions) {" +
@@ -260,9 +279,9 @@ private void readSDocPageOptionsData(Consumer continuation
public void onReceiveValue(String value) {
if (!TextUtils.isEmpty(value)) {
value = StringUtils.deString(value).replace("\\", "");
- SDocPageOptionsModel configModel1 = GsonUtils.fromJson(value, SDocPageOptionsModel.class);
- if (configModel1 != null) {
- continuation.accept(configModel1);
+ pageOptionsData = GsonUtils.fromJson(value, SDocPageOptionsModel.class);
+ if (pageOptionsData != null) {
+ continuation.accept(pageOptionsData);
} else {
SLogs.e("read sodc page options data from web, an exception occurred in the parsing data");
SLogs.e(value);
@@ -400,6 +419,16 @@ private void hideProgressBar() {
}
}
+ private void canLoadPageConfigData() {
+ readSDocPageOptionsData(new Consumer() {
+ @Override
+ public void accept(SDocPageOptionsModel model) {
+ getViewModel().loadFileDetail(repoId, path, model.enableMetadataManagement);
+ }
+ });
+
+ }
+
@Override
protected void onPause() {
super.onPause();
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/outline/SDocOutlineRemoteDialog.java b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/outline/SDocOutlineRemoteDialog.java
index 7e6cd8196..2378d046d 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/outline/SDocOutlineRemoteDialog.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/outline/SDocOutlineRemoteDialog.java
@@ -13,7 +13,6 @@
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
-import com.blankj.utilcode.util.ToastUtils;
import com.chad.library.adapter4.BaseQuickAdapter;
import com.chad.library.adapter4.QuickAdapterHelper;
import com.google.android.material.bottomsheet.BottomSheetDialog;
@@ -22,12 +21,12 @@
import com.seafile.seadroid2.databinding.DialogSdocDirectoryBinding;
import com.seafile.seadroid2.framework.data.model.sdoc.OutlineItemModel;
import com.seafile.seadroid2.framework.data.model.sdoc.SDocPageOptionsModel;
-import com.seafile.seadroid2.ui.sdoc.DocsCommentViewModel;
+import com.seafile.seadroid2.ui.sdoc.SDocViewModel;
import java.util.List;
public class SDocOutlineRemoteDialog extends BottomSheetDialogFragment {
- private DocsCommentViewModel viewModel;
+ private SDocViewModel viewModel;
private SDocPageOptionsModel pageOptionsModel;
@@ -51,7 +50,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
}
pageOptionsModel = getArguments().getParcelable("pageOption");
- viewModel = new ViewModelProvider(this).get(DocsCommentViewModel.class);
+ viewModel = new ViewModelProvider(this).get(SDocViewModel.class);
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java
index a48934fc3..4c55a7d97 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java
@@ -301,13 +301,13 @@ private void doWorkInfoLiveData(WorkInfo workInfo) {
}
if (String.valueOf(TransferDataSource.ALBUM_BACKUP).equals(dataType)) {
- if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(progressEvent)) {
+ if (TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA.equals(progressEvent)) {
mCameraBackupState.setSummary(R.string.above_quota);
} else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) {
viewModel.countAlbumBackupPendingList(requireContext());
}
} else if (String.valueOf(TransferDataSource.FOLDER_BACKUP).equals(dataType)) {
- if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(progressEvent)) {
+ if (TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA.equals(progressEvent)) {
mFolderBackupState.setSummary(R.string.above_quota);
} else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) {
viewModel.countFolderBackupPendingList(requireContext());
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/settings/TabSettingsFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/settings/TabSettingsFragment.java
index 7c970136b..b34cada07 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/settings/TabSettingsFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/settings/TabSettingsFragment.java
@@ -5,11 +5,9 @@
import android.content.DialogInterface;
import android.content.Intent;
-import android.os.Build;
import android.os.Bundle;
import android.text.Spanned;
import android.text.TextUtils;
-import android.view.View;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
@@ -37,13 +35,10 @@
import com.seafile.seadroid2.bus.TransferBusHelper;
import com.seafile.seadroid2.config.Constants;
import com.seafile.seadroid2.enums.NetworkMode;
-import com.seafile.seadroid2.enums.NightMode;
import com.seafile.seadroid2.enums.TransferDataSource;
-import com.seafile.seadroid2.framework.data.ServerInfo;
import com.seafile.seadroid2.framework.datastore.StorageManager;
import com.seafile.seadroid2.framework.datastore.sp_livedata.AlbumBackupSharePreferenceHelper;
import com.seafile.seadroid2.framework.datastore.sp_livedata.FolderBackupSharePreferenceHelper;
-import com.seafile.seadroid2.framework.helper.NightModeHelper;
import com.seafile.seadroid2.framework.util.PermissionUtil;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl;
@@ -53,7 +48,6 @@
import com.seafile.seadroid2.framework.worker.upload.MediaBackupScannerWorker;
import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker;
import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker;
-import com.seafile.seadroid2.gesturelock.LockPatternUtils;
import com.seafile.seadroid2.preferences.RenameSharePreferenceFragmentCompat;
import com.seafile.seadroid2.preferences.Settings;
import com.seafile.seadroid2.ui.account.AccountsActivity;
@@ -67,11 +61,9 @@
import com.seafile.seadroid2.ui.folder_backup.FolderBackupConfigActivity;
import com.seafile.seadroid2.ui.folder_backup.FolderBackupSelectedPathActivity;
import com.seafile.seadroid2.ui.folder_backup.RepoConfig;
-import com.seafile.seadroid2.ui.gesture.CreateGesturePasswordActivity;
import com.seafile.seadroid2.ui.main.MainActivity;
import com.seafile.seadroid2.ui.selector.ObjSelectorActivity;
import com.seafile.seadroid2.ui.webview.SeaWebViewActivity;
-import com.seafile.seadroid2.widget.prefs.ButtonPreference;
import java.util.ArrayList;
import java.util.List;
@@ -445,9 +437,10 @@ public void onChanged(Boolean aBoolean) {
} else {
mAlbumBackupSwitch.setChecked(false);
AlbumBackupSharePreferenceHelper.writeRepoConfig(null);
+ switchAlbumBackupState(false);
+ dispatchAlbumBackupWork(false);
}
- switchAlbumBackupState(aBoolean);
}
});
@@ -557,14 +550,18 @@ private void checkScanWorkInfo(TransferDataSource dataSource, WorkInfo workInfo)
Data outData = workInfo.getOutputData();
String outDataEvent = outData.getString(TransferWorker.KEY_DATA_EVENT);
String outDataType = outData.getString(TransferWorker.KEY_DATA_TYPE);
+
+ //scan end
if (TextUtils.equals(String.valueOf(TransferDataSource.ALBUM_BACKUP), outDataType)) {
if (TransferEvent.EVENT_SCAN_END.equals(outDataEvent)) {
- mAlbumBackupState.setSummary(R.string.done);
+// mAlbumBackupState.setSummary(R.string.done);
+ SLogs.e("album scan end");
return;
}
} else if (TextUtils.equals(String.valueOf(TransferDataSource.FOLDER_BACKUP), outDataType)) {
if (TransferEvent.EVENT_SCAN_END.equals(outDataEvent)) {
- mFolderBackupState.setSummary(R.string.done);
+// mFolderBackupState.setSummary(R.string.done);
+ SLogs.e("folder scan end");
return;
}
}
@@ -598,14 +595,18 @@ private void checkOutputData(WorkInfo workInfo) {
if (TextUtils.equals(String.valueOf(TransferDataSource.ALBUM_BACKUP), outDataType)) {
if (TransferEvent.EVENT_FINISH.equals(outDataEvent)) {
mAlbumBackupState.setSummary(R.string.settings_cuc_finish_title);
- } else if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(outDataEvent)) {
+ } else if (TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA.equals(outDataEvent)) {
mAlbumBackupState.setSummary(R.string.above_quota);
+ } else if (TransferEvent.EVENT_CANCEL_WITH_BY_STOPPED.equals(outDataEvent)) {
+ mAlbumBackupState.setSummary(R.string.canceled);
}
} else if (TextUtils.equals(String.valueOf(TransferDataSource.FOLDER_BACKUP), outDataType)) {
if (TransferEvent.EVENT_FINISH.equals(outDataEvent)) {
mFolderBackupState.setSummary(R.string.folder_backup_waiting_state);
- } else if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(outDataEvent)) {
+ } else if (TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA.equals(outDataEvent)) {
mFolderBackupState.setSummary(R.string.above_quota);
+ } else if (TransferEvent.EVENT_CANCEL_WITH_BY_STOPPED.equals(outDataEvent)) {
+ mFolderBackupState.setSummary(R.string.canceled);
}
} else {
checkProgressData(workInfo);
@@ -696,6 +697,10 @@ private void switchAlbumBackupState(boolean isEnable) {
mAlbumBackupState.setVisible(isEnable);
mAlbumBackupAdvanced.setVisible(isEnable);
+ if (!isEnable) {
+ mAlbumBackupState.setSummary(null);
+ }
+
updateAlbumBackupSelectedRepoSummary();
}
@@ -724,6 +729,10 @@ private void switchFolderBackupState(boolean isEnable) {
mFolderBackupSelectFolder.setVisible(isEnable);
mFolderBackupState.setVisible(isEnable);
+ if (!isEnable) {
+ mFolderBackupState.setSummary(null);
+ }
+
updateFolderBackupSelectedRepoAndFolderSummary();
}
@@ -856,10 +865,12 @@ public void onActivityResult(ActivityResult o) {
@Override
public void onActivityResult(ActivityResult o) {
if (o.getResultCode() == RESULT_OK) {
+ //The dispatch function needs to be put first
dispatchAlbumBackupWork(true);
- updateAlbumBackupSelectedRepoSummary();
+ switchAlbumBackupState(true);
} else {
+ //The dispatch function needs to be put first
dispatchAlbumBackupWork(false);
if (o.getData() != null) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java
index 5a97437db..834e088bf 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java
@@ -97,8 +97,12 @@ private void onBindHolder(TransferItemViewHolder holder, FileTransferEntity enti
}
//target path
- String targetPath = Utils.pathJoin(entity.repo_name, entity.getParent_path());
- holder.binding.transferTargetPath.setText(targetPath);
+ if (!TextUtils.isEmpty(entity.repo_name)) {
+ String targetPath = Utils.pathJoin(entity.repo_name, entity.getParent_path());
+ holder.binding.transferTargetPath.setText(targetPath);
+ } else {
+ holder.binding.transferTargetPath.setText(entity.getParent_path());
+ }
//file name
holder.binding.transferFileName.setText(entity.file_name);
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java
index c8f764aeb..53080f0e6 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java
@@ -176,14 +176,6 @@ public void showBottomSheet(FileTransferEntity entity) {
builder.removeMenu(R.id.upload);
builder.removeMenu(R.id.download);
- builder.removeMenu(R.id.pause);
-
- //not supported yet
-// if (getTransferAction() == TransferAction.DOWNLOAD) {
-// builder.removeMenu(R.id.upload);
-// } else if (getTransferAction() == TransferAction.UPLOAD) {
-// builder.removeMenu(R.id.download);
-// }
builder.show(getChildFragmentManager());
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java
index b7e323623..782a97af9 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java
@@ -101,7 +101,7 @@ private void doWorkInfoLiveData(TransferDataSource dataSource, WorkInfo workInfo
Data progressData = workInfo.getProgress();
String progressEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT);
- if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(progressEvent)) {
+ if (TransferEvent.EVENT_CANCEL_WITH_OUT_OF_QUOTA.equals(progressEvent)) {
refreshData();
} else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) {
@@ -113,7 +113,6 @@ private void doWorkInfoLiveData(TransferDataSource dataSource, WorkInfo workInfo
SLogs.d("upload: " + fileName + ", percent:" + percent + ", total_size:" + totalSize + ", dataSource: " + dataSource);
-
if (TextUtils.equals(transferId, lastTransferId)) {
notifyProgressById(transferId, transferredSize, percent, progressEvent);
} else {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java b/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/GravitySnapHelper.java
similarity index 98%
rename from app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
rename to app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/GravitySnapHelper.java
index 7f27ee3a7..2c7d26d06 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
+++ b/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/GravitySnapHelper.java
@@ -1,4 +1,4 @@
-package com.seafile.seadroid2.ui.media.image_preview2;
+package com.seafile.seadroid2.view.snap_recyclerview;
import android.util.DisplayMetrics;
import android.view.Gravity;
@@ -215,8 +215,8 @@ protected void onTargetFound(View targetView,
// The associated RecyclerView has been removed so there is no action to take.
return;
}
- int[] snapDistances = calculateDistanceToFinalSnap(recyclerView.getLayoutManager(),
- targetView);
+
+ int[] snapDistances = calculateDistanceToFinalSnap(recyclerView.getLayoutManager(), targetView);
final int dx = snapDistances[0];
final int dy = snapDistances[1];
final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
@@ -468,18 +468,19 @@ private int getFlingDistance() {
private boolean scrollTo(int position, boolean smooth) {
if (recyclerView.getLayoutManager() != null) {
if (smooth) {
- RecyclerView.SmoothScroller smoothScroller
- = createScroller(recyclerView.getLayoutManager());
+ RecyclerView.SmoothScroller smoothScroller = createScroller(recyclerView.getLayoutManager());
if (smoothScroller != null) {
smoothScroller.setTargetPosition(position);
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
return true;
}
} else {
- RecyclerView.ViewHolder viewHolder
- = recyclerView.findViewHolderForAdapterPosition(position);
+// recyclerView.getLayoutManager().scrollToPosition(position);
+// return true;
+ RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position);
if (viewHolder != null) {
- int[] distances = calculateDistanceToFinalSnap(recyclerView.getLayoutManager(),
+ int[] distances = calculateDistanceToFinalSnap(
+ recyclerView.getLayoutManager(),
viewHolder.itemView);
recyclerView.scrollBy(distances[0], distances[1]);
return true;
diff --git a/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/GravitySnapRecyclerView.java b/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/GravitySnapRecyclerView.java
new file mode 100644
index 000000000..84dd154d1
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/GravitySnapRecyclerView.java
@@ -0,0 +1,150 @@
+package com.seafile.seadroid2.view.snap_recyclerview;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.seafile.seadroid2.R;
+
+/**
+ * An {@link OrientationAwareRecyclerView} that uses a default {@link GravitySnapHelper}
+ */
+public class GravitySnapRecyclerView extends OrientationAwareRecyclerView {
+
+ @NonNull
+ final private GravitySnapHelper snapHelper;
+
+ private boolean isSnappingEnabled = false;
+
+ public GravitySnapRecyclerView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public GravitySnapRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public GravitySnapRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ TypedArray typedArray = context.obtainStyledAttributes(attrs,
+ R.styleable.GravitySnapRecyclerView, defStyleAttr, 0);
+ int snapGravity = typedArray.getInt(
+ R.styleable.GravitySnapRecyclerView_snapGravity, 0);
+ switch (snapGravity) {
+ case 0:
+ snapHelper = new GravitySnapHelper(Gravity.START);
+ break;
+ case 1:
+ snapHelper = new GravitySnapHelper(Gravity.TOP);
+ break;
+ case 2:
+ snapHelper = new GravitySnapHelper(Gravity.END);
+ break;
+ case 3:
+ snapHelper = new GravitySnapHelper(Gravity.BOTTOM);
+ break;
+ case 4:
+ snapHelper = new GravitySnapHelper(Gravity.CENTER);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid gravity value. Use START " +
+ "| END | BOTTOM | TOP | CENTER constants");
+ }
+
+ snapHelper.setSnapToPadding(typedArray.getBoolean(
+ R.styleable.GravitySnapRecyclerView_snapToPadding, false));
+
+ snapHelper.setSnapLastItem(typedArray.getBoolean(
+ R.styleable.GravitySnapRecyclerView_snapLastItem, false));
+
+ snapHelper.setMaxFlingSizeFraction(typedArray.getFloat(
+ R.styleable.GravitySnapRecyclerView_snapMaxFlingSizeFraction,
+ GravitySnapHelper.FLING_SIZE_FRACTION_DISABLE));
+
+ snapHelper.setScrollMsPerInch(typedArray.getFloat(
+ R.styleable.GravitySnapRecyclerView_snapScrollMsPerInch, 100f));
+
+ enableSnapping(typedArray.getBoolean(
+ R.styleable.GravitySnapRecyclerView_snapEnabled, true));
+
+ typedArray.recycle();
+ }
+
+ @Override
+ public void smoothScrollToPosition(int position) {
+ if (!isSnappingEnabled || !snapHelper.smoothScrollToPosition(position)) {
+ super.smoothScrollToPosition(position);
+ }
+ }
+
+ @Override
+ public void scrollToPosition(int position) {
+ if (!isSnappingEnabled || !snapHelper.scrollToPosition(position)) {
+ super.scrollToPosition(position);
+ }
+ }
+
+ @NonNull
+ public GravitySnapHelper getSnapHelper() {
+ return snapHelper;
+ }
+
+ public void enableSnapping(Boolean enable) {
+ if (enable) {
+ snapHelper.attachToRecyclerView(this);
+ } else {
+ snapHelper.attachToRecyclerView(null);
+ }
+ isSnappingEnabled = enable;
+ }
+
+ public boolean isSnappingEnabled() {
+ return isSnappingEnabled;
+ }
+
+ public int getCurrentSnappedPosition() {
+ return snapHelper.getCurrentSnappedPosition();
+ }
+
+ public void snapToNextPosition(Boolean smooth) {
+ snapTo(true, smooth);
+ }
+
+ public void snapToPreviousPosition(Boolean smooth) {
+ snapTo(false, smooth);
+ }
+
+ public void setSnapListener(@Nullable GravitySnapHelper.SnapListener listener) {
+ snapHelper.setSnapListener(listener);
+ }
+
+ private void snapTo(Boolean next, Boolean smooth) {
+ final RecyclerView.LayoutManager lm = getLayoutManager();
+ if (lm != null) {
+ final View snapView = snapHelper.findSnapView(lm, false);
+ if (snapView != null) {
+ final int pos = getChildAdapterPosition(snapView);
+ if (next) {
+ if (smooth) {
+ smoothScrollToPosition(pos + 1);
+ } else {
+ scrollToPosition(pos + 1);
+ }
+ } else if (pos > 0) {
+ if (smooth) {
+ smoothScrollToPosition(pos - 1);
+ } else {
+ scrollToPosition(pos - 1);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/OrientationAwareRecyclerView.java b/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/OrientationAwareRecyclerView.java
new file mode 100644
index 000000000..ba993d26b
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/view/snap_recyclerview/OrientationAwareRecyclerView.java
@@ -0,0 +1,81 @@
+package com.seafile.seadroid2.view.snap_recyclerview;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * A RecyclerView that only handles scroll events with the same orientation of its LayoutManager.
+ * Avoids situations where nested recyclerviews don't receive touch events properly:
+ */
+public class OrientationAwareRecyclerView extends RecyclerView {
+
+ private float lastX = 0.0f;
+ private float lastY = 0.0f;
+ private boolean scrolling = false;
+
+ public OrientationAwareRecyclerView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public OrientationAwareRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public OrientationAwareRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ addOnScrollListener(new OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ scrolling = newState != RecyclerView.SCROLL_STATE_IDLE;
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent e) {
+ final LayoutManager lm = getLayoutManager();
+ if (lm == null) {
+ return super.onInterceptTouchEvent(e);
+ }
+
+ boolean allowScroll = true;
+
+ switch (e.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ lastX = e.getX();
+ lastY = e.getY();
+ // If we were scrolling, stop now by faking a touch release
+ if (scrolling) {
+ MotionEvent newEvent = MotionEvent.obtain(e);
+ newEvent.setAction(MotionEvent.ACTION_UP);
+ return super.onInterceptTouchEvent(newEvent);
+ }
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ // We're moving, so check if we're trying
+ // to scroll vertically or horizontally so we don't intercept the wrong event.
+ float currentX = e.getX();
+ float currentY = e.getY();
+ float dx = Math.abs(currentX - lastX);
+ float dy = Math.abs(currentY - lastY);
+ allowScroll = dy > dx ? lm.canScrollVertically() : lm.canScrollHorizontally();
+ break;
+ }
+ }
+
+ if (!allowScroll) {
+ return false;
+ }
+
+ return super.onInterceptTouchEvent(e);
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/seafile/seadroid2/view/webview/OnWebPageListener.java b/app/src/main/java/com/seafile/seadroid2/view/webview/OnWebPageListener.java
new file mode 100644
index 000000000..5348815f7
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/view/webview/OnWebPageListener.java
@@ -0,0 +1,7 @@
+package com.seafile.seadroid2.view.webview;
+
+import android.webkit.WebView;
+
+public interface OnWebPageListener {
+ void onPageFinished(WebView view, String url);
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebView.java b/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebView.java
index c756bed2b..55bccf3db 100644
--- a/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebView.java
+++ b/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebView.java
@@ -6,6 +6,7 @@
import android.util.AttributeSet;
import android.webkit.CookieManager;
import android.webkit.WebSettings;
+import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -92,6 +93,11 @@ private void init() {
registerCommonHandler();
}
+ public void setOnWebPageListener(OnWebPageListener onWebPageListener) {
+ mWebViewClient.setOnWebPageListener(onWebPageListener);
+ this.setWebViewClient(mWebViewClient);
+ }
+
public void load(String targetUrl) {
mWebViewClient.go(targetUrl, this);
}
diff --git a/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebViewClient.java b/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebViewClient.java
index b6da31b3f..fe7ae53bf 100644
--- a/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebViewClient.java
+++ b/app/src/main/java/com/seafile/seadroid2/view/webview/SeaWebViewClient.java
@@ -19,10 +19,25 @@
import java.util.Map;
public class SeaWebViewClient extends BridgeWebViewClient {
+
+ private OnWebPageListener onWebPageListener;
+
+ public void setOnWebPageListener(OnWebPageListener onWebPageListener) {
+ this.onWebPageListener = onWebPageListener;
+ }
+
public SeaWebViewClient(BridgeWebView webView) {
super(webView);
}
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ if (onWebPageListener != null) {
+ onWebPageListener.onPageFinished(view, url);
+ }
+ }
+
@Override
public boolean shouldOverrideUrlLoading(WebView wb, WebResourceRequest request) {
String url = request.getUrl().toString();
diff --git a/app/src/main/res/drawable/baseline_delete_24.xml b/app/src/main/res/drawable/baseline_delete_24.xml
index 8603e59d2..af9a48e10 100644
--- a/app/src/main/res/drawable/baseline_delete_24.xml
+++ b/app/src/main/res/drawable/baseline_delete_24.xml
@@ -4,6 +4,21 @@
android:viewportWidth="24"
android:viewportHeight="24">
+ android:pathData="M20.792,6.462H3.208C3.093,6.462 3,6.555 3,6.669V7.985C3,8.099 3.093,8.192 3.208,8.192H20.792C20.907,8.192 21,8.099 21,7.985V6.669C21,6.555 20.907,6.462 20.792,6.462Z"
+ android:fillColor="#999999"/>
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_download_24.xml b/app/src/main/res/drawable/baseline_download_24.xml
new file mode 100644
index 000000000..c9ca2f102
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_download_24.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_share_24.xml b/app/src/main/res/drawable/baseline_share_24.xml
index ec5a0fac2..a3390defe 100644
--- a/app/src/main/res/drawable/baseline_share_24.xml
+++ b/app/src/main/res/drawable/baseline_share_24.xml
@@ -1,9 +1,21 @@
+ android:width="18dp"
+ android:height="18dp"
+ android:viewportWidth="18"
+ android:viewportHeight="18">
+ android:pathData="M17.308,2.423C17.308,1.085 16.223,0 14.884,0C13.546,0 12.461,1.085 12.461,2.423C12.461,3.761 13.546,4.846 14.884,4.846C16.223,4.846 17.308,3.761 17.308,2.423Z"
+ android:fillColor="#999999"/>
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_star_filled_24.xml b/app/src/main/res/drawable/baseline_star_filled_24.xml
deleted file mode 100644
index 40437ec7c..000000000
--- a/app/src/main/res/drawable/baseline_star_filled_24.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/baseline_star_outline_24.xml b/app/src/main/res/drawable/baseline_star_outline_24.xml
deleted file mode 100644
index 2a5e48606..000000000
--- a/app/src/main/res/drawable/baseline_star_outline_24.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/baseline_starred_32.xml b/app/src/main/res/drawable/baseline_starred_32.xml
deleted file mode 100644
index 6153d4543..000000000
--- a/app/src/main/res/drawable/baseline_starred_32.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/baseline_starred_filled_24.xml b/app/src/main/res/drawable/baseline_starred_filled_24.xml
new file mode 100644
index 000000000..45b89e79b
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_starred_filled_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_starred_filled_32.xml b/app/src/main/res/drawable/baseline_starred_filled_32.xml
new file mode 100644
index 000000000..9efb9bdec
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_starred_filled_32.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_starred_outline_24.xml b/app/src/main/res/drawable/baseline_starred_outline_24.xml
new file mode 100644
index 000000000..b3d1e96ed
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_starred_outline_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/shape_solid_grey100_radius_4.xml b/app/src/main/res/drawable/shape_solid_grey100_radius_4.xml
new file mode 100644
index 000000000..ccd3eb776
--- /dev/null
+++ b/app/src/main/res/drawable/shape_solid_grey100_radius_4.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_carousel_image_preview.xml b/app/src/main/res/layout/activity_carousel_image_preview.xml
index bb2ada195..e12a5154a 100644
--- a/app/src/main/res/layout/activity_carousel_image_preview.xml
+++ b/app/src/main/res/layout/activity_carousel_image_preview.xml
@@ -21,7 +21,7 @@
style="@style/ToolBarStyle"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
- android:background="@color/bar_background_translucent_color"
+ android:background="@color/bar_background_color"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -30,7 +30,7 @@
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/bar_background_translucent_color"
+ android:background="@color/bar_background_color"
android:clipToPadding="false"
android:paddingTop="4dp"
app:layout_constraintBottom_toTopOf="@+id/gallery_tool_bar"
@@ -41,10 +41,11 @@
android:id="@+id/gallery_tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/bar_background_translucent_color"
+ android:background="@color/bar_background_color"
android:gravity="center_horizontal"
android:orientation="horizontal"
- android:paddingTop="4dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -56,7 +57,7 @@
android:layout_height="36dp"
android:foreground="?selectableItemBackground"
android:scaleType="centerInside"
- android:src="@drawable/action_download"
+ android:src="@drawable/baseline_download_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/gallery_delete_photo"
app:layout_constraintStart_toStartOf="parent"
@@ -82,7 +83,7 @@
android:layout_height="36dp"
android:foreground="?selectableItemBackground"
android:scaleType="centerInside"
- android:src="@drawable/baseline_star_outline_24"
+ android:src="@drawable/baseline_starred_outline_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/gallery_share_photo"
app:layout_constraintStart_toEndOf="@+id/gallery_delete_photo"
diff --git a/app/src/main/res/layout/activity_image_preview.xml b/app/src/main/res/layout/activity_image_preview.xml
index c1f5d7f55..53a7db8c7 100644
--- a/app/src/main/res/layout/activity_image_preview.xml
+++ b/app/src/main/res/layout/activity_image_preview.xml
@@ -28,7 +28,7 @@
android:background="@drawable/shape_stroke_radius_solid_translucent"
android:foreground="?selectableItemBackground"
android:scaleType="centerInside"
- android:src="@drawable/action_download"
+ android:src="@drawable/baseline_download_24"
app:shapeAppearance="@style/ShapeCircleStyle"
app:tint="@color/white" />
@@ -40,7 +40,7 @@
android:background="@drawable/shape_stroke_radius_solid_translucent"
android:foreground="?selectableItemBackground"
android:scaleType="centerInside"
- android:src="@drawable/action_delete"
+ android:src="@drawable/baseline_delete_24"
app:shapeAppearance="@style/ShapeCircleStyle"
app:tint="@color/white" />
@@ -52,7 +52,7 @@
android:background="@drawable/shape_stroke_radius_solid_translucent"
android:foreground="?selectableItemBackground"
android:scaleType="centerInside"
- android:src="@drawable/baseline_star_outline_24"
+ android:src="@drawable/baseline_starred_outline_24"
app:shapeAppearance="@style/ShapeCircleStyle"
app:tint="@color/white" />
@@ -63,7 +63,7 @@
android:background="@drawable/shape_stroke_radius_solid_translucent"
android:foreground="?selectableItemBackground"
android:scaleType="centerInside"
- android:src="@drawable/action_share"
+ android:src="@drawable/baseline_share_24"
app:shapeAppearance="@style/ShapeCircleStyle"
app:tint="@color/white" />
diff --git a/app/src/main/res/layout/gallery_activity_layout.xml b/app/src/main/res/layout/gallery_activity_layout.xml
deleted file mode 100644
index a5a3f937f..000000000
--- a/app/src/main/res/layout/gallery_activity_layout.xml
+++ /dev/null
@@ -1,131 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml
index 726782915..b68ecbb92 100644
--- a/app/src/main/res/menu/bottom_navigation_menu.xml
+++ b/app/src/main/res/menu/bottom_navigation_menu.xml
@@ -8,7 +8,7 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_sheet_unstarred.xml b/app/src/main/res/menu/bottom_sheet_unstarred.xml
index a2c840bcb..82a8e0699 100644
--- a/app/src/main/res/menu/bottom_sheet_unstarred.xml
+++ b/app/src/main/res/menu/bottom_sheet_unstarred.xml
@@ -11,7 +11,7 @@
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index b436f4ac2..6ae299478 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -71,4 +71,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 70fdab007..e3c2ccd5d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -683,6 +683,8 @@
Mark as resolved
Are you sure you want to delete this item?
+
+ Canceled
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 87a53e5fc..43be69259 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -201,6 +201,10 @@
- 4dp
+