fragments = new ArrayList<>();
+ for (DirentModel direntModel : direntList) {
+ PhotoFragment photoFragment = PhotoFragment.newInstance(direntModel);
+ photoFragment.setOnPhotoTapListener((view, x, y) -> hideOrShowToolBar());
+ fragments.add(photoFragment);
+ }
+
+ adapter.addFragments(fragments);
+ adapter.notifyItemRangeInserted(0, direntList.size());
+
+ carouselAdapter.submitList(direntList);
+
+ binding.recyclerView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ navToSelectedPage();
+ }
+ }, 100);
+ }
+
+
+ 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);
+
+ 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);
+
+ isLightMode = !isLightMode;
+ }
+
+
+ /**
+ * 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 index = -1;
+
+ for (int i = 0; i < size; i++) {
+ if (direntList.get(i).name.equals(name)) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index != -1) {
+ binding.pager.setCurrentItem(index, true);
+ gravitySnapHelper.scrollToPosition(index);
+ }
+ }
+
+ private void notifyCurrentStarredStatus() {
+ DirentModel direntModel = getSelectedDirent();
+ if (direntModel == null) {
+ return;
+ }
+ if (direntModel.starred) {
+ binding.galleryStarPhoto.setImageResource(R.drawable.baseline_starred_32);
+ } else {
+ binding.galleryStarPhoto.setImageResource(R.drawable.baseline_star_outline_24);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ Toolbar toolbar = getActionBarToolbar();
+ toolbar.inflateMenu(R.menu.menu_image_list_preview);
+ toolbar.setOnMenuItemClickListener(this);
+
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ } else if (item.getItemId() == R.id.copy) {
+ ToastUtils.showLong(R.string.file_action_copy);
+ } else if (item.getItemId() == R.id.info) {
+ ToastUtils.showLong(R.string.file_action_copy);
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ private DirentModel getSelectedDirent() {
+ int index = binding.pager.getCurrentItem();
+ return carouselAdapter.getItem(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;
+
+ direntList.remove(position);
+ adapter.removeFragment(position);
+ adapter.notifyItemRemoved(position);
+ carouselAdapter.notifyItemRemoved(position);
+
+ ToastUtils.showLong(R.string.delete_successful);
+
+ if (adapter.getItemCount() == 0) {
+ setResult(RESULT_OK);
+ finish();
+ }
+ }
+ }
+ });
+ 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/CarouselItem.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItem.java
similarity index 93%
rename from app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/CarouselItem.java
rename to app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItem.java
index 821ed483e..202ee4838 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/CarouselItem.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItem.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.seafile.seadroid2.ui.media.image_preview;
+package com.seafile.seadroid2.ui.media.image_preview2;
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
@@ -22,7 +22,7 @@
/**
* A data class that holds all information related to an item inside a Carousel.
*/
-class CarouselItem {
+public class CarouselItem {
@DrawableRes
private final int drawableRes;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/CarouselItemListener.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java
similarity index 55%
rename from app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/CarouselItemListener.java
rename to app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java
index 8f1870fd9..f036a3703 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview/CarouselItemListener.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java
@@ -14,9 +14,24 @@
* limitations under the License.
*/
-package com.seafile.seadroid2.ui.media.image_preview;
+package com.seafile.seadroid2.ui.media.image_preview2;
+
+
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.seafile.seadroid2.R;
+
+public class CarouselItemViewHolder extends RecyclerView.ViewHolder {
+
+ public final ImageView imageView;
+
+ CarouselItemViewHolder(@NonNull View itemView) {
+ super(itemView);
+ imageView = itemView.findViewById(R.id.image_view);
+ }
-/** An interface for items in a carousel. */
-interface CarouselItemListener {
- void onItemClicked(CarouselItem item, int position);
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java
new file mode 100644
index 000000000..a81e44cbe
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java
@@ -0,0 +1,121 @@
+package com.seafile.seadroid2.ui.media.image_preview2;
+
+import android.content.Context;
+import android.os.Handler;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.blankj.utilcode.util.ScreenUtils;
+import com.seafile.seadroid2.R;
+import com.seafile.seadroid2.framework.util.SLogs;
+
+public class CenterScaleXYRecyclerViewScrollListener extends RecyclerView.OnScrollListener {
+
+ private float maxScale = 1.2f;
+ private float minScale = 1.0f;
+
+ private final int centerX;
+ private final float maxDistance;// 12dp is (view width / 2) + margin(2dp)
+ private final int itemWidth, itemMargin;
+
+ private LinearLayoutManager layoutManager;
+
+ private final Handler handler = new Handler();
+ private boolean isPendingUpdate = false;
+
+ public CenterScaleXYRecyclerViewScrollListener(Context context) {
+ itemWidth = context.getResources().getDimensionPixelSize(R.dimen.carousel_item_width);
+ itemMargin = context.getResources().getDimensionPixelSize(R.dimen.carousel_item_margin);
+ maxDistance = (float) itemWidth / 2 + itemMargin;
+ centerX = ScreenUtils.getAppScreenWidth() / 2;
+ }
+
+ public CenterScaleXYRecyclerViewScrollListener(Context context, float maxScale, float minScale) {
+ this.maxScale = maxScale;
+ this.minScale = minScale;
+
+ itemWidth = context.getResources().getDimensionPixelSize(R.dimen.carousel_item_width);
+ itemMargin = context.getResources().getDimensionPixelSize(R.dimen.carousel_item_margin);
+ maxDistance = (float) itemWidth / 2 + itemMargin;
+ centerX = ScreenUtils.getAppScreenWidth() / 2;
+
+ }
+
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ adjustChildScale(recyclerView, 0); // 滚动停止时更新缩放状态
+ }
+ }
+
+ @Override
+ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+ super.onScrolled(recyclerView, dx, dy);
+// if (isPendingUpdate) return;
+// isPendingUpdate = true;
+
+ adjustChildScale(recyclerView, dx);
+
+// handler.postDelayed(() -> {
+// adjustChildScale(recyclerView, dx);
+//
+// isPendingUpdate = false;
+// }, 25);
+ }
+
+ private void adjustChildScale(RecyclerView recyclerView, int dx) {
+ if (layoutManager == null) {
+ layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
+ }
+
+ if (layoutManager == null) {
+ throw new IllegalStateException("LayoutManager is null");
+ }
+
+ int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
+ int lastVisiblePosition = layoutManager.findLastVisibleItemPosition();
+ if (firstVisiblePosition == RecyclerView.NO_POSITION || lastVisiblePosition == RecyclerView.NO_POSITION) {
+ return; // 防止意外状态
+ }
+
+ for (int i = firstVisiblePosition; i <= lastVisiblePosition; i++) {
+ View view = layoutManager.findViewByPosition(i);
+ if (view == null) {
+ continue;
+ }
+
+ int left = view.getLeft();
+ if (left == 0) {
+ continue;
+ }
+
+ // 计算每个 item 的中心点与屏幕中心的距离
+ int viewCenterX = left + itemWidth / 2;
+
+ float distanceFromCenter = Math.abs(centerX - viewCenterX);
+
+ // 1.2f - 4/60 * 0.2f
+ float scale = maxScale - (distanceFromCenter / maxDistance) * (maxScale - minScale);
+ scale = Math.max(minScale, scale); // 确保不小于最小缩放比例
+
+ if (i == firstVisiblePosition) {
+ SLogs.d("firstVisiblePosition: " + firstVisiblePosition + ", itemWidth: " + itemWidth + ", left: " + left + ", viewCenterX: " + viewCenterX + ", centerX: " + centerX + ", distanceFromCenter: " + distanceFromCenter + ", scale: " + scale);
+ }
+
+ float alpha = 1.0f - (distanceFromCenter / maxDistance) * 0.8f; // 透明度范围 1.0 到 0.6
+ alpha = Math.max(0.8f, alpha);
+ view.setAlpha(alpha);
+
+ // 仅当 scale 有变化时才更新
+ if (Math.abs(view.getScaleX() - scale) > 0.01f) {
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
new file mode 100644
index 000000000..894db1a58
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
@@ -0,0 +1,679 @@
+package com.seafile.seadroid2.ui.media.image_preview2;
+
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Scroller;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
+import androidx.core.text.TextUtilsCompat;
+import androidx.core.view.ViewCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.LinearSmoothScroller;
+import androidx.recyclerview.widget.LinearSnapHelper;
+import androidx.recyclerview.widget.OrientationHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.Locale;
+
+/**
+ * A {@link LinearSnapHelper} that allows snapping to an edge or to the center.
+ *
+ * Possible snap positions:
+ * {@link Gravity#START}, {@link Gravity#TOP}, {@link Gravity#END}, {@link Gravity#BOTTOM},
+ * {@link Gravity#CENTER}.
+ *
+ * To customize the scroll duration, use {@link GravitySnapHelper#setScrollMsPerInch(float)}.
+ *
+ * To customize the maximum scroll distance during flings,
+ * use {@link GravitySnapHelper#setMaxFlingSizeFraction(float)}
+ * or {@link GravitySnapHelper#setMaxFlingDistance(int)}
+ */
+public class GravitySnapHelper extends LinearSnapHelper {
+
+ public static final int FLING_DISTANCE_DISABLE = -1;
+ public static final float FLING_SIZE_FRACTION_DISABLE = -1f;
+ private int gravity;
+ private boolean isRtl;
+ private boolean snapLastItem;
+ private int nextSnapPosition;
+ private boolean isScrolling = false;
+ private boolean snapToPadding = false;
+ private float scrollMsPerInch = 100f;
+ private int maxFlingDistance = FLING_DISTANCE_DISABLE;
+ private float maxFlingSizeFraction = FLING_SIZE_FRACTION_DISABLE;
+ private OrientationHelper verticalHelper;
+ private OrientationHelper horizontalHelper;
+ private SnapListener listener;
+ private RecyclerView recyclerView;
+ private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ GravitySnapHelper.this.onScrollStateChanged(newState);
+ }
+ };
+
+ public GravitySnapHelper(int gravity) {
+ this(gravity, false, null);
+ }
+
+ public GravitySnapHelper(int gravity, @NonNull SnapListener snapListener) {
+ this(gravity, false, snapListener);
+ }
+
+ public GravitySnapHelper(int gravity, boolean enableSnapLastItem) {
+ this(gravity, enableSnapLastItem, null);
+ }
+
+ public GravitySnapHelper(int gravity, boolean enableSnapLastItem,
+ @Nullable SnapListener snapListener) {
+ if (gravity != Gravity.START
+ && gravity != Gravity.END
+ && gravity != Gravity.BOTTOM
+ && gravity != Gravity.TOP
+ && gravity != Gravity.CENTER) {
+ throw new IllegalArgumentException("Invalid gravity value. Use START " +
+ "| END | BOTTOM | TOP | CENTER constants");
+ }
+ this.snapLastItem = enableSnapLastItem;
+ this.gravity = gravity;
+ this.listener = snapListener;
+ }
+
+ @Override
+ public void attachToRecyclerView(@Nullable RecyclerView recyclerView)
+ throws IllegalStateException {
+ if (this.recyclerView != null) {
+ this.recyclerView.removeOnScrollListener(scrollListener);
+ }
+ if (recyclerView != null) {
+ recyclerView.setOnFlingListener(null);
+ if (gravity == Gravity.START || gravity == Gravity.END) {
+ isRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
+ == ViewCompat.LAYOUT_DIRECTION_RTL;
+ }
+ recyclerView.addOnScrollListener(scrollListener);
+ this.recyclerView = recyclerView;
+ } else {
+ this.recyclerView = null;
+ }
+ super.attachToRecyclerView(recyclerView);
+ }
+
+ @Override
+ @Nullable
+ public View findSnapView(@NonNull RecyclerView.LayoutManager lm) {
+ return findSnapView(lm, true);
+ }
+
+ @Nullable
+ public View findSnapView(@NonNull RecyclerView.LayoutManager lm, boolean checkEdgeOfList) {
+ View snapView = null;
+
+ switch (gravity) {
+ case Gravity.START:
+ snapView = findView(lm, getHorizontalHelper(lm), Gravity.START, checkEdgeOfList);
+ break;
+ case Gravity.END:
+ snapView = findView(lm, getHorizontalHelper(lm), Gravity.END, checkEdgeOfList);
+ break;
+ case Gravity.TOP:
+ snapView = findView(lm, getVerticalHelper(lm), Gravity.START, checkEdgeOfList);
+ break;
+ case Gravity.BOTTOM:
+ snapView = findView(lm, getVerticalHelper(lm), Gravity.END, checkEdgeOfList);
+ break;
+ case Gravity.CENTER:
+ if (lm.canScrollHorizontally()) {
+ snapView = findView(lm, getHorizontalHelper(lm), Gravity.CENTER,
+ checkEdgeOfList);
+ } else {
+ snapView = findView(lm, getVerticalHelper(lm), Gravity.CENTER,
+ checkEdgeOfList);
+ }
+ break;
+ }
+ if (snapView != null) {
+ nextSnapPosition = recyclerView.getChildAdapterPosition(snapView);
+ } else {
+ nextSnapPosition = RecyclerView.NO_POSITION;
+ }
+ return snapView;
+ }
+
+ @Override
+ @NonNull
+ public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,
+ @NonNull View targetView) {
+ if (gravity == Gravity.CENTER) {
+ //noinspection ConstantConditions
+ return super.calculateDistanceToFinalSnap(layoutManager, targetView);
+ }
+
+ int[] out = new int[2];
+
+ if (!(layoutManager instanceof LinearLayoutManager)) {
+ return out;
+ }
+
+ LinearLayoutManager lm = (LinearLayoutManager) layoutManager;
+
+ if (lm.canScrollHorizontally()) {
+ if ((isRtl && gravity == Gravity.END) || (!isRtl && gravity == Gravity.START)) {
+ out[0] = getDistanceToStart(targetView, getHorizontalHelper(lm));
+ } else {
+ out[0] = getDistanceToEnd(targetView, getHorizontalHelper(lm));
+ }
+ } else if (lm.canScrollVertically()) {
+ if (gravity == Gravity.TOP) {
+ out[1] = getDistanceToStart(targetView, getVerticalHelper(lm));
+ } else {
+ out[1] = getDistanceToEnd(targetView, getVerticalHelper(lm));
+ }
+ }
+ return out;
+ }
+
+ @Override
+ @NonNull
+ public int[] calculateScrollDistance(int velocityX, int velocityY) {
+ if (recyclerView == null
+ || (verticalHelper == null && horizontalHelper == null)
+ || (maxFlingDistance == FLING_DISTANCE_DISABLE
+ && maxFlingSizeFraction == FLING_SIZE_FRACTION_DISABLE)) {
+ return super.calculateScrollDistance(velocityX, velocityY);
+ }
+ final int[] out = new int[2];
+ Scroller scroller = new Scroller(recyclerView.getContext(),
+ new DecelerateInterpolator());
+ int maxDistance = getFlingDistance();
+ scroller.fling(0, 0, velocityX, velocityY,
+ -maxDistance, maxDistance,
+ -maxDistance, maxDistance);
+ out[0] = scroller.getFinalX();
+ out[1] = scroller.getFinalY();
+ return out;
+ }
+
+ @Nullable
+ @Override
+ public RecyclerView.SmoothScroller createScroller(RecyclerView.LayoutManager layoutManager) {
+ if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)
+ || recyclerView == null) {
+ return null;
+ }
+ return new LinearSmoothScroller(recyclerView.getContext()) {
+ @Override
+ protected void onTargetFound(View targetView,
+ RecyclerView.State state,
+ Action action) {
+ if (recyclerView == null || recyclerView.getLayoutManager() == null) {
+ // The associated RecyclerView has been removed so there is no action to take.
+ return;
+ }
+ 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)));
+ if (time > 0) {
+ action.update(dx, dy, time, mDecelerateInterpolator);
+ }
+ }
+
+ @Override
+ protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
+ return scrollMsPerInch / displayMetrics.densityDpi;
+ }
+ };
+ }
+
+ /**
+ * Sets a {@link SnapListener} to listen for snap events
+ *
+ * @param listener a {@link SnapListener} that'll receive snap events or null to clear it
+ */
+ public void setSnapListener(@Nullable SnapListener listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * Changes the gravity of this {@link GravitySnapHelper}
+ * and dispatches a smooth scroll for the new snap position.
+ *
+ * @param newGravity one of the following: {@link Gravity#START}, {@link Gravity#TOP},
+ * {@link Gravity#END}, {@link Gravity#BOTTOM}, {@link Gravity#CENTER}
+ * @param smooth true if we should smooth scroll to new edge, false otherwise
+ */
+ public void setGravity(int newGravity, Boolean smooth) {
+ if (this.gravity != newGravity) {
+ this.gravity = newGravity;
+ updateSnap(smooth, false);
+ }
+ }
+
+ /**
+ * Updates the current view to be snapped
+ *
+ * @param smooth true if we should smooth scroll, false otherwise
+ * @param checkEdgeOfList true if we should check if we're at an edge of the list
+ * and snap according to {@link GravitySnapHelper#getSnapLastItem()},
+ * or false to force snapping to the nearest view
+ */
+ public void updateSnap(Boolean smooth, Boolean checkEdgeOfList) {
+ if (recyclerView == null || recyclerView.getLayoutManager() == null) {
+ return;
+ }
+ final RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
+ View snapView = findSnapView(lm, checkEdgeOfList);
+ if (snapView != null) {
+ int[] out = calculateDistanceToFinalSnap(lm, snapView);
+ if (smooth) {
+ recyclerView.smoothScrollBy(out[0], out[1]);
+ } else {
+ recyclerView.scrollBy(out[0], out[1]);
+ }
+ }
+ }
+
+ /**
+ * This method will only work if there's a ViewHolder for the given position.
+ *
+ * @return true if scroll was successful, false otherwise
+ */
+ public boolean scrollToPosition(int position) {
+ if (position == RecyclerView.NO_POSITION) {
+ return false;
+ }
+ return scrollTo(position, false);
+ }
+
+ /**
+ * Unlike {@link GravitySnapHelper#scrollToPosition(int)},
+ * this method will generally always find a snap view if the position is valid.
+ *
+ * The smooth scroller from {@link GravitySnapHelper#createScroller(RecyclerView.LayoutManager)}
+ * will be used, and so will {@link GravitySnapHelper#scrollMsPerInch} for the scroll velocity
+ *
+ * @return true if scroll was successful, false otherwise
+ */
+ public boolean smoothScrollToPosition(int position) {
+ if (position == RecyclerView.NO_POSITION) {
+ return false;
+ }
+ return scrollTo(position, true);
+ }
+
+ /**
+ * Get the current gravity being applied
+ *
+ * @return one of the following: {@link Gravity#START}, {@link Gravity#TOP}, {@link Gravity#END},
+ * {@link Gravity#BOTTOM}, {@link Gravity#CENTER}
+ */
+ public int getGravity() {
+ return this.gravity;
+ }
+
+ /**
+ * Changes the gravity of this {@link GravitySnapHelper}
+ * and dispatches a smooth scroll for the new snap position.
+ *
+ * @param newGravity one of the following: {@link Gravity#START}, {@link Gravity#TOP},
+ * {@link Gravity#END}, {@link Gravity#BOTTOM}, {@link Gravity#CENTER}
+ */
+ public void setGravity(int newGravity) {
+ setGravity(newGravity, true);
+ }
+
+ /**
+ * @return true if this SnapHelper should snap to the last item
+ */
+ public boolean getSnapLastItem() {
+ return snapLastItem;
+ }
+
+ /**
+ * Enable snapping of the last item that's snappable.
+ * The default value is false, because you can't see the last item completely
+ * if this is enabled.
+ *
+ * @param snap true if you want to enable snapping of the last snappable item
+ */
+ public void setSnapLastItem(boolean snap) {
+ snapLastItem = snap;
+ }
+
+ /**
+ * @return last distance set through {@link GravitySnapHelper#setMaxFlingDistance(int)}
+ * or {@link GravitySnapHelper#FLING_DISTANCE_DISABLE} if we're not limiting the fling distance
+ */
+ public int getMaxFlingDistance() {
+ return maxFlingDistance;
+ }
+
+ /**
+ * Changes the max fling distance in absolute values.
+ *
+ * @param distance max fling distance in pixels
+ * or {@link GravitySnapHelper#FLING_DISTANCE_DISABLE}
+ * to disable fling limits
+ */
+ public void setMaxFlingDistance(@Px int distance) {
+ maxFlingDistance = distance;
+ maxFlingSizeFraction = FLING_SIZE_FRACTION_DISABLE;
+ }
+
+ /**
+ * @return last distance set through {@link GravitySnapHelper#setMaxFlingSizeFraction(float)}
+ * or {@link GravitySnapHelper#FLING_SIZE_FRACTION_DISABLE}
+ * if we're not limiting the fling distance
+ */
+ public float getMaxFlingSizeFraction() {
+ return maxFlingSizeFraction;
+ }
+
+ /**
+ * Changes the max fling distance depending on the available size of the RecyclerView.
+ *
+ * Example: if you pass 0.5f and the RecyclerView measures 600dp,
+ * the max fling distance will be 300dp.
+ *
+ * @param fraction size fraction to be used for the max fling distance
+ * or {@link GravitySnapHelper#FLING_SIZE_FRACTION_DISABLE}
+ * to disable fling limits
+ */
+ public void setMaxFlingSizeFraction(float fraction) {
+ maxFlingDistance = FLING_DISTANCE_DISABLE;
+ maxFlingSizeFraction = fraction;
+ }
+
+ /**
+ * @return last scroll speed set through {@link GravitySnapHelper#setScrollMsPerInch(float)}
+ * or 100f
+ */
+ public float getScrollMsPerInch() {
+ return scrollMsPerInch;
+ }
+
+ /**
+ * Sets the scroll duration in ms per inch.
+ *
+ * Default value is 100.0f
+ *
+ * This value will be used in
+ * {@link GravitySnapHelper#createScroller(RecyclerView.LayoutManager)}
+ *
+ * @param ms scroll duration in ms per inch
+ */
+ public void setScrollMsPerInch(float ms) {
+ scrollMsPerInch = ms;
+ }
+
+ /**
+ * @return true if this SnapHelper should snap to the padding. Defaults to false.
+ */
+ public boolean getSnapToPadding() {
+ return snapToPadding;
+ }
+
+ /**
+ * If true, GravitySnapHelper will snap to the gravity edge
+ * plus any amount of padding that was set in the RecyclerView.
+ *
+ * The default value is false.
+ *
+ * @param snapToPadding true if you want to snap to the padding
+ */
+ public void setSnapToPadding(boolean snapToPadding) {
+ this.snapToPadding = snapToPadding;
+ }
+
+ /**
+ * @return the position of the current view that's snapped
+ * or {@link RecyclerView#NO_POSITION} in case there's none.
+ */
+ public int getCurrentSnappedPosition() {
+ if (recyclerView != null && recyclerView.getLayoutManager() != null) {
+ View snappedView = findSnapView(recyclerView.getLayoutManager());
+ if (snappedView != null) {
+ return recyclerView.getChildAdapterPosition(snappedView);
+ }
+ }
+ return RecyclerView.NO_POSITION;
+ }
+
+ private int getFlingDistance() {
+ if (maxFlingSizeFraction != FLING_SIZE_FRACTION_DISABLE) {
+ if (verticalHelper != null) {
+ return (int) (recyclerView.getHeight() * maxFlingSizeFraction);
+ } else if (horizontalHelper != null) {
+ return (int) (recyclerView.getWidth() * maxFlingSizeFraction);
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ } else if (maxFlingDistance != FLING_DISTANCE_DISABLE) {
+ return maxFlingDistance;
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+
+ /**
+ * @return true if the scroll will snap to a view, false otherwise
+ */
+ private boolean scrollTo(int position, boolean smooth) {
+ if (recyclerView.getLayoutManager() != null) {
+ if (smooth) {
+ 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);
+ if (viewHolder != null) {
+ int[] distances = calculateDistanceToFinalSnap(recyclerView.getLayoutManager(),
+ viewHolder.itemView);
+ recyclerView.scrollBy(distances[0], distances[1]);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int getDistanceToStart(View targetView, @NonNull OrientationHelper helper) {
+ int distance;
+ // If we don't care about padding, just snap to the start of the view
+ if (!snapToPadding) {
+ int childStart = helper.getDecoratedStart(targetView);
+ if (childStart >= helper.getStartAfterPadding() / 2) {
+ distance = childStart - helper.getStartAfterPadding();
+ } else {
+ distance = childStart;
+ }
+ } else {
+ distance = helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
+ }
+ return distance;
+ }
+
+ private int getDistanceToEnd(View targetView, @NonNull OrientationHelper helper) {
+ int distance;
+
+ if (!snapToPadding) {
+ int childEnd = helper.getDecoratedEnd(targetView);
+ if (childEnd >= helper.getEnd() - (helper.getEnd() - helper.getEndAfterPadding()) / 2) {
+ distance = helper.getDecoratedEnd(targetView) - helper.getEnd();
+ } else {
+ distance = childEnd - helper.getEndAfterPadding();
+ }
+ } else {
+ distance = helper.getDecoratedEnd(targetView) - helper.getEndAfterPadding();
+ }
+
+ return distance;
+ }
+
+ /**
+ * Returns the first view that we should snap to.
+ *
+ * @param layoutManager the RecyclerView's LayoutManager
+ * @param helper orientation helper to calculate view sizes
+ * @param gravity gravity to find the closest view
+ * @return the first view in the LayoutManager to snap to, or null if we shouldn't snap to any
+ */
+ @Nullable
+ private View findView(@NonNull RecyclerView.LayoutManager layoutManager,
+ @NonNull OrientationHelper helper,
+ int gravity,
+ boolean checkEdgeOfList) {
+
+ if (layoutManager.getChildCount() == 0 || !(layoutManager instanceof LinearLayoutManager)) {
+ return null;
+ }
+
+ final LinearLayoutManager lm = (LinearLayoutManager) layoutManager;
+
+ // If we're at an edge of the list, we shouldn't snap
+ // to avoid having the last item not completely visible.
+ if (checkEdgeOfList && (isAtEdgeOfList(lm) && !snapLastItem)) {
+ return null;
+ }
+
+ View edgeView = null;
+ int distanceToTarget = Integer.MAX_VALUE;
+ final int center;
+ if (layoutManager.getClipToPadding()) {
+ center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
+ } else {
+ center = helper.getEnd() / 2;
+ }
+
+ final boolean snapToStart = (gravity == Gravity.START && !isRtl)
+ || (gravity == Gravity.END && isRtl);
+
+ final boolean snapToEnd = (gravity == Gravity.START && isRtl)
+ || (gravity == Gravity.END && !isRtl);
+
+ for (int i = 0; i < lm.getChildCount(); i++) {
+ View currentView = lm.getChildAt(i);
+ int currentViewDistance;
+ if (snapToStart) {
+ if (!snapToPadding) {
+ currentViewDistance = Math.abs(helper.getDecoratedStart(currentView));
+ } else {
+ currentViewDistance = Math.abs(helper.getStartAfterPadding()
+ - helper.getDecoratedStart(currentView));
+ }
+ } else if (snapToEnd) {
+ if (!snapToPadding) {
+ currentViewDistance = Math.abs(helper.getDecoratedEnd(currentView)
+ - helper.getEnd());
+ } else {
+ currentViewDistance = Math.abs(helper.getEndAfterPadding()
+ - helper.getDecoratedEnd(currentView));
+ }
+ } else {
+ currentViewDistance = Math.abs(helper.getDecoratedStart(currentView)
+ + (helper.getDecoratedMeasurement(currentView) / 2) - center);
+ }
+ if (currentViewDistance < distanceToTarget) {
+ distanceToTarget = currentViewDistance;
+ edgeView = currentView;
+ }
+ }
+ return edgeView;
+ }
+
+ private boolean isAtEdgeOfList(LinearLayoutManager lm) {
+ if ((!lm.getReverseLayout() && gravity == Gravity.START)
+ || (lm.getReverseLayout() && gravity == Gravity.END)
+ || (!lm.getReverseLayout() && gravity == Gravity.TOP)
+ || (lm.getReverseLayout() && gravity == Gravity.BOTTOM)) {
+ return lm.findLastCompletelyVisibleItemPosition() == lm.getItemCount() - 1;
+ } else if (gravity == Gravity.CENTER) {
+ return lm.findFirstCompletelyVisibleItemPosition() == 0
+ || lm.findLastCompletelyVisibleItemPosition() == lm.getItemCount() - 1;
+ } else {
+ return lm.findFirstCompletelyVisibleItemPosition() == 0;
+ }
+ }
+
+ /**
+ * Dispatches a {@link SnapListener#onSnap(int)} event if the snapped position
+ * is different than {@link RecyclerView#NO_POSITION}.
+ *
+ * When {@link GravitySnapHelper#findSnapView(RecyclerView.LayoutManager)} returns null,
+ * {@link GravitySnapHelper#dispatchSnapChangeWhenPositionIsUnknown()} is called
+ *
+ * @param newState the new RecyclerView scroll state
+ */
+ private void onScrollStateChanged(int newState) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE && listener != null) {
+ if (isScrolling) {
+ if (nextSnapPosition != RecyclerView.NO_POSITION) {
+ listener.onSnap(nextSnapPosition);
+ } else {
+ dispatchSnapChangeWhenPositionIsUnknown();
+ }
+ }
+ }
+ isScrolling = newState != RecyclerView.SCROLL_STATE_IDLE;
+ }
+
+ /**
+ * Calls {@link GravitySnapHelper#findSnapView(RecyclerView.LayoutManager, boolean)}
+ * without the check for the edge of the list.
+ *
+ * This makes sure that a position is reported in {@link SnapListener#onSnap(int)}
+ */
+ private void dispatchSnapChangeWhenPositionIsUnknown() {
+ RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+ if (layoutManager == null) {
+ return;
+ }
+ View snapView = findSnapView(layoutManager, false);
+ if (snapView == null) {
+ return;
+ }
+ int snapPosition = recyclerView.getChildAdapterPosition(snapView);
+ if (snapPosition != RecyclerView.NO_POSITION) {
+ listener.onSnap(snapPosition);
+ }
+ }
+
+ private OrientationHelper getVerticalHelper(RecyclerView.LayoutManager layoutManager) {
+ if (verticalHelper == null || verticalHelper.getLayoutManager() != layoutManager) {
+ verticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
+ }
+ return verticalHelper;
+ }
+
+ private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {
+ if (horizontalHelper == null || horizontalHelper.getLayoutManager() != layoutManager) {
+ horizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
+ }
+ return horizontalHelper;
+ }
+
+ /**
+ * A listener that's called when the {@link RecyclerView} used by {@link GravitySnapHelper}
+ * changes its scroll state to {@link RecyclerView#SCROLL_STATE_IDLE}
+ * and there's a valid snap position.
+ */
+ public interface SnapListener {
+ /**
+ * @param position last position snapped to
+ */
+ void onSnap(int position);
+ }
+
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt
new file mode 100644
index 000000000..c55356299
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt
@@ -0,0 +1,62 @@
+package com.seafile.seadroid2.ui.media.image_preview2
+
+import android.graphics.Rect
+import android.view.View
+import androidx.annotation.Px
+import androidx.recyclerview.widget.RecyclerView
+
+class LinearEdgeDecoration(
+ @Px private val startPadding: Int,
+ @Px private val endPadding: Int = startPadding,
+ private val orientation: Int = RecyclerView.VERTICAL,
+ private val inverted: Boolean = false
+) : RecyclerView.ItemDecoration() {
+
+ override fun getItemOffsets(
+ outRect: Rect, view: View, parent: RecyclerView,
+ state: RecyclerView.State
+ ) {
+ super.getItemOffsets(outRect, view, parent, state)
+
+ val layoutManager: RecyclerView.LayoutManager = parent.layoutManager!!
+ val layoutParams = view.layoutParams as RecyclerView.LayoutParams
+ val position = layoutParams.viewAdapterPosition
+ val itemCount = layoutManager.itemCount
+
+ if (position == RecyclerView.NO_POSITION || itemCount == 0
+ || (position > 0 && position < itemCount - 1)
+ ) {
+ return
+ }
+
+ if (orientation == RecyclerView.HORIZONTAL) {
+ if (position == 0) {
+ if (!inverted) {
+ outRect.left = startPadding
+ } else {
+ outRect.right = startPadding
+ }
+ } else if (position == itemCount - 1) {
+ if (!inverted) {
+ outRect.right = endPadding
+ } else {
+ outRect.left = endPadding
+ }
+ }
+ } else {
+ if (position == 0) {
+ if (!inverted) {
+ outRect.top = startPadding
+ } else {
+ outRect.bottom = startPadding
+ }
+ } else if (position == itemCount - 1) {
+ if (!inverted) {
+ outRect.bottom = endPadding
+ } else {
+ outRect.top = endPadding
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
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 33fb7f094..afb109773 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
@@ -89,6 +89,7 @@
import com.seafile.seadroid2.ui.main.MainViewModel;
import com.seafile.seadroid2.ui.markdown.MarkdownActivity;
import com.seafile.seadroid2.ui.media.image_preview.ImagePreviewActivity;
+import com.seafile.seadroid2.ui.media.image_preview2.CarouselImagePreviewActivity;
import com.seafile.seadroid2.ui.media.player.exoplayer.CustomExoVideoPlayerActivity;
import com.seafile.seadroid2.ui.sdoc.SDocWebViewActivity;
import com.seafile.seadroid2.ui.search.SearchViewModel;
@@ -96,12 +97,10 @@
import com.seafile.seadroid2.view.TipsViews;
import java.io.File;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import io.reactivex.functions.Consumer;
@@ -430,7 +429,7 @@ private List getDisableMenuIds() {
if (baseModel instanceof RepoModel m) {
} else if (baseModel instanceof DirentModel m) {
- if (m.isDir()){
+ if (m.isDir()) {
return CollectionUtils.newArrayList(R.id.upload);
}
}
@@ -901,7 +900,7 @@ private void navTo(BaseModel model) {
}
} else if (model instanceof SearchModel searchModel) {
- DirentModel direntModel = SearchModel.converterThis2DirentModel(searchModel);
+ DirentModel direntModel = SearchModel.convert2DirentModel(searchModel);
if (direntModel.isDir()) {
String repoId = getNavContext().getRepoModel().repo_id;
@@ -1179,7 +1178,7 @@ private void open(DirentModel dirent) {
// because pic thumbnail under encrypted repo was not supported at the server side
if (Utils.isViewableImage(fileName) && !repoModel.encrypted) {
- Intent getIntent = ImagePreviewActivity.startThisFromRepo(requireContext(), dirent);
+ Intent getIntent = CarouselImagePreviewActivity.startThisFromRepo(requireContext(), dirent);
imagePreviewActivityLauncher.launch(getIntent);
return;
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 daca7b503..75319cc0b 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
@@ -170,7 +170,7 @@ private void loadDirentsFromLocalWithGalleryViewType(Account account, NavContext
String repoId = context.getRepoModel().repo_id;
String parentDir = context.getNavPath();
- Single> direntDBSingle = AppDatabase.getInstance().direntDao().getListByParentPath(repoId, parentDir);
+ Single> direntDBSingle = AppDatabase.getInstance().direntDao().getListByParentPathAsync(repoId, parentDir);
addSingleDisposable(direntDBSingle, new Consumer>() {
@Override
public void accept(List direntModels) throws Exception {
@@ -198,7 +198,7 @@ private void loadDirentsFromLocal(Account account, NavContext context) {
String repoId = context.getRepoModel().repo_id;
String parentDir = context.getNavPath();
- Single> direntDBSingle = AppDatabase.getInstance().direntDao().getListByParentPath(repoId, parentDir);
+ Single> direntDBSingle = AppDatabase.getInstance().direntDao().getListByParentPathAsync(repoId, parentDir);
Single> curParentDownloadedList = AppDatabase.getInstance().fileTransferDAO().getDownloadedListByParentAsync(repoId, parentDir);
Single> resultSingle = Single.zip(direntDBSingle, curParentDownloadedList, new BiFunction, List, List>() {
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 39cf80e1e..9644fc6f8 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
@@ -24,6 +24,7 @@
import com.blankj.utilcode.util.ToastUtils;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
+import com.seafile.seadroid2.annotation.Todo;
import com.seafile.seadroid2.annotation.Unstable;
import com.seafile.seadroid2.databinding.ActivitySeaWebviewProBinding;
import com.seafile.seadroid2.databinding.ToolbarActionbarProgressBarBinding;
@@ -41,7 +42,7 @@
import com.seafile.seadroid2.view.webview.PreloadWebView;
import com.seafile.seadroid2.view.webview.SeaWebView;
-@Unstable
+@Todo
public class SDocWebViewActivity extends BaseActivityWithVM {
private ActivitySeaWebviewProBinding binding;
private ToolbarActionbarProgressBarBinding toolBinding;
@@ -57,7 +58,7 @@ public class SDocWebViewActivity extends BaseActivityWithVM {
* not support, please use SeaWebViewActivity instead
*/
public static void openSdoc(Context context, String repoName, String repoID, String path) {
- Intent intent = new Intent(context, SeaWebViewActivity.class);
+ Intent intent = new Intent(context, SDocWebViewActivity.class);
intent.putExtra("previewType", WebViewPreviewType.SDOC.name());
intent.putExtra("repoName", repoName);
intent.putExtra("repoID", repoID);
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/selector/ObjSelectorActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/selector/ObjSelectorActivity.java
index 0bd581ed2..453fa45c5 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/selector/ObjSelectorActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/selector/ObjSelectorActivity.java
@@ -273,25 +273,45 @@ public void onResultData(RepoModel uRepoModel) {
}
private void checkCurrentPathHasWritePermission(java.util.function.Consumer consumer) {
- DirentModel direntModel = mNavContext.getTopDirentModel();
- if (!direntModel.isCustomPermission()) {
- consumer.accept(direntModel.hasWritePermission());
+ BaseModel model = mNavContext.getTopModel();
+
+ String repo_id = null;
+ int pNum = 0;
+ if (model instanceof RepoModel m) {
+ if (!m.isCustomPermission()) {
+ consumer.accept(m.hasWritePermission());
+ return;
+ } else {
+ repo_id = m.repo_id;
+ pNum = m.getCustomPermissionNum();
+ }
+ } else if (model instanceof DirentModel m) {
+ if (!m.isCustomPermission()) {
+ consumer.accept(m.hasWritePermission());
+ return;
+ } else {
+ repo_id = m.repo_id;
+ pNum = m.getCustomPermissionNum();
+ }
} else {
- viewModel.getPermissionFromLocal(direntModel.repo_id, direntModel.getCustomPermissionNum(), new Consumer() {
- @Override
- public void accept(PermissionEntity entity) throws Exception {
- consumer.accept(entity != null && entity.create);
- }
- });
+ consumer.accept(false);
+ return;
}
- }
+ viewModel.getPermissionFromLocal(repo_id, pNum, new Consumer() {
+ @Override
+ public void accept(PermissionEntity entity) throws Exception {
+ consumer.accept(entity != null && entity.create);
+ }
+ });
+ }
private void showNewDirDialog() {
if (!mNavContext.inRepo()) {
ToastUtils.showLong(R.string.choose_a_library);
return;
}
+
checkCurrentPathHasWritePermission(new java.util.function.Consumer() {
@Override
public void accept(Boolean aBoolean) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferActivity.java
index a393ca992..502beadf6 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferActivity.java
@@ -165,26 +165,13 @@ public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- // MenuItem cancel = menu.findItem(R.id.cancel_transfer_tasks);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
@Override
public boolean onMenuItemClick(MenuItem item) {
int whichTab = binding.slidingTabs.getSelectedTabPosition();
- if (item.getItemId() == R.id.cancel_transfer_tasks) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ } else if (item.getItemId() == R.id.cancel_transfer_tasks) {
if (whichTab == 0) {
getDownloadFragment().cancelAllTasks();
} else {
diff --git a/app/src/main/res/layout/activity_carousel_image_preview.xml b/app/src/main/res/layout/activity_carousel_image_preview.xml
new file mode 100644
index 000000000..2d2bccad4
--- /dev/null
+++ b/app/src/main/res/layout/activity_carousel_image_preview.xml
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_photo_view.xml b/app/src/main/res/layout/fragment_photo_view.xml
index d21477f9e..76e9c805b 100644
--- a/app/src/main/res/layout/fragment_photo_view.xml
+++ b/app/src/main/res/layout/fragment_photo_view.xml
@@ -1,5 +1,6 @@
diff --git a/app/src/main/res/layout/item_carousel_item_vertical.xml b/app/src/main/res/layout/item_carousel_item_vertical.xml
index 9b3620380..5afe7c027 100644
--- a/app/src/main/res/layout/item_carousel_item_vertical.xml
+++ b/app/src/main/res/layout/item_carousel_item_vertical.xml
@@ -1,33 +1,20 @@
-
-
-
-
-
+
+
diff --git a/app/src/main/res/menu/menu_image_list_preview.xml b/app/src/main/res/menu/menu_image_list_preview.xml
new file mode 100644
index 000000000..043a5241c
--- /dev/null
+++ b/app/src/main/res/menu/menu_image_list_preview.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 605a4e8c4..e7d6739ab 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -60,6 +60,7 @@
@color/material_grey_100
@color/material_grey_900
@color/material_grey_900
+ @color/material_grey_100_translucent
@color/material_grey_599
diff --git a/app/src/main/res/values/colors_material.xml b/app/src/main/res/values/colors_material.xml
index 1651cea50..872410610 100644
--- a/app/src/main/res/values/colors_material.xml
+++ b/app/src/main/res/values/colors_material.xml
@@ -261,6 +261,7 @@
#FAFAFA
#F8F8F8
#F5F5F5
+ #88F5F5F5
#F3F3F3
#EEEEEE
#E0E0E0
@@ -275,6 +276,7 @@
#222222
#191919
+ #00191919
#111111
#ECEFF1
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 4104e264e..476dcf67e 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -190,4 +190,8 @@
22sp
292.6dp
+
+ 20dp
+ 40dp
+ 2dp
\ No newline at end of file
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index cc9727188..8f4cae6eb 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -13,4 +13,6 @@
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ed9ae39c8..49a3b6e6d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -664,6 +664,7 @@
Last modified
Ascending
Folders first
+ Detail
Size
diff --git a/build_count.txt b/build_count.txt
index d99e90eb9..8580e7b68 100644
--- a/build_count.txt
+++ b/build_count.txt
@@ -1 +1 @@
-29
\ No newline at end of file
+30
\ No newline at end of file
From e3f98912506d5032c6524418f9ea8d774088b728 Mon Sep 17 00:00:00 2001
From: zhwanng <48609908+zhwanng@users.noreply.github.com>
Date: Mon, 16 Dec 2024 14:12:02 +0800
Subject: [PATCH 03/17] new pages
new Docs Comment page
new Sdoc preview page
---
app/build.gradle | 24 +-
app/src/main/AndroidManifest.xml | 2 +-
.../seadroid2/SeadroidApplication.java | 3 +-
.../seadroid2/account/AccountUtils.java | 1 +
.../account/SupportAccountManager.java | 4 +
.../seadroid2/config/GlideLoadConfig.java | 30 +-
.../config/WebViewActionConstant.java | 19 +
.../framework/data/model/WebRouteModel.java | 11 +
.../DocsCommentModel.java} | 12 +-
.../docs_comment/DocsCommentWrapperModel.java | 5 +
.../DocsCommentsWrapperModel.java | 7 +
.../docs_comment/DocsUploadResultModel.java | 7 +
...cDetailModel.java => FileDetailModel.java} | 16 +-
...Model.java => FileProfileConfigModel.java} | 8 +-
...Model.java => FileRecordWrapperModel.java} | 16 +-
.../{SDocModel.java => OutlineItemModel.java} | 4 +-
.../data/model/sdoc/RecordResultModel.java | 3 +
.../model/sdoc/SDocCommentWrapperModel.java | 7 -
...odel.java => SDocOutlineWrapperModel.java} | 4 +-
.../framework/http/BaseOkHttpClient.java | 13 +-
.../seadroid2/framework/http/HttpIO.java | 11 +-
.../framework/http/SafeOkHttpClient.java | 38 +-
.../framework/util/ContentResolvers.java | 55 ++
.../seadroid2/framework/util/StringUtils.java | 45 +-
.../worker/upload/BaseUploadWorker.java | 26 +-
.../seadroid2/preferences/Settings.java | 10 +-
.../seafile/seadroid2/ssl/CertsManager.java | 19 +-
.../seadroid2/ssl/SSLTrustManager.java | 1 +
.../ui/account/AccountViewModel.java | 9 +-
.../account/SeafileAuthenticatorActivity.java | 1 -
.../ui/activities/AllActivitiesFragment.java | 4 +-
.../ui/base/BaseMediaSelectorActivity.java | 174 ++++++
.../ui/base/viewmodel/BaseViewModel.java | 15 +-
.../seadroid2/ui/dialog/SslConfirmDialog.java | 4 +-
.../SignOutDialogFragment.java | 2 +
.../viewmodel/NewDirViewModel.java | 4 +-
.../viewmodel/NewRepoViewModel.java | 2 +-
.../viewmodel/PasswordViewModel.java | 2 +-
.../viewmodel/RenameRepoViewModel.java | 6 +-
.../DocsCommentAdapter.java} | 127 +++--
.../DocsCommentUserAdapter.java} | 10 +-
.../DocsCommentUserViewHolder.java} | 6 +-
.../docs_comment/DocsCommentViewHolder.java | 17 +
.../ui/docs_comment/DocsCommentsActivity.java | 330 +++++++++++
.../FileProfileDialog.java} | 73 +--
.../seadroid2/ui/main/MainActivity.java | 5 -
.../media/image_info/FileDetailViewModel.java | 7 +
.../image_preview/ImagePreviewActivity.java | 1 +
.../image_preview/ImagePreviewViewModel.java | 46 +-
.../ui/media/image_preview/PhotoFragment.java | 10 +-
.../media/image_preview2/CarouselAdapter.java | 21 +-
.../CarouselImagePreviewActivity.java | 243 ++++++--
.../CarouselItemViewHolder.java | 37 --
...nterScaleXYRecyclerViewScrollListener.java | 6 +-
.../image_preview2/GravitySnapHelper.java | 7 +-
.../image_preview2/LinearEdgeDecoration.kt | 3 +-
.../image_preview2/PagerSnapBinders.java | 48 ++
.../seadroid2/ui/repo/RepoQuickAdapter.java | 40 +-
.../seadroid2/ui/repo/RepoQuickFragment.java | 3 +-
.../seadroid2/ui/repo/RepoViewModel.java | 2 +-
.../seadroid2/ui/sdoc/DocsCommentService.java | 63 +++
.../ui/sdoc/DocsCommentViewModel.java | 522 ++++++++++++++++++
.../seadroid2/ui/sdoc/SDocService.java | 34 --
.../seadroid2/ui/sdoc/SDocViewModel.java | 223 --------
.../ui/sdoc/SDocWebViewActivity.java | 188 +++++--
.../sdoc/comments/SDocCommentViewHolder.java | 17 -
.../sdoc/comments/SDocCommentsActivity.java | 184 ------
.../sdoc/directory/SDocDirectoryAdapter.java | 59 --
.../ui/sdoc/outline/SDocOutlineAdapter.java | 56 ++
.../ui/sdoc/outline/SDocOutlineDialog.java | 158 ++++++
.../SDocOutlineRemoteDialog.java} | 40 +-
.../seadroid2/ui/search/Search2Activity.java | 13 +-
.../ui/selector/ObjSelectorActivity.java | 20 +-
.../ui/settings/TabSettingsFragment.java | 66 +--
.../ui/star/StarredQuickFragment.java | 12 +-
.../seadroid2/view/HideBottomBehavior.java | 1 +
.../seafile/seadroid2/view/NestedWebView.java | 4 +-
.../view/webview/IWebViewActionStrategy.java | 9 +
.../seadroid2/view/webview/SeaWebView.java | 91 ++-
.../view/webview/SeaWebViewClient.java | 15 +-
.../strategy/AppShowToastStrategy.java | 13 +
.../strategy/AppVersionGetStrategy.java | 11 +
.../webview/strategy/BaseStrategyModel.java | 5 +
.../webview/strategy/PageFinishStrategy.java | 28 +
.../strategy/PageStatusColorSetStrategy.java | 37 ++
.../strategy/PageStatusHeightGetStrategy.java | 12 +
.../webview/strategy/UnsupportedStrategy.java | 15 +
.../widget/SimpleMarkdownParser.java | 130 +++++
.../main/res/drawable/baseline_comment_24.xml | 9 +
.../main/res/drawable/baseline_delete_24.xml | 9 +
.../main/res/drawable/baseline_info_24.xml | 15 +
.../main/res/drawable/baseline_mark_32.xml | 9 +
.../main/res/drawable/baseline_outline_24.xml | 24 +
.../baseline_sdoc_mark_as_resolved_32.xml | 9 +
.../main/res/drawable/baseline_share_24.xml | 9 +
.../res/drawable/baseline_star_filled_24.xml | 9 +
.../res/drawable/baseline_star_outline_24.xml | 6 +-
app/src/main/res/drawable/ic_camera.xml | 9 +
.../res/drawable/shape_solid_ff_radius_8.xml | 2 +-
.../activity_carousel_image_preview.xml | 29 +-
...c_comment.xml => activity_doc_comment.xml} | 19 +-
.../res/layout/activity_sea_webview_pro.xml | 69 +--
...oc_profile.xml => dialog_file_profile.xml} | 10 +
.../main/res/layout/dialog_sdoc_directory.xml | 2 +-
.../layout/item_carousel_item_vertical.xml | 21 +-
...sdoc_comment.xml => item_file_comment.xml} | 60 +-
...oc_directory.xml => item_sdoc_outline.xml} | 3 +-
app/src/main/res/layout/layout_empty.xml | 2 +-
app/src/main/res/layout/layout_image.xml | 3 +-
.../menu/bottom_sheet_camera_album_select.xml | 11 +
.../main/res/menu/bottom_sheet_op_dirent.xml | 2 +-
.../main/res/menu/bottom_sheet_op_repo.xml | 2 +-
.../res/menu/menu_comment_mark_delete.xml | 11 +
.../menu/transfer_list_multi_choice_menu.xml | 2 +-
app/src/main/res/values-night/colors.xml | 2 +
app/src/main/res/values-zh-rCN/strings.xml | 8 +-
app/src/main/res/values/colors.xml | 2 +
app/src/main/res/values/strings.xml | 6 +-
app/src/main/res/xml/prefs_settings.xml | 1 +
build_count.txt | 2 +-
120 files changed, 2942 insertions(+), 1127 deletions(-)
create mode 100644 app/src/main/java/com/seafile/seadroid2/config/WebViewActionConstant.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/data/model/WebRouteModel.java
rename app/src/main/java/com/seafile/seadroid2/framework/data/model/{sdoc/SDocCommentModel.java => docs_comment/DocsCommentModel.java} (70%)
create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentWrapperModel.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentsWrapperModel.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsUploadResultModel.java
rename app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/{SDocDetailModel.java => FileDetailModel.java} (91%)
rename app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/{SDocProfileConfigModel.java => FileProfileConfigModel.java} (78%)
rename app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/{SDocRecordWrapperModel.java => FileRecordWrapperModel.java} (57%)
rename app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/{SDocModel.java => OutlineItemModel.java} (74%)
delete mode 100644 app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentWrapperModel.java
rename app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/{SDocWrapperModel.java => SDocOutlineWrapperModel.java} (67%)
create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/util/ContentResolvers.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/base/BaseMediaSelectorActivity.java
rename app/src/main/java/com/seafile/seadroid2/ui/{sdoc/comments/SDocCommentAdapter.java => docs_comment/DocsCommentAdapter.java} (60%)
rename app/src/main/java/com/seafile/seadroid2/ui/{sdoc/comments/SDocCommentUserAdapter.java => docs_comment/DocsCommentUserAdapter.java} (83%)
rename app/src/main/java/com/seafile/seadroid2/ui/{sdoc/comments/SDocCommentUserViewHolder.java => docs_comment/DocsCommentUserViewHolder.java} (63%)
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewHolder.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentsActivity.java
rename app/src/main/java/com/seafile/seadroid2/ui/{sdoc/profile/SDocProfileDialog.java => file_profile/FileProfileDialog.java} (92%)
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/media/image_info/FileDetailViewModel.java
delete mode 100644 app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/PagerSnapBinders.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentService.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentViewModel.java
delete mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocService.java
delete mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/SDocViewModel.java
delete mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentViewHolder.java
delete mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentsActivity.java
delete mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/directory/SDocDirectoryAdapter.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/outline/SDocOutlineAdapter.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/ui/sdoc/outline/SDocOutlineDialog.java
rename app/src/main/java/com/seafile/seadroid2/ui/sdoc/{directory/SDocDirectoryDialog.java => outline/SDocOutlineRemoteDialog.java} (77%)
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/IWebViewActionStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/AppShowToastStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/AppVersionGetStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/BaseStrategyModel.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/PageFinishStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/PageStatusColorSetStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/PageStatusHeightGetStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/view/webview/strategy/UnsupportedStrategy.java
create mode 100644 app/src/main/java/com/seafile/seadroid2/widget/SimpleMarkdownParser.java
create mode 100644 app/src/main/res/drawable/baseline_comment_24.xml
create mode 100644 app/src/main/res/drawable/baseline_delete_24.xml
create mode 100644 app/src/main/res/drawable/baseline_info_24.xml
create mode 100644 app/src/main/res/drawable/baseline_mark_32.xml
create mode 100644 app/src/main/res/drawable/baseline_outline_24.xml
create mode 100644 app/src/main/res/drawable/baseline_sdoc_mark_as_resolved_32.xml
create mode 100644 app/src/main/res/drawable/baseline_share_24.xml
create mode 100644 app/src/main/res/drawable/baseline_star_filled_24.xml
create mode 100644 app/src/main/res/drawable/ic_camera.xml
rename app/src/main/res/layout/{activity_sdoc_comment.xml => activity_doc_comment.xml} (87%)
rename app/src/main/res/layout/{dialog_sdoc_profile.xml => dialog_file_profile.xml} (79%)
rename app/src/main/res/layout/{item_sdoc_comment.xml => item_file_comment.xml} (56%)
rename app/src/main/res/layout/{item_sdoc_directory.xml => item_sdoc_outline.xml} (85%)
create mode 100644 app/src/main/res/menu/bottom_sheet_camera_album_select.xml
create mode 100644 app/src/main/res/menu/menu_comment_mark_delete.xml
diff --git a/app/build.gradle b/app/build.gradle
index ab7864caf..21abfdb74 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -14,7 +14,7 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
compileSdk rootProject.ext.compileSdkVersion
- versionCode 158
+ versionCode 160
versionName "3.0.7"
multiDexEnabled true
@@ -184,15 +184,12 @@ android {
// Firebase
implementation platform('com.google.firebase:firebase-bom:33.2.0')
implementation 'com.google.firebase:firebase-crashlytics'
- implementation 'com.google.firebase:firebase-analytics'
//media3
final def media3_version = '1.4.1'
implementation "androidx.media3:media3-exoplayer:$media3_version"
implementation "androidx.media3:media3-ui:$media3_version"
-// implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
-
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation "androidx.appcompat:appcompat:1.7.0"
@@ -239,6 +236,17 @@ android {
//https://github.com/KunMinX/UnPeek-LiveData
implementation 'com.kunminx.arch:unpeek-livedata:7.8.0'
+ implementation 'org.commonmark:commonmark:0.21.0'
+// implementation 'org.commonmark:commonmark-ext-gfm-tables:0.21.0' // 如果需要表格支持
+ implementation 'org.commonmark:commonmark-ext-autolink:0.21.0' // 如果需要自动链接支持
+
+ //https://github.com/lzyzsd/JsBridge
+ implementation 'com.github.lzyzsd:jsbridge:1.0.4'
+
+// https://github.com/rubensousa/GravitySnapHelper
+// implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
+
+
//
implementation 'com.blankj:utilcode:1.30.7'
@@ -289,20 +297,20 @@ android {
implementation 'com.github.yydcdut.RxMarkdown:markdown-processor:v0.1.3'
-// //markdown
+ //https://noties.io/Markwon/
// final def markwon_version = '4.6.2'
// implementation "io.noties.markwon:core:$markwon_version"
// implementation "io.noties.markwon:editor:$markwon_version"
-// implementation "io.noties.markwon:ext-latex:$markwon_version"
// implementation "io.noties.markwon:ext-strikethrough:$markwon_version"
// implementation "io.noties.markwon:ext-tables:$markwon_version"
// implementation "io.noties.markwon:ext-tasklist:$markwon_version"
+// implementation "io.noties.markwon:ext-latex:$markwon_version"
// implementation "io.noties.markwon:html:$markwon_version"
// implementation "io.noties.markwon:image:$markwon_version"
// implementation "io.noties.markwon:image-glide:$markwon_version"
-// implementation "io.noties.markwon:inline-parser:$markwon_version"
// implementation "io.noties.markwon:linkify:$markwon_version"
-// implementation "io.noties.markwon:syntax-highlight:$markwon_version"
+// implementation "io.noties.markwon:inline-parser:$markwon_version"
+// implementation "io.noties.markwon:recycler:$markwon_version"
implementation 'com.madgag.spongycastle:core:1.54.0.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 57b667591..7d8fb0aa7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -210,7 +210,7 @@
-
+
getAccountList() {
List list = new ArrayList<>();
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 4056c3008..785a181a8 100644
--- a/app/src/main/java/com/seafile/seadroid2/config/GlideLoadConfig.java
+++ b/app/src/main/java/com/seafile/seadroid2/config/GlideLoadConfig.java
@@ -1,25 +1,29 @@
package com.seafile.seadroid2.config;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.load.model.LazyHeaders;
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;
import com.seafile.seadroid2.ui.WidgetUtils;
public class GlideLoadConfig {
-// public static GlideUrl getGlideUrl(String url) {
-//
-// Account account = SupportAccountManager.getInstance().getCurrentAccount();
-// if (account == null) {
-// return new GlideUrl(url, new LazyHeaders.Builder().build());
-// }
-//
-// String token = account.token;
-//
-// return new GlideUrl(url, new LazyHeaders.Builder()
-// .addHeader("Authorization", "Token " + token)
-// .build());
-// }
+ public static GlideUrl getGlideUrl(String url) {
+
+ Account account = SupportAccountManager.getInstance().getCurrentAccount();
+ if (account == null) {
+ return new GlideUrl(url, new LazyHeaders.Builder().build());
+ }
+
+ String token = account.token;
+
+ return new GlideUrl(url, new LazyHeaders.Builder()
+ .addHeader("Authorization", "Token " + token)
+ .build());
+ }
//
// public static GlideUrl getGlideUrl(String url, String token) {
// return new GlideUrl(url, new LazyHeaders.Builder()
diff --git a/app/src/main/java/com/seafile/seadroid2/config/WebViewActionConstant.java b/app/src/main/java/com/seafile/seadroid2/config/WebViewActionConstant.java
new file mode 100644
index 000000000..5cdb5fda2
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/config/WebViewActionConstant.java
@@ -0,0 +1,19 @@
+package com.seafile.seadroid2.config;
+
+public class WebViewActionConstant {
+ public final static String APP_VERSION_GET = "app.version.get";
+ public final static String APP_TOAST_SHOW = "app.toast.show";
+ public final static String PAGE_FINISH = "page.finish";
+ public final static String PAGE_STATUS_COLOR_SET = "page.status.color.set";
+ public final static String PAGE_STATUS_HEIGHT_GET = "page.status.height.get";
+
+ public static class CallJsFunction {
+ public final static String SDOC_OUTLINES_DATA_GET = "sdoc.outline.data.get";
+ public final static String SDOC_OUTLINES_DATA_SELECT = "sdoc.outline.data.select";
+
+ public static class CallJsFunctionRequestCode {
+ public final static int REQ = 1001;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/WebRouteModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/WebRouteModel.java
new file mode 100644
index 000000000..8fae7b728
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/WebRouteModel.java
@@ -0,0 +1,11 @@
+package com.seafile.seadroid2.framework.data.model;
+
+public class WebRouteModel {
+ public int v = 1;
+ public String action;
+
+ /**
+ * params data
+ */
+ public String data;
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentModel.java
similarity index 70%
rename from app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentModel.java
rename to app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentModel.java
index 9260574cd..06c7b55cb 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentModel.java
@@ -1,13 +1,15 @@
-package com.seafile.seadroid2.framework.data.model.sdoc;
+package com.seafile.seadroid2.framework.data.model.docs_comment;
import com.google.gson.annotations.JsonAdapter;
import com.seafile.seadroid2.framework.data.model.adapter.OffsetDateTimeAdapter;
+import com.seafile.seadroid2.framework.data.model.sdoc.SDocCommentReplyModel;
+import com.seafile.seadroid2.view.rich_edittext.RichEditText;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
-public class SDocCommentModel {
+public class DocsCommentModel {
public int id;
public String item_name;
public String parent_path;
@@ -16,7 +18,7 @@ public class SDocCommentModel {
public List replies;
public String comment;
public String repo_id;
- public String resolved;
+ public boolean resolved;
public String user_contact_email;
public String user_email;
public String user_name;
@@ -29,6 +31,10 @@ public class SDocCommentModel {
public String detail;
+
+ public boolean isContainImage = false;
+ public List commentList;
+
public String getCreatedAtFriendlyText() {
return created_at.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).replace("T", " ");
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentWrapperModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentWrapperModel.java
new file mode 100644
index 000000000..e3506abb4
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentWrapperModel.java
@@ -0,0 +1,5 @@
+package com.seafile.seadroid2.framework.data.model.docs_comment;
+
+public class DocsCommentWrapperModel {
+ public DocsCommentModel comment;
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentsWrapperModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentsWrapperModel.java
new file mode 100644
index 000000000..4ec05381b
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsCommentsWrapperModel.java
@@ -0,0 +1,7 @@
+package com.seafile.seadroid2.framework.data.model.docs_comment;
+
+import java.util.List;
+
+public class DocsCommentsWrapperModel {
+ public List comments;
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsUploadResultModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsUploadResultModel.java
new file mode 100644
index 000000000..a5d8c2974
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/docs_comment/DocsUploadResultModel.java
@@ -0,0 +1,7 @@
+package com.seafile.seadroid2.framework.data.model.docs_comment;
+
+import java.util.List;
+
+public class DocsUploadResultModel {
+ public List relative_path;
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocDetailModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileDetailModel.java
similarity index 91%
rename from app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocDetailModel.java
rename to app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileDetailModel.java
index 9f9aa26ba..77ea5f381 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocDetailModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileDetailModel.java
@@ -13,7 +13,7 @@
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
-public class SDocDetailModel implements Parcelable {
+public class FileDetailModel implements Parcelable {
private String type;
private String id;
@@ -183,10 +183,10 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeByte(this.canEdit ? (byte) 1 : (byte) 0);
}
- public SDocDetailModel() {
+ public FileDetailModel() {
}
- protected SDocDetailModel(Parcel in) {
+ protected FileDetailModel(Parcel in) {
this.type = in.readString();
this.id = in.readString();
this.name = in.readString();
@@ -203,15 +203,15 @@ protected SDocDetailModel(Parcel in) {
this.canEdit = in.readByte() != 0;
}
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
- public SDocDetailModel createFromParcel(Parcel source) {
- return new SDocDetailModel(source);
+ public FileDetailModel createFromParcel(Parcel source) {
+ return new FileDetailModel(source);
}
@Override
- public SDocDetailModel[] newArray(int size) {
- return new SDocDetailModel[size];
+ public FileDetailModel[] newArray(int size) {
+ return new FileDetailModel[size];
}
};
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocProfileConfigModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java
similarity index 78%
rename from app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocProfileConfigModel.java
rename to app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java
index 658ef12cd..0b63f210d 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocProfileConfigModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileProfileConfigModel.java
@@ -2,10 +2,10 @@
import com.seafile.seadroid2.framework.data.model.user.UserWrapperModel;
-public class SDocProfileConfigModel {
+public class FileProfileConfigModel {
public UserWrapperModel users;
public MetadataConfigModel metadata;
- public SDocDetailModel detail;
+ public FileDetailModel detail;
public UserWrapperModel getUsers() {
return users;
@@ -23,11 +23,11 @@ public void setMetadata(MetadataConfigModel metadata) {
this.metadata = metadata;
}
- public SDocDetailModel getDetail() {
+ public FileDetailModel getDetail() {
return detail;
}
- public void setDetail(SDocDetailModel detail) {
+ public void setDetail(FileDetailModel detail) {
this.detail = detail;
}
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocRecordWrapperModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileRecordWrapperModel.java
similarity index 57%
rename from app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocRecordWrapperModel.java
rename to app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileRecordWrapperModel.java
index 4f1748c07..a104efff1 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocRecordWrapperModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/FileRecordWrapperModel.java
@@ -5,7 +5,7 @@
import java.util.List;
-public class SDocRecordWrapperModel implements Parcelable {
+public class FileRecordWrapperModel implements Parcelable {
public List metadata;
public List results;
@@ -20,23 +20,23 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(this.results);
}
- public SDocRecordWrapperModel() {
+ public FileRecordWrapperModel() {
}
- protected SDocRecordWrapperModel(Parcel in) {
+ protected FileRecordWrapperModel(Parcel in) {
this.metadata = in.createTypedArrayList(MetadataModel.CREATOR);
this.results = in.createTypedArrayList(RecordResultModel.CREATOR);
}
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
- public SDocRecordWrapperModel createFromParcel(Parcel source) {
- return new SDocRecordWrapperModel(source);
+ public FileRecordWrapperModel createFromParcel(Parcel source) {
+ return new FileRecordWrapperModel(source);
}
@Override
- public SDocRecordWrapperModel[] newArray(int size) {
- return new SDocRecordWrapperModel[size];
+ public FileRecordWrapperModel[] newArray(int size) {
+ return new FileRecordWrapperModel[size];
}
};
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/OutlineItemModel.java
similarity index 74%
rename from app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocModel.java
rename to app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/OutlineItemModel.java
index d8b316122..9ef5cea74 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/OutlineItemModel.java
@@ -4,11 +4,11 @@
import java.util.List;
-public class SDocModel extends BaseModel {
+public class OutlineItemModel extends BaseModel {
public String id;
public String type;
public String text;
public boolean indent;
- public List children;
+ public List children;
public SDocDataModel data;
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/RecordResultModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/RecordResultModel.java
index 11386d1ed..e602da6ef 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/RecordResultModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/RecordResultModel.java
@@ -37,6 +37,7 @@ public class RecordResultModel implements Parcelable {
public String _suffix;
public String _description;
public List _owner;
+ public List _reviewer;
@JsonAdapter(RecordResultDeserializer.class)
public Map dynamicFields;
@@ -49,6 +50,7 @@ public int describeContents() {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringList(this._collaborators);
+ dest.writeStringList(this._reviewer);
dest.writeString(this._creator);
dest.writeString(this._ctime);
dest.writeString(this._file_creator);
@@ -80,6 +82,7 @@ public RecordResultModel() {
protected RecordResultModel(Parcel in) {
this._collaborators = in.createStringArrayList();
+ this._reviewer = in.createStringArrayList();
this._creator = in.readString();
this._ctime = in.readString();
this._file_creator = in.readString();
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentWrapperModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentWrapperModel.java
deleted file mode 100644
index 796389d0c..000000000
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocCommentWrapperModel.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.seafile.seadroid2.framework.data.model.sdoc;
-
-import java.util.List;
-
-public class SDocCommentWrapperModel {
- public List comments;
-}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocWrapperModel.java b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocOutlineWrapperModel.java
similarity index 67%
rename from app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocWrapperModel.java
rename to app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocOutlineWrapperModel.java
index 03e7cfdea..3452258f7 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocWrapperModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/data/model/sdoc/SDocOutlineWrapperModel.java
@@ -2,9 +2,9 @@
import java.util.List;
-public class SDocWrapperModel {
+public class SDocOutlineWrapperModel {
public int version;
public int format_version;
public String last_modify_user;
- public List elements;
+ public List elements;
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/http/BaseOkHttpClient.java b/app/src/main/java/com/seafile/seadroid2/framework/http/BaseOkHttpClient.java
index 1e3f73424..0374fc0e2 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/http/BaseOkHttpClient.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/http/BaseOkHttpClient.java
@@ -43,6 +43,16 @@ public BaseOkHttpClient(Account account) {
protected List getInterceptors() {
+ List interceptors = getInterceptorsWithoutToken();
+ if (account != null && !TextUtils.isEmpty(account.token)) {
+ interceptors.add(new HeaderInterceptor(account.token));
+ }
+
+ return interceptors;
+ }
+
+ protected List getInterceptorsWithoutToken() {
+
List interceptors = new ArrayList<>();
//print log
@@ -51,9 +61,6 @@ protected List getInterceptors() {
loggingInterceptor.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.BASIC);
interceptors.add(loggingInterceptor);
- if (account != null && !TextUtils.isEmpty(account.token)) {
- interceptors.add(new HeaderInterceptor(account.token));
- }
// interceptors.add(new AddCookiesInterceptor());
// interceptors.add(new ReceivedCookiesInterceptor());
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/http/HttpIO.java b/app/src/main/java/com/seafile/seadroid2/framework/http/HttpIO.java
index 00702a34a..2fd29011f 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/http/HttpIO.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/http/HttpIO.java
@@ -80,6 +80,14 @@ public static HttpIO getCurrentInstance() {
return INSTANCE;
}
+ public static void removeInstanceByAccount(Account account) {
+ if (account == null) {
+ return;
+ }
+
+ IO_MAP.remove(account.getSignature());
+ }
+
/**
* Not logged in/Log in to another server
*/
@@ -153,6 +161,7 @@ public T execute(Class clazz) {
private Retrofit createRetrofit() {
Retrofit.Builder rBuilder = new Retrofit.Builder();
+
rBuilder.baseUrl(getServerUrl());
rBuilder.addConverterFactory(ConverterFactory.create());
rBuilder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
@@ -162,7 +171,6 @@ private Retrofit createRetrofit() {
return rBuilder.build();
}
-
public void downloadBinarySync(String url, File destinationFile, ProgressListener callback) throws IOException {
OkHttpClient client = getOkHttpClient().getOkClient();
@@ -178,7 +186,6 @@ public void onProgress(long transferSize, long totalSize) {
try (BinaryFileDownloader fileDownloader = new BinaryFileDownloader(client, fileWriter)) {
fileDownloader.download(url);
-
} catch (Exception e) {
if (callback != null) {
callback.isCancelled();
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/http/SafeOkHttpClient.java b/app/src/main/java/com/seafile/seadroid2/framework/http/SafeOkHttpClient.java
index 25524a5c1..cc46d68b6 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/http/SafeOkHttpClient.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/http/SafeOkHttpClient.java
@@ -2,6 +2,7 @@
import com.blankj.utilcode.util.CollectionUtils;
import com.seafile.seadroid2.account.Account;
+import com.seafile.seadroid2.ssl.CertsManager;
import com.seafile.seadroid2.ssl.SSLSeafileSocketFactory;
import com.seafile.seadroid2.ssl.SSLTrustManager;
@@ -12,6 +13,7 @@
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -31,8 +33,28 @@
import okhttp3.Request;
public class SafeOkHttpClient extends BaseOkHttpClient {
+ private final List _interceptors = new ArrayList<>();
+
public SafeOkHttpClient(Account account) {
super(account);
+
+ _interceptors.addAll(getInterceptors());
+ }
+
+ public SafeOkHttpClient(Account account, boolean isCustomToken) {
+ super(account);
+
+ if (isCustomToken) {
+ _interceptors.addAll(getInterceptorsWithoutToken());
+ } else {
+ _interceptors.addAll(getInterceptors());
+ }
+ }
+
+ public void addInterceptors(List s) {
+ if (s != null) {
+ _interceptors.addAll(s);
+ }
}
public static TrustManager[] getTrustManagers() {
@@ -69,24 +91,15 @@ public OkHttpClient getOkClient() {
//https
if (account.getServer().startsWith("https://")) {
//ssl
-
SSLSocketFactory factory = SSLTrustManager.instance().getSSLSocketFactory(account);
TrustManager[] trustManagers = SSLTrustManager.instance().getTrustManagers(account);
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
builder.sslSocketFactory(factory, trustManager);
-
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
- //check host
- if (account.getServerDomainName().equals(hostname)) {
- return true;
- }
-
- //check by default verifier
- HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
- return verifier.verify(hostname, session);
+ return true;
}
});
}
@@ -129,9 +142,8 @@ public boolean verify(String hostname, SSLSession session) {
builder.networkInterceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR);
//add interceptors
- List interceptors = getInterceptors();
- if (!CollectionUtils.isEmpty(interceptors)) {
- for (Interceptor i : interceptors) {
+ if (!CollectionUtils.isEmpty(_interceptors)) {
+ for (Interceptor i : _interceptors) {
builder.interceptors().add(i);
}
}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/util/ContentResolvers.java b/app/src/main/java/com/seafile/seadroid2/framework/util/ContentResolvers.java
new file mode 100644
index 000000000..de86a85ee
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/framework/util/ContentResolvers.java
@@ -0,0 +1,55 @@
+package com.seafile.seadroid2.framework.util;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.MediaStore;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ContentResolvers {
+
+ public static String getFileNameFromUri(ContentResolver contentResolver, Uri uri) {
+ String fileName = null;
+ String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
+ try (Cursor cursor = contentResolver.query(uri, projection, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
+ fileName = cursor.getString(index);
+ }
+ }
+
+ return fileName;
+ }
+
+ // 获取文件内容的方法
+ public static byte[] getFileContentFromUri(ContentResolver contentResolver, Uri uri) {
+ byte[] fileContent = null;
+ InputStream inputStream = null;
+ try {
+ inputStream = contentResolver.openInputStream(uri);
+ if (inputStream != null) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, bytesRead);
+ }
+ fileContent = outputStream.toByteArray();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return fileContent;
+ }
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/framework/util/StringUtils.java b/app/src/main/java/com/seafile/seadroid2/framework/util/StringUtils.java
index 6d8d5c876..975d1926b 100644
--- a/app/src/main/java/com/seafile/seadroid2/framework/util/StringUtils.java
+++ b/app/src/main/java/com/seafile/seadroid2/framework/util/StringUtils.java
@@ -129,9 +129,13 @@ public static String trimStart(String input, String character) {
}
/**
- *
- * ""string"" => "string"
- *
+ *
+ *
+ * ""string"" => "string"
+ * null => null
+ * "" => ""
+ *
+ *
*/
public static String deString(String input) {
if (TextUtils.isEmpty(input)) {
@@ -143,6 +147,25 @@ public static String deString(String input) {
return input;
}
+ /**
+ *
+ *
+ * ""string"" => "string"
+ * null => ""
+ * "" => ""
+ *
+ *
+ */
+ public static String deStringReturnNonNull(String input) {
+ if (TextUtils.isEmpty(input)) {
+ return "";
+ }
+
+ input = trim(input, "\"");
+
+ return input;
+ }
+
public static int getStringAsciiSum(String input) {
int sum = 0;
for (int i = 0; i < input.length(); i++) {
@@ -151,7 +174,7 @@ public static int getStringAsciiSum(String input) {
}
return sum;
}
-
+
public static int getHexStringAsciiSum(String input) {
byte[] bytes = hexStringToByteArray(input);
@@ -173,4 +196,18 @@ public static byte[] hexStringToByteArray(String s) {
}
return data;
}
+
+ /**
+ * => org.apache.commons.lang3.StringUtils#countMatches(c,c)
+ */
+ public static int countMatches(String inputStr, String matchStr) {
+ if (TextUtils.isEmpty(inputStr)) {
+ return 0;
+ }
+ if (TextUtils.isEmpty(matchStr)) {
+ return 0;
+ }
+
+ return org.apache.commons.lang3.StringUtils.countMatches(inputStr, matchStr);
+ }
}
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 d3742b207..04662712e 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
@@ -485,24 +485,25 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
.build();
newCall = HttpIO.getCurrentInstance().getOkHttpClient().getOkClient().newCall(request);
- Response response = newCall.execute();
+ String str;
+ try (Response response = newCall.execute()) {
+ if (!response.isSuccessful()) {
+ String b = response.body() != null ? response.body().string() : null;
+ SLogs.d("result,failed:" + b);
- if (!response.isSuccessful()) {
- String b = response.body() != null ? response.body().string() : null;
- SLogs.d("result,failed:" + b);
+ //
+ newCall.cancel();
- //
- newCall.cancel();
+ //[text={"error": "Out of quota.\n"}]
+ if (b != null && b.toLowerCase().contains("out of quota")) {
+ throw SeafException.OUT_OF_QUOTA;
+ }
- //[text={"error": "Out of quota.\n"}]
- if (b != null && b.toLowerCase().contains("out of quota")) {
- throw SeafException.OUT_OF_QUOTA;
+ throw SeafException.networkException;
}
- throw SeafException.networkException;
+ str = response.body().string();
}
-
- String str = response.body().string();
String fileId = str.replace("\"", "");
SLogs.d("result,file ID:" + str);
@@ -512,7 +513,6 @@ private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity
}
}
-
private void uploadBlockFile(Account account, RepoModel repoModel, FileTransferEntity transferEntity) throws SeafException, IOException, JSONException {
if (isStopped()) {
return;
diff --git a/app/src/main/java/com/seafile/seadroid2/preferences/Settings.java b/app/src/main/java/com/seafile/seadroid2/preferences/Settings.java
index 2519d4d0c..2c6441e5e 100644
--- a/app/src/main/java/com/seafile/seadroid2/preferences/Settings.java
+++ b/app/src/main/java/com/seafile/seadroid2/preferences/Settings.java
@@ -49,6 +49,8 @@ public Settings() {
public static SettingsLiveData SPACE_INFO;
public static SettingsLiveData NIGHT_MODE;
public static SettingsLiveData APP_NIGHT_MODE;
+
+ @Deprecated
public static SettingsLiveData USER_GESTURE_LOCK_SWITCH;
// public static SettingsLiveData USER_GESTURE_LOCK_TIMESTAMP;
@@ -137,9 +139,9 @@ public static void initUserSettings(Account account) {
SPACE_INFO = new StringSettingLiveData(_account.getEncryptSignature(), R.string.pref_key_user_space, R.string.settings_account_info_load_data);
NIGHT_MODE = new EnumSettingLiveData<>(NightMode.class, _account.getEncryptSignature(), R.string.pref_key_night_mode, R.string.pref_default_value_night_mode);
APP_NIGHT_MODE = new EnumSettingLiveData<>(NightMode.class, _account.getEncryptSignature(), R.string.pref_key_current_night_mode, R.string.pref_default_value_night_mode);
- CLIENT_ENCRYPT_SWITCH = new BooleanSettingLiveData(_account.getEncryptSignature(), R.string.pref_key_security_client_encrypt);
+// CLIENT_ENCRYPT_SWITCH = new BooleanSettingLiveData(_account.getEncryptSignature(), R.string.pref_key_security_client_encrypt);
- USER_GESTURE_LOCK_SWITCH = new BooleanSettingLiveData(_account.getEncryptSignature(), R.string.pref_key_gesture_lock);
+// USER_GESTURE_LOCK_SWITCH = new BooleanSettingLiveData(_account.getEncryptSignature(), R.string.pref_key_gesture_lock);
// USER_GESTURE_LOCK_TIMESTAMP = new LongSettingLiveData(_account.getEncryptSignature(), R.string.pref_key_gesture_lock_timestamp, R.string.pref_default_value_key_gesture_lock_timestamp);
@@ -169,9 +171,9 @@ public static void initUserSettings(Account account) {
REGISTER_LIST.add(SPACE_INFO);
REGISTER_LIST.add(NIGHT_MODE);
REGISTER_LIST.add(APP_NIGHT_MODE);
- REGISTER_LIST.add(USER_GESTURE_LOCK_SWITCH);
+// REGISTER_LIST.add(USER_GESTURE_LOCK_SWITCH);
// REGISTER_LIST.add(USER_GESTURE_LOCK_TIMESTAMP);
- REGISTER_LIST.add(CLIENT_ENCRYPT_SWITCH);
+// REGISTER_LIST.add(CLIENT_ENCRYPT_SWITCH);
REGISTER_LIST.add(ALBUM_BACKUP_SWITCH);
REGISTER_LIST.add(ALBUM_BACKUP_SELECTED_REPO);
REGISTER_LIST.add(ALBUM_BACKUP_STATE);
diff --git a/app/src/main/java/com/seafile/seadroid2/ssl/CertsManager.java b/app/src/main/java/com/seafile/seadroid2/ssl/CertsManager.java
index d39f018d5..2cdf472a6 100644
--- a/app/src/main/java/com/seafile/seadroid2/ssl/CertsManager.java
+++ b/app/src/main/java/com/seafile/seadroid2/ssl/CertsManager.java
@@ -17,7 +17,7 @@
*/
public final class CertsManager {
- private final Map cachedCerts = Maps.newConcurrentMap();
+ private final Map cachedCerts = Maps.newConcurrentMap();
private static CertsManager instance;
@@ -36,7 +36,7 @@ public void saveCertForAccount(final Account account, boolean rememberChoice) {
}
final X509Certificate cert = certs.get(0);
- cachedCerts.put(account, cert);
+ cachedCerts.put(account.getServer(), cert);
if (rememberChoice) {
// save cert info to shared preferences
@@ -46,12 +46,23 @@ public void saveCertForAccount(final Account account, boolean rememberChoice) {
}
}
+ public void deleteCertForAccount(final Account account) {
+ if (account == null) {
+ return;
+ }
+
+ cachedCerts.remove(account.getServer());
+
+ String keyPrefix = EncryptUtils.encryptMD5ToString(account.getServer());
+ Settings.getCommonPreferences().edit().remove(DataStoreKeys.KEY_SERVER_CERT_INFO + "_" + keyPrefix).apply();
+ }
public X509Certificate getCertificate(Account account) {
- X509Certificate cert = cachedCerts.get(account);
+ X509Certificate cert = cachedCerts.get(account.getServer());
if (cert != null) {
return cert;
}
+
String keyPrefix = EncryptUtils.encryptMD5ToString(account.getServer());
String certBase64 = Settings.getCommonPreferences().getString(DataStoreKeys.KEY_SERVER_CERT_INFO + "_" + keyPrefix, null);
if (TextUtils.isEmpty(certBase64)) {
@@ -60,7 +71,7 @@ public X509Certificate getCertificate(Account account) {
cert = CertsHelper.convertToCert(certBase64);
if (cert != null) {
- cachedCerts.put(account, cert);
+ cachedCerts.put(account.getServer(), cert);
}
return cert;
diff --git a/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java b/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java
index fc0ea4f36..c75f1312c 100644
--- a/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java
+++ b/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java
@@ -25,6 +25,7 @@
import java.util.Map;
import java.util.Set;
+import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/account/AccountViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/account/AccountViewModel.java
index a79bcc7e0..57d613dfb 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/account/AccountViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/account/AccountViewModel.java
@@ -17,6 +17,7 @@
import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.account.AccountUtils;
import com.seafile.seadroid2.framework.util.DeviceIdManager;
+import com.seafile.seadroid2.ssl.CertsManager;
import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
import com.seafile.seadroid2.ui.dialog_fragment.SignOutDialogFragment;
import com.seafile.seadroid2.ui.main.MainService;
@@ -181,7 +182,7 @@ private Call getLoginCall(Account tempAccount, String pwd, String to
body.put("client_version", appVersion);
body.put("platform_version", Build.VERSION.RELEASE);
- Map requestBody = generateRequestBody(body);
+ Map requestBody = genRequestBody(body);
return HttpIO.getInstanceByAccount(tempAccount).execute(AccountService.class).login(headers, requestBody);
}
@@ -214,9 +215,6 @@ public void accept(Throwable throwable) throws Exception {
});
}
- /**
- * @see SignOutDialogFragment#onPositiveClick()
- */
public void deleteAccount(Account account) {
Account curAccount = SupportAccountManager.getInstance().getCurrentAccount();
@@ -224,8 +222,11 @@ public void deleteAccount(Account account) {
if (curAccount != null && curAccount.equals(account)) {
//
AccountUtils.logout(account);
+ } else {
+ HttpIO.removeInstanceByAccount(account);
}
+ CertsManager.instance().deleteCertForAccount(account);
//delete local account
SupportAccountManager.getInstance().removeAccount(account.getAndroidAccount(), null, null);
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/account/SeafileAuthenticatorActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/account/SeafileAuthenticatorActivity.java
index a993ea2a5..c38be8735 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/account/SeafileAuthenticatorActivity.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/account/SeafileAuthenticatorActivity.java
@@ -23,7 +23,6 @@
import androidx.core.app.NavUtils;
import androidx.core.app.TaskStackBuilder;
-import com.google.firebase.analytics.FirebaseAnalytics;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.account.Authenticator;
import com.seafile.seadroid2.account.SupportAccountManager;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java
index 24d1dfbc4..1339ac269 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java
@@ -40,7 +40,7 @@
import com.seafile.seadroid2.ui.file.FileActivity;
import com.seafile.seadroid2.ui.main.MainActivity;
import com.seafile.seadroid2.ui.markdown.MarkdownActivity;
-import com.seafile.seadroid2.ui.media.image_preview.ImagePreviewActivity;
+import com.seafile.seadroid2.ui.media.image_preview2.CarouselImagePreviewActivity;
import com.seafile.seadroid2.ui.media.player.exoplayer.CustomExoVideoPlayerActivity;
import com.seafile.seadroid2.ui.sdoc.SDocWebViewActivity;
import com.seafile.seadroid2.view.TipsViews;
@@ -274,7 +274,7 @@ private void open(RepoModel repoModel, ActivityModel activityModel) {
} else if (Utils.isViewableImage(activityModel.name)) {
- Intent getIntent = ImagePreviewActivity.startThisFromActivity(requireContext(), activityModel);
+ Intent getIntent = CarouselImagePreviewActivity.startThisFromActivity(requireContext(), activityModel);
imagePreviewActivityLauncher.launch(getIntent);
} else if (activityModel.name.endsWith(Constants.Format.DOT_SDOC)) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/base/BaseMediaSelectorActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/base/BaseMediaSelectorActivity.java
new file mode 100644
index 000000000..e38c5bb2e
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/base/BaseMediaSelectorActivity.java
@@ -0,0 +1,174 @@
+package com.seafile.seadroid2.ui.base;
+
+import android.Manifest;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.PickVisualMediaRequest;
+import androidx.activity.result.contract.ActivityResultContracts;
+
+import com.blankj.utilcode.util.ToastUtils;
+import com.seafile.seadroid2.R;
+import com.seafile.seadroid2.framework.util.SLogs;
+import com.seafile.seadroid2.framework.util.TakeCameras;
+import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
+import com.seafile.seadroid2.ui.bottomsheetmenu.BottomSheetHelper;
+import com.seafile.seadroid2.ui.bottomsheetmenu.OnMenuClickListener;
+
+import java.io.File;
+import java.util.List;
+
+import kotlin.Pair;
+
+public class BaseMediaSelectorActivity extends BaseActivityWithVM {
+ private ActivityResultLauncher cameraPermissionLauncher, cameraPermissionLauncher1, storagePermissionLauncher;
+ private ActivityResultLauncher takePhotoLauncher;
+ private ActivityResultLauncher shootVideoLauncher;
+ private ActivityResultLauncher pickMediaLauncher;
+ private ActivityResultLauncher pickMultipleMediaLauncher;
+ private ActivityResultLauncher fileChooseLauncher;
+ private Pair uriPair;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ initLauncher();
+ }
+
+ private void initLauncher() {
+ cameraPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Boolean result) {
+ if (result) {
+ uriPair = TakeCameras.buildTakePhotoUri(BaseMediaSelectorActivity.this);
+ takePhotoLauncher.launch(uriPair.getFirst());
+ } else {
+ ToastUtils.showLong(R.string.permission_camera);
+ }
+ }
+ });
+
+ cameraPermissionLauncher1 = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Boolean result) {
+ if (result) {
+ uriPair = TakeCameras.buildTakePhotoUri(BaseMediaSelectorActivity.this);
+ shootVideoLauncher.launch(uriPair.getFirst());
+ } else {
+ ToastUtils.showLong(R.string.permission_camera);
+ }
+ }
+ });
+
+ storagePermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Boolean o) {
+ if (o) {
+ fileChooseLauncher.launch("*/*");
+ } else {
+ ToastUtils.showLong(R.string.permission_manage_external_storage_rationale);
+ }
+ }
+ });
+
+ takePhotoLauncher = registerForActivityResult(new ActivityResultContracts.TakePicture(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Boolean o) {
+ if (!o) {
+ return;
+ }
+ onMediaPicked(uriPair.getFirst());
+ }
+ });
+
+ shootVideoLauncher = registerForActivityResult(new ActivityResultContracts.CaptureVideo(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Boolean o) {
+ if (!o) {
+ return;
+ }
+ onMediaPicked(uriPair.getFirst());
+ }
+ });
+
+ pickMediaLauncher = registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Uri o) {
+ onMediaPicked(o);
+ }
+ });
+
+ pickMultipleMediaLauncher = registerForActivityResult(new ActivityResultContracts.PickMultipleVisualMedia(9), new ActivityResultCallback>() {
+ @Override
+ public void onActivityResult(List o) {
+ for (Uri uri : o) {
+ onMediaPicked(uri);
+ }
+ }
+ });
+
+ fileChooseLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(Uri o) {
+ onMediaPicked(o);
+ }
+ });
+ }
+
+ public void onMediaPicked(Uri uri) {
+ SLogs.d(uri.toString());
+ }
+
+ ///////////////////////////////////////////////////////
+
+ public void showPickPhotoSheetDialog(boolean isPickMultiWhenMenuIdIsViewFile) {
+ BottomSheetHelper.buildSheet(this, R.menu.bottom_sheet_camera_album_select, new OnMenuClickListener() {
+ @Override
+ public void onMenuClick(MenuItem menuItem) {
+ if (menuItem.getItemId() == R.id.take_photo) {
+ cameraPermissionLauncher.launch(Manifest.permission.CAMERA);
+ } else if (menuItem.getItemId() == R.id.view_file) {
+ if (isPickMultiWhenMenuIdIsViewFile) {
+ pickMultipleMediaLauncher.launch(new PickVisualMediaRequest.Builder()
+ .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
+ .build());
+ } else {
+ pickMediaLauncher.launch(new PickVisualMediaRequest.Builder()
+ .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
+ .build());
+ }
+ }
+ }
+ }).show(getSupportFragmentManager());
+ }
+
+ public void showPickPhotoAndVideoSheetDialog(boolean isPickMultiWhenMenuIdIsViewFile) {
+ BottomSheetHelper.buildSheet(this, R.menu.bottom_sheet_camera_album_select, new OnMenuClickListener() {
+ @Override
+ public void onMenuClick(MenuItem menuItem) {
+ if (menuItem.getItemId() == R.id.take_photo) {
+ cameraPermissionLauncher.launch(Manifest.permission.CAMERA);
+ } else if (menuItem.getItemId() == R.id.view_file) {
+ if (isPickMultiWhenMenuIdIsViewFile) {
+ pickMultipleMediaLauncher.launch(new PickVisualMediaRequest.Builder()
+ .setMediaType(ActivityResultContracts.PickVisualMedia.ImageAndVideo.INSTANCE)
+ .build());
+ } else {
+ pickMediaLauncher.launch(new PickVisualMediaRequest.Builder()
+ .setMediaType(ActivityResultContracts.PickVisualMedia.ImageAndVideo.INSTANCE)
+ .build());
+ }
+ }
+ }
+ }).show(getSupportFragmentManager());
+ }
+
+ public void pickFile() {
+ storagePermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
+ }
+
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java
index 8cbc4d260..2d99ad020 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java
@@ -13,6 +13,7 @@
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.SeadroidApplication;
import com.seafile.seadroid2.SeafException;
+import com.seafile.seadroid2.annotation.Todo;
import com.seafile.seadroid2.framework.data.model.ResultModel;
import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.framework.util.SLogs;
@@ -118,7 +119,19 @@ protected void onCleared() {
}
}
- public Map generateRequestBody(Map requestDataMap) {
+
+ @Todo
+ public Map genObjRequestBody(Map params) {
+ Map requestBodyMap = new HashMap<>();
+ for (Map.Entry entry : params.entrySet()) {
+ String value = entry.getValue().toString();
+ RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), value);
+ requestBodyMap.put(entry.getKey(), requestBody);
+ }
+ return requestBodyMap;
+ }
+
+ public Map genRequestBody(Map requestDataMap) {
Map requestBodyMap = new HashMap<>();
if (requestDataMap == null || requestDataMap.isEmpty()) {
requestBodyMap.put("x-test", RequestBody.create(MediaType.parse("multipart/form-data"), "test"));
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/dialog/SslConfirmDialog.java b/app/src/main/java/com/seafile/seadroid2/ui/dialog/SslConfirmDialog.java
index 747149ce7..c448c3fc8 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/dialog/SslConfirmDialog.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/dialog/SslConfirmDialog.java
@@ -115,7 +115,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
binding.notAfter.setText(not_available);
}
- builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+ builder.setPositiveButton(R.string.ignore, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(DEBUG_TAG, "listener.onAccepted is called");
@@ -123,7 +123,7 @@ public void onClick(DialogInterface dialog, int which) {
}
});
- builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
+ builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(DEBUG_TAG, "listener.onRejected is called");
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/SignOutDialogFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/SignOutDialogFragment.java
index e92e93430..4be88cd17 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/SignOutDialogFragment.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/SignOutDialogFragment.java
@@ -8,6 +8,7 @@
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.SupportAccountManager;
import com.seafile.seadroid2.account.AccountUtils;
+import com.seafile.seadroid2.ssl.CertsManager;
import com.seafile.seadroid2.ui.base.fragment.CustomDialogFragment;
public class SignOutDialogFragment extends CustomDialogFragment {
@@ -34,6 +35,7 @@ public int getDialogTitleRes() {
protected void onPositiveClick() {
Account account = SupportAccountManager.getInstance().getCurrentAccount();
+ CertsManager.instance().deleteCertForAccount(account);
AccountUtils.logout(account);
refreshData();
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewDirViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewDirViewModel.java
index 4fb497a1c..40f1c1db5 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewDirViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewDirViewModel.java
@@ -39,7 +39,7 @@ public void createNewDir(String p, String repo_id) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("operation", "mkdir");
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(DialogService.class).createDir(repo_id, p, bodyMap);
addSingleDisposable(single, new Consumer() {
@@ -77,7 +77,7 @@ public void createNewFile(String filePathName, String repo_id) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("operation", "create");
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(DialogService.class).createFile(repo_id, filePathName, bodyMap);
addSingleDisposable(single, new Consumer() {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewRepoViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewRepoViewModel.java
index 09958fa5c..e3163a7cb 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewRepoViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/NewRepoViewModel.java
@@ -40,7 +40,7 @@ public void createNewRepo(String repoName, String description, String password)
if (!TextUtils.isEmpty(password)) {
requestDataMap.put("passwd", password);
}
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(DialogService.class).createRepo(bodyMap);
addSingleDisposable(single, new Consumer() {
@Override
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/PasswordViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/PasswordViewModel.java
index 61642b09c..a5dde46cd 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/PasswordViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/PasswordViewModel.java
@@ -135,7 +135,7 @@ private void remoteVerify(RepoModel repoModel, String password) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("password", password);
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single netSingle = HttpIO.getCurrentInstance().execute(DialogService.class).setPassword(repoModel.repo_id, bodyMap);
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/RenameRepoViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/RenameRepoViewModel.java
index 13300d1d5..b9f331461 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/RenameRepoViewModel.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/dialog_fragment/viewmodel/RenameRepoViewModel.java
@@ -38,7 +38,7 @@ public void renameRepo(String repoName, String repoId) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("repo_name", repoName);
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(DialogService.class).renameRepo(repoId, bodyMap);
@@ -64,7 +64,7 @@ public void renameDir(String repoId, String curPath, String newName) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("operation", "rename");
requestDataMap.put("newname", newName);
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(DialogService.class).renameDir(repoId, curPath, bodyMap);
@@ -90,7 +90,7 @@ public void renameFile(String repoId, String curPath, String newName) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("operation", "rename");
requestDataMap.put("newname", newName);
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(DialogService.class).renameFile(repoId, curPath, bodyMap);
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentAdapter.java
similarity index 60%
rename from app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentAdapter.java
rename to app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentAdapter.java
index 7037b50fd..41014c5fa 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentAdapter.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentAdapter.java
@@ -1,4 +1,4 @@
-package com.seafile.seadroid2.ui.sdoc.comments;
+package com.seafile.seadroid2.ui.docs_comment;
import static com.seafile.seadroid2.config.Constants.DP.DP_4;
import static com.seafile.seadroid2.config.Constants.DP.DP_8;
@@ -7,7 +7,9 @@
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -20,9 +22,15 @@
import com.bumptech.glide.Glide;
import com.google.android.flexbox.FlexboxLayout;
import com.seafile.seadroid2.R;
-import com.seafile.seadroid2.databinding.ItemSdocCommentBinding;
-import com.seafile.seadroid2.framework.data.model.sdoc.SDocCommentModel;
+import com.seafile.seadroid2.config.GlideLoadConfig;
+import com.seafile.seadroid2.databinding.ItemFileCommentBinding;
+import com.seafile.seadroid2.databinding.LayoutImageBinding;
+import com.seafile.seadroid2.framework.data.model.docs_comment.DocsCommentModel;
+import com.seafile.seadroid2.framework.util.GlideApp;
+import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.ui.base.adapter.BaseAdapter;
+import com.seafile.seadroid2.view.rich_edittext.RichEditText;
+import com.seafile.seadroid2.widget.SimpleMarkdownParser;
import com.yydcdut.markdown.MarkdownConfiguration;
import com.yydcdut.markdown.MarkdownProcessor;
import com.yydcdut.markdown.MarkdownTextView;
@@ -33,7 +41,7 @@
import java.util.Locale;
import java.util.Objects;
-public class SDocCommentAdapter extends BaseAdapter {
+public class DocsCommentAdapter extends BaseAdapter {
public static int SCREEN_WIDTH = ScreenUtils.getScreenWidth();
public static int WIDTH = SizeUtils.dp2px(120);
public static int IMAGE_WIDTH = (SCREEN_WIDTH - WIDTH) / 3;
@@ -56,7 +64,7 @@ private MarkdownProcessor getProcessor() {
}
@Override
- protected void onBindViewHolder(@NonNull SDocCommentViewHolder holder, int i, @Nullable SDocCommentModel model) {
+ protected void onBindViewHolder(@NonNull DocsCommentViewHolder holder, int i, @Nullable DocsCommentModel model) {
if (model == null) {
return;
}
@@ -69,83 +77,88 @@ protected void onBindViewHolder(@NonNull SDocCommentViewHolder holder, int i, @N
holder.binding.commentNickName.setText(model.user_name);
holder.binding.commentTime.setText(model.getCreatedAtFriendlyText());
-// if (TextUtils.isEmpty(model.resolved) || "false".equals(model.resolved.toLowerCase(Locale.getDefault()))) {
-// holder.binding.commentContentContainer.setBackgroundResource(R.drawable.shape_stroke1_radius8_solid_grey);
-// } else {
- holder.binding.commentContentContainer.setBackgroundResource(R.drawable.shape_stroke1_radius8_solid_white);
-// }
+ if (model.resolved) {
+ holder.binding.container.setBackgroundResource(R.color.comment_resolved_color);
+ holder.binding.commentResolved.setVisibility(View.VISIBLE);
+ } else {
+ holder.binding.commentResolved.setVisibility(View.INVISIBLE);
+ holder.binding.container.setBackgroundResource(R.color.window_background_color);
+ }
holder.binding.commentContentContainer.removeAllViews();
- appendTextToFlex(holder.binding.commentContentContainer, model.comment);
+ addViews(holder, model);
}
-// //![](https://dev.seafile.com/e-Hek4ng6iRbCw7h-bXsc6jA.png)\n是是是\n
-// private void addViews(SDocCommentModel model, SDocCommentViewHolder holder) {
-// int index = 0;
-// for (RichEditText.RichContentModel commentModel : model.commentList) {
+ //![](https://dev.seafile.com/e-Hek4ng6iRbCw7h-bXsc6jA.png)\n是是是\n
+ private void addViews(DocsCommentViewHolder holder, DocsCommentModel model) {
+ int index = 0;
+ for (RichEditText.RichContentModel commentModel : model.commentList) {
// //0 is text, 1 is image
-// if (commentModel.type == 0) {
-// appendTextToFlex(holder.binding.commentContentContainer, commentModel.content, model.isContainImage);
-// } else {
-// appendImageToFlex(holder.binding.commentContentContainer, model.commentList, commentModel.content, index);
-// index++;
-// }
-// }
-// }
+ if (commentModel.type == 0) {
+ appendMovementTextToFlex(holder.binding.commentContentContainer, commentModel.content);
+ } else {
+ appendImageToFlex(holder.binding.commentContentContainer, model.commentList, commentModel.content, index);
+ index++;
+ }
+ }
+ }
@NonNull
@Override
- protected SDocCommentViewHolder onCreateViewHolder(@NonNull Context context, @NonNull ViewGroup viewGroup, int i) {
- ItemSdocCommentBinding binding = ItemSdocCommentBinding.inflate(LayoutInflater.from(context), viewGroup, false);
- return new SDocCommentViewHolder(binding);
+ protected DocsCommentViewHolder onCreateViewHolder(@NonNull Context context, @NonNull ViewGroup viewGroup, int i) {
+ ItemFileCommentBinding binding = ItemFileCommentBinding.inflate(LayoutInflater.from(context), viewGroup, false);
+ return new DocsCommentViewHolder(binding);
}
-// public void appendImageToFlex(FlexboxLayout parent, List commentList, String url, int position) {
-// LayoutImageBinding fileBinding = LayoutImageBinding.inflate(LayoutInflater.from(getContext()));
-// fileBinding.uploadImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
-//
-// FlexboxLayout.LayoutParams f = new FlexboxLayout.LayoutParams(IMAGE_WIDTH, IMAGE_WIDTH);
-// f.setMargins(DP_4, DP_4, DP_4, DP_4);
-// fileBinding.getRoot().setLayoutParams(f);
-//
-// Glide.with(getContext())
-// .load(GlideLoadConfig.getGlideUrl(url))
-// .apply(GlideLoadConfig.getOptions(IMAGE_WIDTH, IMAGE_WIDTH))
-// .into(fileBinding.uploadImage);
-// fileBinding.uploadImage.setOnClickListener(new View.OnClickListener() {
-// @Override
-// public void onClick(View v) {
+ public void appendImageToFlex(FlexboxLayout parent, List commentList, String url, int position) {
+ LayoutImageBinding fileBinding = LayoutImageBinding.inflate(LayoutInflater.from(getContext()));
+ fileBinding.uploadImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
+
+ FlexboxLayout.LayoutParams f = new FlexboxLayout.LayoutParams(IMAGE_WIDTH, IMAGE_WIDTH);
+ f.setMargins(DP_4, DP_4, DP_4, DP_4);
+ fileBinding.getRoot().setLayoutParams(f);
+
+ GlideApp.with(getContext())
+ .load(url)
+ .apply(GlideLoadConfig.getOptions())
+ .into(fileBinding.uploadImage);
+
+ fileBinding.uploadImage.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
// List ll = commentList.stream().filter(f -> f.type == 1).map(m -> m.content).collect(Collectors.toList());
// MediaPlayerModel model = new MediaPlayerModel();
// model.index = position;
// model.urls = ll;
// MediaPlayerActivity.startThis(getContext(), model);
-// }
-// });
-//
-//
-// parent.addView(fileBinding.getRoot());
-// }
-
- public void appendTextToFlex(FlexboxLayout parent, String comment) {
+ }
+ });
+
+
+ parent.addView(fileBinding.getRoot());
+ }
+
+
+ public void appendMovementTextToFlex(FlexboxLayout parent, String text) {
+
MarkdownTextView textView = new MarkdownTextView(getContext());
textView.setPadding(DP_4, DP_8, DP_4, DP_8);
-// textView.setText(getProcessor().parse(comment));
- textView.setText(comment);
+ textView.setText(getProcessor().parse(text));
+// textView.setText(text);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setId(android.R.id.text1);
textView.setTextSize(14);
- textView.setTextColor(ContextCompat.getColor(getContext(), R.color.material_blue_grey_900));
+ textView.setTextColor(ContextCompat.getColor(getContext(), R.color.item_title_color));
FlexboxLayout.LayoutParams f = new FlexboxLayout.LayoutParams(-1, -2);
parent.addView(textView, f);
}
- public void submitData(List list) {
+ public void submitData(List list) {
if (CollectionUtils.isEmpty(list)) {
submitList(list);
return;
@@ -167,15 +180,15 @@ public int getNewListSize() {
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
- SDocCommentModel newT = getItems().get(oldItemPosition);
- SDocCommentModel oldT = list.get(newItemPosition);
+ DocsCommentModel newT = getItems().get(oldItemPosition);
+ DocsCommentModel oldT = list.get(newItemPosition);
return newT.id == oldT.id;
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
- SDocCommentModel newT = getItems().get(oldItemPosition);
- SDocCommentModel oldT = list.get(newItemPosition);
+ DocsCommentModel newT = getItems().get(oldItemPosition);
+ DocsCommentModel oldT = list.get(newItemPosition);
return newT.id == oldT.id
&& Objects.equals(newT.resolved, oldT.resolved)
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentUserAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentUserAdapter.java
similarity index 83%
rename from app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentUserAdapter.java
rename to app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentUserAdapter.java
index f36926541..52dbed7f7 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentUserAdapter.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentUserAdapter.java
@@ -1,4 +1,4 @@
-package com.seafile.seadroid2.ui.sdoc.comments;
+package com.seafile.seadroid2.ui.docs_comment;
import android.content.Context;
import android.text.TextUtils;
@@ -15,9 +15,9 @@
import com.seafile.seadroid2.framework.data.model.user.UserModel;
import com.seafile.seadroid2.ui.base.adapter.BaseAdapter;
-public class SDocCommentUserAdapter extends BaseAdapter {
+public class DocsCommentUserAdapter extends BaseAdapter {
@Override
- protected void onBindViewHolder(@NonNull SDocCommentUserViewHolder holder, int i, @Nullable UserModel model) {
+ protected void onBindViewHolder(@NonNull DocsCommentUserViewHolder holder, int i, @Nullable UserModel model) {
if (i == 0) {
setMargins(holder.binding.itemUserContainer, 0, 0, 0, 0);
@@ -39,9 +39,9 @@ protected void onBindViewHolder(@NonNull SDocCommentUserViewHolder holder, int i
@NonNull
@Override
- protected SDocCommentUserViewHolder onCreateViewHolder(@NonNull Context context, @NonNull ViewGroup viewGroup, int i) {
+ protected DocsCommentUserViewHolder onCreateViewHolder(@NonNull Context context, @NonNull ViewGroup viewGroup, int i) {
ItemUserAvatarBinding binding = ItemUserAvatarBinding.inflate(LayoutInflater.from(context), viewGroup, false);
- return new SDocCommentUserViewHolder(binding);
+ return new DocsCommentUserViewHolder(binding);
}
public void setMargins(View v, int l, int t, int r, int b) {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentUserViewHolder.java b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentUserViewHolder.java
similarity index 63%
rename from app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentUserViewHolder.java
rename to app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentUserViewHolder.java
index 2cd81d913..9251ed842 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/comments/SDocCommentUserViewHolder.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentUserViewHolder.java
@@ -1,15 +1,15 @@
-package com.seafile.seadroid2.ui.sdoc.comments;
+package com.seafile.seadroid2.ui.docs_comment;
import androidx.annotation.NonNull;
import com.seafile.seadroid2.databinding.ItemUserAvatarBinding;
import com.seafile.seadroid2.ui.base.viewholder.BaseViewHolder;
-public class SDocCommentUserViewHolder extends BaseViewHolder {
+public class DocsCommentUserViewHolder extends BaseViewHolder {
public ItemUserAvatarBinding binding;
- public SDocCommentUserViewHolder(@NonNull ItemUserAvatarBinding binding) {
+ public DocsCommentUserViewHolder(@NonNull ItemUserAvatarBinding binding) {
super(binding.getRoot());
this.binding = binding;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewHolder.java b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewHolder.java
new file mode 100644
index 000000000..9e13d8f22
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentViewHolder.java
@@ -0,0 +1,17 @@
+package com.seafile.seadroid2.ui.docs_comment;
+
+import androidx.annotation.NonNull;
+
+import com.seafile.seadroid2.databinding.ItemFileCommentBinding;
+import com.seafile.seadroid2.ui.base.viewholder.BaseViewHolder;
+
+public class DocsCommentViewHolder extends BaseViewHolder {
+
+ public ItemFileCommentBinding binding;
+
+ public DocsCommentViewHolder(@NonNull ItemFileCommentBinding binding) {
+ super(binding.getRoot());
+
+ this.binding = binding;
+ }
+}
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
new file mode 100644
index 000000000..ae718ec94
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/docs_comment/DocsCommentsActivity.java
@@ -0,0 +1,330 @@
+package com.seafile.seadroid2.ui.docs_comment;
+
+import android.animation.ValueAnimator;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+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;
+import com.blankj.utilcode.util.ToastUtils;
+import com.chad.library.adapter4.BaseQuickAdapter;
+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;
+import com.seafile.seadroid2.framework.data.model.docs_comment.DocsCommentsWrapperModel;
+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;
+
+import io.reactivex.functions.Consumer;
+
+public class DocsCommentsActivity extends BaseMediaSelectorActivity {
+ private ActivityDocCommentBinding binding;
+ private ToolbarActionbarBinding bindingOfToolbar;
+
+ private Toolbar toolbar;
+
+ private DocsCommentAdapter adapter;
+ private DocsCommentUserAdapter userAdapter;
+
+ private SDocPageOptionsModel pageOptionsModel;
+
+ public static void start(Context context, SDocPageOptionsModel pageModel) {
+ Intent starter = new Intent(context, DocsCommentsActivity.class);
+ starter.putExtra("pageOption", pageModel);
+ context.startActivity(starter);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ binding = ActivityDocCommentBinding.inflate(getLayoutInflater());
+ bindingOfToolbar = ToolbarActionbarBinding.bind(binding.toolbar.getRoot());
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+ setContentView(binding.getRoot());
+
+ if (getIntent() == null || !getIntent().hasExtra("pageOption")) {
+ throw new IllegalArgumentException("pageOption is null");
+ }
+
+ pageOptionsModel = getIntent().getParcelableExtra("pageOption");
+
+ initView();
+
+ initViewModel();
+
+ initAdapter();
+
+ refreshData();
+
+ }
+
+
+ private final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
+
+ private void initView() {
+ toolbar = bindingOfToolbar.toolbarActionbar;
+
+ toolbar.setTitle("");
+ setSupportActionBar(toolbar);
+ toolbar.setTitle(pageOptionsModel.docName);
+
+ toolbar.setNavigationOnClickListener(v -> {
+ finish();
+ });
+
+ //refresh listener
+ binding.swipeRefreshLayout.setOnRefreshListener(this::refreshData);
+
+ binding.rv.setLayoutManager(linearLayoutManager);
+
+ binding.photoView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showPickPhotoSheetDialog(false);
+ }
+ });
+
+// //
+// LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
+// binding.rvUserList.setLayoutManager(linearLayoutManager);
+
+ binding.submit.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ submitData();
+ }
+ });
+//
+// binding.richEditText.setOnRichAtListener(new OnRichAtListener() {
+// @Override
+// public void onCall(EditText editText) {
+// showCollaboratorSelector(editText);
+// }
+// });
+ }
+
+
+ protected void initViewModel() {
+ getViewModel().getRefreshLiveData().observe(this, new Observer() {
+ @Override
+ public void onChanged(Boolean aBoolean) {
+ binding.swipeRefreshLayout.setRefreshing(aBoolean);
+ }
+ });
+
+ getViewModel().getPostCommentLiveData().observe(this, new Observer() {
+ @Override
+ public void onChanged(Boolean model) {
+ //remove all
+ binding.richEditText.removeAllViews();
+
+
+ refreshData();
+ }
+ });
+
+// getViewModel().getUserListLiveData().observe(this, new Observer>() {
+// @Override
+// public void onChanged(List relatedUserModels) {
+// userAdapter.submitList(relatedUserModels);
+// }
+// });
+ getViewModel().getSdocCommentLiveData().observe(this, new Observer() {
+ @Override
+ public void onChanged(DocsCommentsWrapperModel model) {
+ adapter.setStateViewEnable(true);
+ adapter.submitData(model.comments);
+
+ linearLayoutManager.smoothScrollToPosition(binding.rv, null, adapter.getItemCount() - 1);
+
+ }
+ });
+ }
+
+
+ private void initAdapter() {
+// userAdapter = new DocsCommentUserAdapter();
+// userAdapter.setAnimationEnable(true);
+//
+// userAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
+// @Override
+// public void onClick(@NonNull BaseQuickAdapter baseQuickAdapter, @NonNull View view, int i) {
+// if (CollectionUtils.isEmpty(userAdapter.getItems())) {
+// return;
+// }
+//
+//// showCollaboratorSelector();
+// }
+// });
+// binding.rvUserList.setAdapter(userAdapter);
+//
+// if (CollectionUtils.isEmpty(strategyModel.participants)) {
+// binding.rvUserList.setVisibility(View.GONE);
+// } else {
+// userAdapter.submitList(strategyModel.participants);
+// }
+
+ adapter = new DocsCommentAdapter();
+ adapter.setStateViewLayout(this, R.layout.layout_empty);
+ adapter.setStateViewEnable(false);
+ adapter.setAnimationEnable(true);
+
+ adapter.addOnItemChildClickListener(R.id.comment_more, new BaseQuickAdapter.OnItemChildClickListener() {
+ @Override
+ public void onItemClick(@NonNull BaseQuickAdapter baseQuickAdapter, @NonNull View view, int i) {
+// buildMoreDialog(i);
+ initPopupMenu(i, view);
+ }
+ });
+
+ QuickAdapterHelper helper = new QuickAdapterHelper.Builder(adapter).build();
+ binding.rv.setAdapter(helper.getAdapter());
+ }
+
+ private void initPopupMenu(int position, View showView) {
+ DocsCommentModel model = adapter.getItems().get(position);
+
+ PopupMenu popupMenu = new PopupMenu(this, showView);
+ popupMenu.getMenuInflater().inflate(R.menu.menu_comment_mark_delete, popupMenu.getMenu());
+ popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == R.id.mark_resolve) {
+ getViewModel().markResolve(pageOptionsModel.seadocServerUrl, pageOptionsModel.seadocAccessToken, pageOptionsModel.docUuid, model.id, new Consumer() {
+ @Override
+ public void accept(Long aLong) throws Exception {
+ model.resolved = true;
+ adapter.set(position, model);
+ }
+ });
+ } else if (item.getItemId() == R.id.delete) {
+ showDeleteDialog(position, model.id);
+ }
+ return false;
+ }
+ });
+ popupMenu.show();
+ }
+
+ private void showDeleteDialog(int position, int cId) {
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+ builder.setTitle(R.string.delete_confirm);
+ builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getViewModel().delete(pageOptionsModel.seadocServerUrl, pageOptionsModel.seadocAccessToken, pageOptionsModel.docUuid, cId, new Consumer() {
+ @Override
+ public void accept(Long aLong) throws Exception {
+ adapter.removeAt(position);
+ }
+ });
+ }
+ });
+
+ builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ builder.show();
+ }
+
+ private void refreshData() {
+ getViewModel().loadDocComments(pageOptionsModel);
+ }
+
+ public void onMediaPicked(Uri uri) {
+ super.onMediaPicked(uri);
+ uploadFile(uri);
+ }
+
+
+ private void uploadFile(Uri o) {
+ if (null == o) {
+ return;
+ }
+
+ SLogs.d(o.toString());
+
+ binding.richEditText.insertImage(o);
+
+ ContentResolver contentResolver = getContentResolver();
+// https://dev.seafile.com/seafhttp/repos/bc1db6db-afa8-4e85-8479-6eb3f50f3d1c/files/images/sdoc/e4c22460-e99d-4687-9081-1f30d156625d/image-UFB28ta7TVOskNE0uAZ_Ww.jpeg/?op=download
+// https://dev.seafile.com/seahub/lib/bc1db6db-afa8-4e85-8479-6eb3f50f3d1c/file/images/sdoc/e4c22460-e99d-4687-9081-1f30d156625d/image-UFB28ta7TVOskNE0uAZ_Ww.jpeg
+// https://dev.seafile.com/seafhttp/files/73372487-3bb8-4f1d-925e-6e21bb72305c/image-UFB28ta7TVOskNE0uAZ_Ww.jpeg
+// https://dev.seafile.com/seafhttp/files/b1d6e2d7-8b28-4a8e-af93-f3ca70bf51ea/image-UFB28ta7TVOskNE0uAZ_Ww.jpeg
+// https://dev.seafile.com/seahub/api/v2.1/seadoc/download-image/e4c22460-e99d-4687-9081-1f30d156625d/image-UFB28ta7TVOskNE0uAZ_Ww.jpeg
+ //upload file
+ getViewModel().uploadFile(contentResolver, o, pageOptionsModel.docUuid, pageOptionsModel.seadocAccessToken, new Consumer() {
+ @Override
+ public void accept(String absUrl) throws Exception {
+ binding.richEditText.updateUploadState(o.toString(), absUrl);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(String s) throws Exception {
+ ToastUtils.showLong(R.string.upload_failed);
+ }
+ });
+ }
+
+ private void submitData() {
+ //
+ KeyboardUtils.hideSoftInput(getWindow());
+
+ List models = binding.richEditText.buildRichEditData();
+ if (CollectionUtils.isEmpty(models)) {
+ return;
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ models.forEach(f -> {
+ if (f.type == 0) {
+ sb.append(f.content).append("\n\n");
+ } else if (f.type == 1) {
+ sb.append("![](").append(f.content).append(")");
+ }
+ });
+
+ if (TextUtils.isEmpty(sb.toString())) {
+ return;
+ }
+
+ getViewModel().postComment(pageOptionsModel, sb.toString(), "0");
+ }
+}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/profile/SDocProfileDialog.java b/app/src/main/java/com/seafile/seadroid2/ui/file_profile/FileProfileDialog.java
similarity index 92%
rename from app/src/main/java/com/seafile/seadroid2/ui/sdoc/profile/SDocProfileDialog.java
rename to app/src/main/java/com/seafile/seadroid2/ui/file_profile/FileProfileDialog.java
index a8d9086f7..118c35f94 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/sdoc/profile/SDocProfileDialog.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/file_profile/FileProfileDialog.java
@@ -1,4 +1,4 @@
-package com.seafile.seadroid2.ui.sdoc.profile;
+package com.seafile.seadroid2.ui.file_profile;
import static com.seafile.seadroid2.config.Constants.DP.DP_4;
@@ -22,8 +22,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.SizeUtils;
@@ -33,17 +31,16 @@
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.imageview.ShapeableImageView;
-import com.google.android.material.internal.ViewUtils;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.config.ColumnType;
import com.seafile.seadroid2.config.GlideLoadConfig;
-import com.seafile.seadroid2.databinding.DialogSdocProfileBinding;
+import com.seafile.seadroid2.databinding.DialogFileProfileBinding;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileDetailModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileRecordWrapperModel;
import com.seafile.seadroid2.framework.data.model.sdoc.MetadataConfigDataModel;
import com.seafile.seadroid2.framework.data.model.sdoc.MetadataModel;
import com.seafile.seadroid2.framework.data.model.sdoc.OptionsTagModel;
import com.seafile.seadroid2.framework.data.model.sdoc.RecordResultModel;
-import com.seafile.seadroid2.framework.data.model.sdoc.SDocDetailModel;
-import com.seafile.seadroid2.framework.data.model.sdoc.SDocRecordWrapperModel;
import com.seafile.seadroid2.framework.data.model.user.UserModel;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.util.Utils;
@@ -55,15 +52,16 @@
import java.util.List;
import java.util.Optional;
+public class FileProfileDialog extends BottomSheetDialogFragment {
-public class SDocProfileDialog extends BottomSheetDialogFragment {
-
- private SDocDetailModel docDetailModel;
- private SDocRecordWrapperModel recordWrapperModel;
+ private FileDetailModel docDetailModel;
+ private FileRecordWrapperModel recordWrapperModel;
private ArrayList relatedUsers;
+ private boolean isShowTitle = false;
- public static SDocProfileDialog newInstance(SDocDetailModel docDetailModel, SDocRecordWrapperModel recordWrapperModel, List relatedUsers) {
+ public static FileProfileDialog newInstance(FileDetailModel docDetailModel, FileRecordWrapperModel recordWrapperModel, List relatedUsers, boolean isShowTitle) {
Bundle args = new Bundle();
+ args.putBoolean("isShowTitle", isShowTitle);
args.putParcelable("detailModel", docDetailModel);
if (!CollectionUtils.isEmpty(relatedUsers)) {
@@ -74,13 +72,17 @@ public static SDocProfileDialog newInstance(SDocDetailModel docDetailModel, SDoc
args.putParcelableArrayList("relatedUsers", new ArrayList<>(relatedUsers));
}
- SDocProfileDialog fragment = new SDocProfileDialog();
+ FileProfileDialog fragment = new FileProfileDialog();
fragment.setArguments(args);
return fragment;
}
- public static SDocProfileDialog newInstance(SDocDetailModel docDetailModel, List relatedUsers) {
- return newInstance(docDetailModel, null, relatedUsers);
+ public static FileProfileDialog newInstance(FileDetailModel docDetailModel, List relatedUsers) {
+ return newInstance(docDetailModel, null, relatedUsers, false);
+ }
+
+ public static FileProfileDialog newInstance(FileDetailModel docDetailModel, List relatedUsers, boolean isShowTitle) {
+ return newInstance(docDetailModel, null, relatedUsers, isShowTitle);
}
@Override
@@ -91,6 +93,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
throw new IllegalArgumentException("detailModel is null");
}
+ isShowTitle = getArguments().getBoolean("isShowTitle");
docDetailModel = getArguments().getParcelable("detailModel");
recordWrapperModel = getArguments().getParcelable("recordModel");
relatedUsers = getArguments().getParcelableArrayList("relatedUsers");
@@ -102,12 +105,12 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
initFixedValueIfMetadataNotEnable();
}
- DialogSdocProfileBinding profileBinding;
+ private DialogFileProfileBinding profileBinding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- profileBinding = DialogSdocProfileBinding.inflate(inflater, container, false);
+ profileBinding = DialogFileProfileBinding.inflate(inflater, container, false);
return profileBinding.getRoot();
}
@@ -115,33 +118,18 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
- BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(requireContext());
-// View bottomSheetInternal = bottomSheetDialog.findViewById(R.id.design_bottom_sheet);
-// BottomSheetBehavior.from(bottomSheetInternal).setPeekHeight(800);
-
-// View bottomSheetContent = bottomSheetInternal.findViewById(R.id.bottom_drawer_2);
-// ViewUtils.doOnApplyWindowInsets(bottomSheetContent, new ViewUtils.OnApplyWindowInsetsListener() {
-// @Override
-// public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets, ViewUtils.RelativePadding initialPadding) {
-// // Add the inset in the inner NestedScrollView instead to make the edge-to-edge behavior
-// // consistent - i.e., the extra padding will only show at the bottom of all content, i.e.,
-// // only when you can no longer scroll down to show more content.
-// ViewCompat.setPaddingRelative(bottomSheetContent,
-// initialPadding.start,
-// initialPadding.top,
-// initialPadding.end,
-// initialPadding.bottom + insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom);
-// return insets;
-// }
-// });
-
- return bottomSheetDialog;
+ return new BottomSheetDialog(requireContext());
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ if (isShowTitle) {
+ profileBinding.title.setVisibility(View.VISIBLE);
+ profileBinding.title.setText(docDetailModel.getName());
+ }
+
setData(profileBinding.detailsContainer);
}
@@ -149,7 +137,7 @@ private void initFixedValueIfMetadataNotEnable() {
if (recordWrapperModel != null) {
return;
}
- recordWrapperModel = new SDocRecordWrapperModel();
+ recordWrapperModel = new FileRecordWrapperModel();
RecordResultModel sizeModel = new RecordResultModel();
sizeModel._size = docDetailModel.getSize();
@@ -205,6 +193,7 @@ private void addMetadataView(LinearLayout parent, MetadataModel metadata) {
parseViewByType(getContext(), parent, metadata);
}
+ //not support: _tags
private final List _fixedField = List.of("_size", "_file_modifier", "_file_mtime", "_description", "_collaborators", "_reviewer", "_status");
private Object getValueByKey(String key) {
@@ -250,6 +239,8 @@ private int getResNameByKey(String key) {
return R.string._done;
case "_outdated":
return R.string._outdated;
+ case "_tags":
+ return R.string._tags;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -506,10 +497,6 @@ private void parseSingleSelect(LinearLayout view, MetadataModel model) {
textView.setText(option.name);
}
-
-// if (!TextUtils.isEmpty(option.borderColor)) {
-// }
-
if (!TextUtils.isEmpty(option.textColor)) {
textView.setTextColor(Color.parseColor(option.textColor));
}
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 3cdc20e98..8703ecb37 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
@@ -37,7 +37,6 @@
import com.blankj.utilcode.util.ToastUtils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.navigation.NavigationBarView;
-import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.account.Account;
@@ -159,11 +158,7 @@ private void initFireBase() {
if (account != null) {
FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
crashlytics.setUserId(account.getSignature());
-
- FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(this);
- analytics.setUserId(account.getSignature());
}
-
}
private void initOnBackPressedDispatcher() {
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_info/FileDetailViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_info/FileDetailViewModel.java
new file mode 100644
index 000000000..de54a2ca1
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_info/FileDetailViewModel.java
@@ -0,0 +1,7 @@
+package com.seafile.seadroid2.ui.media.image_info;
+
+import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
+
+public class FileDetailViewModel extends BaseViewModel {
+
+}
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
index e827618e0..5d67f4232 100644
--- 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
@@ -34,6 +34,7 @@
import io.reactivex.functions.Consumer;
+@Deprecated
public class ImagePreviewActivity extends BaseActivityWithVM {
private ActivityImagePreviewBinding binding;
private ViewPager2Adapter adapter;
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 119b9402d..b3a380029 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
@@ -14,11 +14,16 @@
import com.seafile.seadroid2.framework.data.db.entities.RepoModel;
import com.seafile.seadroid2.framework.data.model.ResultModel;
import com.seafile.seadroid2.framework.data.model.repo.Dirent2Model;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileDetailModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.MetadataConfigModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileProfileConfigModel;
+import com.seafile.seadroid2.framework.data.model.user.UserWrapperModel;
import com.seafile.seadroid2.framework.util.SLogs;
import com.seafile.seadroid2.framework.util.Utils;
import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl;
import com.seafile.seadroid2.framework.http.HttpIO;
import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel;
+import com.seafile.seadroid2.ui.sdoc.DocsCommentService;
import com.seafile.seadroid2.ui.star.StarredService;
import java.util.HashMap;
@@ -29,8 +34,8 @@
import io.reactivex.Single;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
+import io.reactivex.functions.Function3;
import okhttp3.RequestBody;
-import prettify.parser.Util;
public class ImagePreviewViewModel extends BaseViewModel {
private final MutableLiveData> ListLiveData = new MutableLiveData<>();
@@ -49,6 +54,43 @@ public MutableLiveData> getListLiveData() {
return ListLiveData;
}
+ private final MutableLiveData _fileProfileConfigLiveData = new MutableLiveData<>();
+
+ public MutableLiveData getFileDetailLiveData() {
+ return _fileProfileConfigLiveData;
+ }
+
+ 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() {
+ @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);
+ getRefreshLiveData().setValue(false);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(Throwable throwable) throws Exception {
+ getRefreshLiveData().setValue(false);
+ }
+ });
+ }
public void getRepoModelFromDB(String repoId, Consumer consumer) {
//from db
@@ -170,7 +212,7 @@ public void star(String repoId, String path) {
Map requestDataMap = new HashMap<>();
requestDataMap.put("repo_id", repoId);
requestDataMap.put("path", path);
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(StarredService.class).star(bodyMap);
addSingleDisposable(single, new Consumer() {
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 b71c3192a..22fe23c69 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
@@ -40,7 +40,7 @@ public class PhotoFragment extends BaseFragment {
private OnPhotoTapListener onPhotoTapListener;
private FragmentPhotoViewBinding binding;
- private boolean isLight = true;
+
public void setOnPhotoTapListener(OnPhotoTapListener onPhotoTapListener) {
this.onPhotoTapListener = onPhotoTapListener;
@@ -107,14 +107,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
binding.photoView.setOnPhotoTapListener(new OnPhotoTapListener() {
@Override
public void onPhotoTap(ImageView view, float x, float y) {
- if (!isLight){
- binding.rootLayout.setBackgroundColor(ContextCompatKt.getColorCompat(requireContext(),R.color.material_grey_100));
- }else{
- binding.rootLayout.setBackgroundColor(ContextCompatKt.getColorCompat(requireContext(),R.color.material_grey_919));
- }
-
- isLight =!isLight;
-
if (onPhotoTapListener != null) {
onPhotoTapListener.onPhotoTap(view, x, y);
}
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 3e824b608..04e15a79a 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
@@ -21,24 +21,28 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
+import androidx.recyclerview.widget.RecyclerView;
import com.blankj.utilcode.util.EncodeUtils;
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.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.util.GlideApp;
-public class CarouselAdapter extends ListAdapter {
+public class CarouselAdapter extends ListAdapter {
private static final DiffUtil.ItemCallback DIFF_CALLBACK =
new DiffUtil.ItemCallback<>() {
@@ -110,6 +114,7 @@ public void onBindViewHolder(@NonNull CarouselItemViewHolder carouselItemViewHol
private void bind(CarouselItemViewHolder holder, int pos) {
DirentModel model = getItem(pos);
+// holder.textView.setText(pos + "");
holder.itemView.setOnClickListener(v -> {
listener.onItemClicked(model, pos);
@@ -157,4 +162,18 @@ private String getUrl(String repoId, String fullPath) {
int size = SizeUtils.dp2px(300);
return String.format("%sapi2/repos/%s/thumbnail/?p=%s&size=%s", account.getServer(), repoId, EncodeUtils.urlEncode(fullPath), size);
}
+
+
+ public static class CarouselItemViewHolder extends RecyclerView.ViewHolder {
+
+ public final ImageView imageView;
+ public final TextView textView;
+
+ CarouselItemViewHolder(@NonNull View itemView) {
+ super(itemView);
+ imageView = itemView.findViewById(R.id.image_view);
+ textView = itemView.findViewById(R.id.text_view);
+ }
+
+ }
}
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 d71ec250f..576ece89d 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
@@ -1,5 +1,6 @@
package com.seafile.seadroid2.ui.media.image_preview2;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -12,32 +13,45 @@
import android.view.ViewGroup;
import androidx.activity.OnBackPressedCallback;
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.widget.Toolbar;
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.compat.ContextCompatKt;
+import com.seafile.seadroid2.context.CopyMoveContext;
import com.seafile.seadroid2.databinding.ActivityCarouselImagePreviewBinding;
+import com.seafile.seadroid2.enums.OpType;
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.sdoc.FileProfileConfigModel;
+import com.seafile.seadroid2.framework.data.model.search.SearchModel;
import com.seafile.seadroid2.framework.util.Objs;
+import com.seafile.seadroid2.framework.util.Utils;
import com.seafile.seadroid2.ui.adapter.ViewPager2Adapter;
import com.seafile.seadroid2.ui.base.BaseActivityWithVM;
+import com.seafile.seadroid2.ui.dialog_fragment.CopyMoveDialogFragment;
import com.seafile.seadroid2.ui.dialog_fragment.DeleteFileDialogFragment;
import com.seafile.seadroid2.ui.dialog_fragment.listener.OnRefreshDataListener;
+import com.seafile.seadroid2.ui.file_profile.FileProfileDialog;
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 java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
public class CarouselImagePreviewActivity extends BaseActivityWithVM implements Toolbar.OnMenuItemClickListener {
@@ -47,15 +61,14 @@ public class CarouselImagePreviewActivity extends BaseActivityWithVM direntList;
-
+ private List carouselDirentList;
private boolean isLightMode = true;
private boolean isDataOperated = false;
private String repoId, repoName, parentDir, name;
private boolean load_other_images_in_same_directory = false;
- private int carouselItemWidth, carouselItemMargin;
- public static Intent startThisFromRepo(Context context, DirentModel direntModel) {
+ public static Intent startThisFromObjs(Context context, DirentModel direntModel) {
Intent intent = new Intent(context, CarouselImagePreviewActivity.class);
intent.putExtra("repo_id", direntModel.repo_id);
intent.putExtra("repo_name", direntModel.repo_name);
@@ -65,6 +78,36 @@ public static Intent startThisFromRepo(Context context, DirentModel direntModel)
return intent;
}
+ public static Intent startThisFromStarred(Context context, StarredModel model) {
+ Intent intent = new Intent(context, CarouselImagePreviewActivity.class);
+ intent.putExtra("repo_id", model.repo_id);
+ intent.putExtra("repo_name", model.repo_name);
+ intent.putExtra("parent_dir", Utils.getParentPath(model.path));
+ intent.putExtra("name", model.obj_name);
+ intent.putExtra("load_other_images_in_same_directory", false);//Load other images in the same folder
+ return intent;
+ }
+
+ public static Intent startThisFromActivity(Context context, ActivityModel model) {
+ Intent intent = new Intent(context, CarouselImagePreviewActivity.class);
+ intent.putExtra("repo_id", model.repo_id);
+ intent.putExtra("repo_name", model.repo_name);
+ intent.putExtra("parent_dir", Utils.getParentPath(model.path));
+ intent.putExtra("name", model.name);
+ intent.putExtra("load_other_images_in_same_directory", false);//Load other images in the same folder
+ return intent;
+ }
+
+ public static Intent startThisFromSearch(Context context, SearchModel model) {
+ Intent intent = new Intent(context, CarouselImagePreviewActivity.class);
+ intent.putExtra("repo_id", model.repo_id);
+ intent.putExtra("repo_name", model.repo_name);
+ intent.putExtra("parent_dir", Utils.getParentPath(model.fullpath));
+ intent.putExtra("name", model.name);
+ intent.putExtra("load_other_images_in_same_directory", false);//Load other images in the same folder
+ return intent;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -72,7 +115,6 @@ protected void onCreate(Bundle savedInstanceState) {
binding = ActivityCarouselImagePreviewBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
-
// full screen
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -85,10 +127,6 @@ protected void onCreate(Bundle savedInstanceState) {
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) {
@@ -108,8 +146,11 @@ public void handleOnBackPressed() {
initParams();
initView();
+
initAdapter();
initCarouselAdapter();
+ bindPager();
+
initViewModel();
getViewModel().load(repoId, parentDir, name, load_other_images_in_same_directory);
@@ -184,69 +225,59 @@ public void onChanged(Boolean aBoolean) {
notifyCurrentStarredStatus();
}
});
+
+ getViewModel().getFileDetailLiveData().observe(this, new Observer() {
+ @Override
+ public void onChanged(FileProfileConfigModel configModel) {
+
+ DirentModel direntModel = getSelectedDirent();
+ if (direntModel == null) {
+ return;
+ }
+
+ String key = direntModel.full_path;
+ fileDetailHashMap.put(key, configModel);
+
+ showProfileDialog(configModel);
+ }
+ });
}
private void initAdapter() {
adapter = new ViewPager2Adapter(this);
-
- binding.pager.setAdapter(adapter);
binding.pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
-
- gravitySnapHelper.scrollToPosition(position);
-
notifyCurrentStarredStatus();
}
});
+ binding.pager.setAdapter(adapter);
}
private final LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
private final GravitySnapHelper gravitySnapHelper = new GravitySnapHelper(Gravity.CENTER);
private void initCarouselAdapter() {
-
carouselAdapter = new CarouselAdapter(this, new CarouselAdapter.CarouselItemListener() {
@Override
public void onItemClicked(DirentModel item, int snapPosition) {
- ToastUtils.showShort("onItemClicked: " + snapPosition);
- int pageIndex = binding.pager.getCurrentItem();
- if (pageIndex == snapPosition) {
- return;
- }
- binding.pager.setCurrentItem(snapPosition, true);
+ gravitySnapHelper.smoothScrollToPosition(snapPosition);
}
});
binding.recyclerView.setAdapter(carouselAdapter);
binding.recyclerView.setLayoutManager(layoutManager);
- int itemWidth = getResources().getDimensionPixelSize(R.dimen.carousel_item_width);
- int screenWidth = ScreenUtils.getAppScreenWidth();
- int itemMargin = getResources().getDimensionPixelSize(R.dimen.carousel_item_margin);
- int slidePadding = (screenWidth - itemWidth) / 2 - itemMargin;
-
- LinearEdgeDecoration decoration = new LinearEdgeDecoration(slidePadding, slidePadding, RecyclerView.HORIZONTAL, false);
- binding.recyclerView.addItemDecoration(decoration);
-
binding.recyclerView.addOnScrollListener(new CenterScaleXYRecyclerViewScrollListener(this));
- gravitySnapHelper.setSnapListener(new GravitySnapHelper.SnapListener() {
- @Override
- public void onSnap(int snapPosition) {
- int pageIndex = binding.pager.getCurrentItem();
- if (pageIndex == snapPosition) {
- return;
- }
-
- binding.pager.setCurrentItem(snapPosition, true);
- }
- });
-// gravitySnapHelper.setSnapLastItem(true);
gravitySnapHelper.attachToRecyclerView(binding.recyclerView);
}
+ private void bindPager() {
+ PagerSnapBinders.bind(binding.pager, gravitySnapHelper);
+ }
+
private void submitData(Pair> pair) {
if (pair == null) {
return;
@@ -260,9 +291,8 @@ private void submitData(Pair> pair) {
if (!repoModel.hasWritePermission()) {
binding.galleryDeletePhoto.setVisibility(View.GONE);
}
- direntList = pair.second;
-
+ direntList = pair.second;
//
List fragments = new ArrayList<>();
@@ -275,7 +305,12 @@ private void submitData(Pair> pair) {
adapter.addFragments(fragments);
adapter.notifyItemRangeInserted(0, direntList.size());
- carouselAdapter.submitList(direntList);
+ carouselDirentList = new ArrayList<>();
+ carouselDirentList.add(new DirentModel());
+ carouselDirentList.addAll(direntList);
+ carouselDirentList.add(new DirentModel());
+
+ carouselAdapter.submitList(carouselDirentList);
binding.recyclerView.postDelayed(new Runnable() {
@Override
@@ -285,12 +320,17 @@ public void run() {
}, 100);
}
-
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);
+ if (isLightMode) {
+ binding.pager.setBackgroundColor(ContextCompatKt.getColorCompat(this, R.color.material_grey_919));
+ } else {
+ binding.pager.setBackgroundColor(ContextCompatKt.getColorCompat(this, R.color.material_grey_100));
+ }
+
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);
@@ -300,7 +340,6 @@ private void hideOrShowToolBar() {
isLightMode = !isLightMode;
}
-
/**
* Dynamically navigate to the starting page index selected by user
* by default the starting page index is 0
@@ -317,8 +356,7 @@ private void navToSelectedPage() {
}
if (index != -1) {
- binding.pager.setCurrentItem(index, true);
- gravitySnapHelper.scrollToPosition(index);
+ binding.pager.setCurrentItem(index);
}
}
@@ -327,8 +365,9 @@ private void notifyCurrentStarredStatus() {
if (direntModel == null) {
return;
}
+
if (direntModel.starred) {
- binding.galleryStarPhoto.setImageResource(R.drawable.baseline_starred_32);
+ binding.galleryStarPhoto.setImageResource(R.drawable.baseline_star_filled_24);
} else {
binding.galleryStarPhoto.setImageResource(R.drawable.baseline_star_outline_24);
}
@@ -348,17 +387,25 @@ public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
} else if (item.getItemId() == R.id.copy) {
- ToastUtils.showLong(R.string.file_action_copy);
+ copy();
} else if (item.getItemId() == R.id.info) {
- ToastUtils.showLong(R.string.file_action_copy);
+ preShowProfileDialog();
}
return super.onOptionsItemSelected(item);
}
private DirentModel getSelectedDirent() {
+ if (CollectionUtils.isEmpty(direntList)) {
+ return null;
+ }
+
int index = binding.pager.getCurrentItem();
- return carouselAdapter.getItem(index);
+ if (index > direntList.size() - 1) {
+ return null;
+ }
+
+ return direntList.get(index);
}
private void deleteFile() {
@@ -376,7 +423,10 @@ public void onActionStatus(boolean isDone) {
direntList.remove(position);
adapter.removeFragment(position);
adapter.notifyItemRemoved(position);
- carouselAdapter.notifyItemRemoved(position);
+
+ int carouselIndex = position + 1;
+ carouselDirentList.remove(carouselIndex);
+ carouselAdapter.notifyItemRemoved(carouselIndex);
ToastUtils.showLong(R.string.delete_successful);
@@ -417,4 +467,89 @@ private void downloadFile() {
getViewModel().download(direntModel.repo_id, direntModel.full_path);
}
+
+ private HashMap fileDetailHashMap = new HashMap<>();
+
+ private void preShowProfileDialog() {
+ DirentModel direntModel = getSelectedDirent();
+ if (direntModel == null) {
+ return;
+ }
+
+ String key = direntModel.full_path;
+ if (fileDetailHashMap.containsKey(key)) {
+ showProfileDialog(fileDetailHashMap.get(key));
+ } else {
+ getViewModel().getFileDetail(repoId, key);
+ }
+ }
+
+ private void showProfileDialog(FileProfileConfigModel model) {
+ FileProfileDialog detailDialog = FileProfileDialog.newInstance(model.detail, model.users.user_list, true);
+ detailDialog.show(getSupportFragmentManager(), FileProfileDialog.class.getSimpleName());
+ }
+
+ private CopyMoveContext copyMoveContext = null;
+
+ private void copy() {
+ DirentModel direntModel = getSelectedDirent();
+ if (direntModel == null) {
+ return;
+ }
+
+ chooseCopyMoveDest(direntModel, OpType.COPY);
+ }
+
+ /**
+ * Choose copy/move destination for multiple files
+ */
+ private void chooseCopyMoveDest(DirentModel direntModel, OpType op) {
+
+ copyMoveContext = new CopyMoveContext(repoId, repoName, parentDir, CollectionUtils.newArrayList(direntModel), op);
+ copyMoveLauncher.launch(ObjSelectorActivity.getStartIntent(this));
+ }
+
+ private final ActivityResultLauncher copyMoveLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback() {
+ @Override
+ public void onActivityResult(ActivityResult o) {
+ if (o.getResultCode() != Activity.RESULT_OK || o.getData() == null) {
+ return;
+ }
+
+ String dstRepoId = o.getData().getStringExtra(ObjSelectorActivity.DATA_REPO_ID);
+ String dstDir = o.getData().getStringExtra(ObjSelectorActivity.DATA_DIR);
+ String disRepoName = o.getData().getStringExtra(ObjSelectorActivity.DATA_REPO_NAME);
+
+ copyMoveContext.setDest(dstRepoId, dstDir, disRepoName);
+
+ doCopyMove();
+ }
+ });
+
+ private void doCopyMove() {
+ if (copyMoveContext == null) {
+ return;
+ }
+
+ if (!copyMoveContext.checkCopyMoveToSubfolder()) {
+ ToastUtils.showLong(copyMoveContext.isCopy()
+ ? R.string.cannot_copy_folder_to_subfolder
+ : R.string.cannot_move_folder_to_subfolder);
+ return;
+ }
+
+ CopyMoveDialogFragment dialogFragment = CopyMoveDialogFragment.newInstance();
+ dialogFragment.initData(copyMoveContext);
+ dialogFragment.setRefreshListener(new OnRefreshDataListener() {
+ @Override
+ public void onActionStatus(boolean isDone) {
+ if (isDone) {
+ ToastUtils.showLong(copyMoveContext.isCopy() ? R.string.copied_successfully : R.string.moved_successfully);
+ isDataOperated = true;
+ }
+ }
+ });
+ dialogFragment.show(getSupportFragmentManager(), CopyMoveDialogFragment.class.getSimpleName());
+ }
+
}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java
deleted file mode 100644
index f036a3703..000000000
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CarouselItemViewHolder.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.seafile.seadroid2.ui.media.image_preview2;
-
-
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.seafile.seadroid2.R;
-
-public class CarouselItemViewHolder extends RecyclerView.ViewHolder {
-
- public final ImageView imageView;
-
- CarouselItemViewHolder(@NonNull View itemView) {
- super(itemView);
- imageView = itemView.findViewById(R.id.image_view);
- }
-
-}
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java
index a81e44cbe..9e0dd3d71 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/CenterScaleXYRecyclerViewScrollListener.java
@@ -102,9 +102,9 @@ private void adjustChildScale(RecyclerView recyclerView, int dx) {
float scale = maxScale - (distanceFromCenter / maxDistance) * (maxScale - minScale);
scale = Math.max(minScale, scale); // 确保不小于最小缩放比例
- if (i == firstVisiblePosition) {
- SLogs.d("firstVisiblePosition: " + firstVisiblePosition + ", itemWidth: " + itemWidth + ", left: " + left + ", viewCenterX: " + viewCenterX + ", centerX: " + centerX + ", distanceFromCenter: " + distanceFromCenter + ", scale: " + scale);
- }
+// if (i == firstVisiblePosition) {
+// SLogs.d("firstVisiblePosition: " + firstVisiblePosition + ", itemWidth: " + itemWidth + ", left: " + left + ", viewCenterX: " + viewCenterX + ", centerX: " + centerX + ", distanceFromCenter: " + distanceFromCenter + ", scale: " + scale);
+// }
float alpha = 1.0f - (distanceFromCenter / maxDistance) * 0.8f; // 透明度范围 1.0 到 0.6
alpha = Math.max(0.8f, alpha);
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
index 894db1a58..7f27ee3a7 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/GravitySnapHelper.java
@@ -49,7 +49,7 @@ public class GravitySnapHelper extends LinearSnapHelper {
private OrientationHelper horizontalHelper;
private SnapListener listener;
private RecyclerView recyclerView;
- private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
+ private final RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
@@ -582,8 +582,9 @@ private View findView(@NonNull RecyclerView.LayoutManager layoutManager,
- helper.getDecoratedEnd(currentView));
}
} else {
- currentViewDistance = Math.abs(helper.getDecoratedStart(currentView)
- + (helper.getDecoratedMeasurement(currentView) / 2) - center);
+ int ds = helper.getDecoratedStart(currentView);
+ int dm = helper.getDecoratedMeasurement(currentView);
+ currentViewDistance = Math.abs(ds + (dm / 2) - center);
}
if (currentViewDistance < distanceToTarget) {
distanceToTarget = currentViewDistance;
diff --git a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt
index c55356299..b5a86b45c 100644
--- a/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/LinearEdgeDecoration.kt
@@ -23,7 +23,8 @@ class LinearEdgeDecoration(
val position = layoutParams.viewAdapterPosition
val itemCount = layoutManager.itemCount
- if (position == RecyclerView.NO_POSITION || itemCount == 0
+ if (position == RecyclerView.NO_POSITION
+ || itemCount == 0
|| (position > 0 && position < itemCount - 1)
) {
return
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
new file mode 100644
index 000000000..0d227c48d
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/media/image_preview2/PagerSnapBinders.java
@@ -0,0 +1,48 @@
+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 ba3ce56f4..5f0024f2f 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
@@ -21,6 +21,7 @@
import com.blankj.utilcode.util.SizeUtils;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.account.Account;
+import com.seafile.seadroid2.account.SupportAccountManager;
import com.seafile.seadroid2.config.AbsLayoutItemType;
import com.seafile.seadroid2.config.Constants;
import com.seafile.seadroid2.config.GlideLoadConfig;
@@ -54,7 +55,7 @@
import java.util.stream.Collectors;
public class RepoQuickAdapter extends BaseMultiAdapter {
- private final String SERVER = HttpIO.getCurrentInstance().getServerUrl();
+
private boolean onActionMode;
@@ -570,12 +571,16 @@ private void loadImage(DirentModel direntModel, ImageView imageView) {
imageView.setImageResource(direntModel.getIcon());
} else {
String url = convertThumbnailUrl(direntModel);
- GlideApp.with(getContext()).load(url)
- .apply(GlideLoadConfig.getOptions())
- .into(imageView);
+ 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);
+ }
}
-
-
}
private String convertThumbnailUrl(DirentModel direntModel) {
@@ -586,9 +591,30 @@ private String convertMiddleUrl(DirentModel direntModel) {
return convertThumbnailUrl(direntModel, 256);
}
+ private String server_url;
+
+ private String getServerUrl() {
+ if (!TextUtils.isEmpty(server_url)) {
+ return server_url;
+ }
+
+ boolean isLogin = SupportAccountManager.getInstance().isLogin();
+ if (!isLogin) {
+ return null;
+ }
+
+ server_url = HttpIO.getCurrentInstance().getServerUrl();
+ return server_url;
+ }
+
private String convertThumbnailUrl(DirentModel direntModel, int size) {
+ 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", SERVER, direntModel.repo_id, newFilePath, size);
+ return String.format(Locale.ROOT, "%sapi2/repos/%s/thumbnail/?p=%s&size=%d", serverUrl, direntModel.repo_id, newFilePath, size);
}
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 afb109773..5a1bdbce3 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
@@ -88,7 +88,6 @@
import com.seafile.seadroid2.ui.main.MainActivity;
import com.seafile.seadroid2.ui.main.MainViewModel;
import com.seafile.seadroid2.ui.markdown.MarkdownActivity;
-import com.seafile.seadroid2.ui.media.image_preview.ImagePreviewActivity;
import com.seafile.seadroid2.ui.media.image_preview2.CarouselImagePreviewActivity;
import com.seafile.seadroid2.ui.media.player.exoplayer.CustomExoVideoPlayerActivity;
import com.seafile.seadroid2.ui.sdoc.SDocWebViewActivity;
@@ -1178,7 +1177,7 @@ private void open(DirentModel dirent) {
// because pic thumbnail under encrypted repo was not supported at the server side
if (Utils.isViewableImage(fileName) && !repoModel.encrypted) {
- Intent getIntent = CarouselImagePreviewActivity.startThisFromRepo(requireContext(), dirent);
+ Intent getIntent = CarouselImagePreviewActivity.startThisFromObjs(requireContext(), dirent);
imagePreviewActivityLauncher.launch(getIntent);
return;
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 75319cc0b..22621e7c5 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
@@ -852,7 +852,7 @@ private Flowable> getStarSingle(String repoId, String path, boolean isStar) {
requestDataMap.put("repo_id", repoId);
requestDataMap.put("path", path);
- Map bodyMap = generateRequestBody(requestDataMap);
+ Map bodyMap = genRequestBody(requestDataMap);
Single single = HttpIO.getCurrentInstance().execute(StarredService.class).star(bodyMap);
return single.toFlowable();
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
new file mode 100644
index 000000000..19f3df13d
--- /dev/null
+++ b/app/src/main/java/com/seafile/seadroid2/ui/sdoc/DocsCommentService.java
@@ -0,0 +1,63 @@
+package com.seafile.seadroid2.ui.sdoc;
+
+import com.seafile.seadroid2.framework.data.model.ResultModel;
+import com.seafile.seadroid2.framework.data.model.docs_comment.DocsCommentWrapperModel;
+import com.seafile.seadroid2.framework.data.model.docs_comment.DocsCommentsWrapperModel;
+import com.seafile.seadroid2.framework.data.model.docs_comment.DocsUploadResultModel;
+import com.seafile.seadroid2.framework.data.model.sdoc.FileDetailModel;
+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.SDocOutlineWrapperModel;
+import com.seafile.seadroid2.framework.data.model.user.UserWrapperModel;
+
+import java.util.Map;
+
+import io.reactivex.Flowable;
+import io.reactivex.Single;
+import okhttp3.MultipartBody;
+import okhttp3.RequestBody;
+import retrofit2.http.Body;
+import retrofit2.http.DELETE;
+import retrofit2.http.GET;
+import retrofit2.http.Multipart;
+import retrofit2.http.POST;
+import retrofit2.http.PUT;
+import retrofit2.http.Part;
+import retrofit2.http.PartMap;
+import retrofit2.http.Path;
+import retrofit2.http.Query;
+
+public interface DocsCommentService {
+ @GET("api2/repos/{repo_id}/file/detail/")
+ Single getFileDetail(@Path("repo_id") String repoId, @Query("p") String path);
+
+ @GET("api/v2.1/repos/{repo_id}/related-users/")
+ Single getRelatedUsers(@Path("repo_id") String repoId);
+
+ @GET("api/v2.1/repos/{repo_id}/metadata/")
+ 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);
+
+ //
+ @GET("api/v1/docs/{uuid}/comment/")
+ Single