Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-07-04 19:51:27 +0300
committerStefan Niedermann <info@niedermann.it>2020-07-04 19:51:27 +0300
commitd06d1ec91f49300ed370473261ac6d17730a1bf2 (patch)
tree8e1ec5832d6655a52ee480f2cb235472cc1d58be /app
parent04ef1b9595e544bb95f8e7d1d6ee6cdddce3a18a (diff)
#453 🔀 Move cards to other boards and accounts - UI to move to different accounts and boards
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java19
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java35
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentDeletedListener.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardDialogFragment.java110
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardListener.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackFragment.java195
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackListener.java12
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java22
-rw-r--r--app/src/main/res/layout/dialog_move_card.xml25
-rw-r--r--app/src/main/res/layout/fragment_pick_stack.xml28
10 files changed, 410 insertions, 45 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
index 9ed9035cf..e655de739 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
@@ -917,7 +917,7 @@ public class SyncManager {
doAsync(() -> {
FullCard fullCard = dataBaseAdapter.getFullCardByLocalIdDirectly(card.getAccountId(), card.getLocalId());
if (fullCard == null) {
- throw new IllegalArgumentException("card to delete does not exist.");
+ throw new IllegalArgumentException("card with id " + card.getLocalId() + " to delete does not exist.");
}
Account account = dataBaseAdapter.getAccountByIdDirectly(card.getAccountId());
FullStack stack = dataBaseAdapter.getFullStackByLocalIdDirectly(card.getStackId());
@@ -1670,15 +1670,14 @@ public class SyncManager {
@AnyThread
private static Attachment populateAttachmentEntityForFile(@NonNull Attachment target, long localCardId, @NonNull String mimeType, @NonNull File file) {
- Attachment attachment = target;
- attachment.setCardId(localCardId);
- attachment.setMimetype(mimeType);
- attachment.setData(file.getName());
- attachment.setFilename(file.getName());
- attachment.setBasename(file.getName());
- attachment.setLocalPath(file.getAbsolutePath());
- attachment.setFilesize(file.length());
- return attachment;
+ target.setCardId(localCardId);
+ target.setMimetype(mimeType);
+ target.setData(file.getName());
+ target.setFilename(file.getName());
+ target.setBasename(file.getName());
+ target.setLocalPath(file.getAbsolutePath());
+ target.setFilesize(file.length());
+ return target;
}
@AnyThread
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java
index fb2f0e76a..98a992b93 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java
@@ -23,7 +23,6 @@ import androidx.recyclerview.widget.RecyclerView;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -39,12 +38,11 @@ import it.niedermann.nextcloud.deck.model.Stack;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
import it.niedermann.nextcloud.deck.model.full.FullCard;
-import it.niedermann.nextcloud.deck.model.full.FullStack;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData;
import it.niedermann.nextcloud.deck.ui.branding.Branded;
-import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment;
+import it.niedermann.nextcloud.deck.ui.movecard.MoveCardDialogFragment;
import it.niedermann.nextcloud.deck.util.DateUtil;
import it.niedermann.nextcloud.deck.util.ViewUtil;
@@ -69,7 +67,6 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
private final SelectCardListener selectCardListener;
private List<FullCard> cardList = new LinkedList<>();
private LifecycleOwner lifecycleOwner;
- private List<FullStack> availableStacks = new ArrayList<>();
private String counterMaxValue;
private int mainColor;
@@ -89,10 +86,6 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
this.syncManager = syncManager;
this.selectCardListener = selectCardListener;
this.mainColor = context.getResources().getColor(R.color.primary);
- syncManager.getStacksForBoard(account.getId(), boardId).observe(this.lifecycleOwner, (stacks) -> {
- availableStacks.clear();
- availableStacks.addAll(stacks);
- });
setHasStableIds(true);
}
@@ -298,30 +291,8 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
return true;
}
case R.id.action_card_move: {
- int currentStackItem = 0;
- CharSequence[] items = new CharSequence[availableStacks.size()];
- for (int i = 0; i < availableStacks.size(); i++) {
- final Stack stack = availableStacks.get(i).getStack();
- items[i] = stack.getTitle();
- if (stack.getLocalId().equals(stackId)) {
- currentStackItem = i;
- }
- }
- new BrandedAlertDialogBuilder(context)
- .setSingleChoiceItems(items, currentStackItem, (dialog, which) -> {
- dialog.cancel();
- WrappedLiveData<Void> liveData = syncManager.moveCard(fullCard.getAccountId(), fullCard.getLocalId(), fullCard.getAccountId(), boardId, availableStacks.get(which).getStack().getLocalId());
- observeOnce(liveData, lifecycleOwner, (next) -> {
- if (liveData.hasError()) {
- ExceptionDialogFragment.newInstance(liveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName());
- } else {
- DeckLog.log("Moved card \"" + fullCard.getCard().getTitle() + "\" to \"" + availableStacks.get(which).getStack().getTitle() + "\"");
- }
- });
- })
- .setNeutralButton(android.R.string.cancel, null)
- .setTitle(context.getString(R.string.action_card_move_title, fullCard.getCard().getTitle()))
- .show();
+ DeckLog.verbose("MOVE - Attempt to move " + Card.class.getSimpleName() + " " + fullCard.getCard() + " (#" + fullCard.getLocalId() + ") from " + Stack.class.getSimpleName() + " #" + +stackId);
+ MoveCardDialogFragment.newInstance(fullCard.getAccountId(), fullCard.getLocalId()).show(fragmentManager, MoveCardDialogFragment.class.getSimpleName());
return true;
}
case R.id.action_card_archive: {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentDeletedListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentDeletedListener.java
index c236fa4c5..2d3ece255 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentDeletedListener.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentDeletedListener.java
@@ -3,5 +3,5 @@ package it.niedermann.nextcloud.deck.ui.card.attachments;
import it.niedermann.nextcloud.deck.model.Attachment;
public interface AttachmentDeletedListener {
- void onAttachmentDeleted(Attachment attachment);
- } \ No newline at end of file
+ void onAttachmentDeleted(Attachment attachment);
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardDialogFragment.java
new file mode 100644
index 000000000..6a6c12888
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardDialogFragment.java
@@ -0,0 +1,110 @@
+package it.niedermann.nextcloud.deck.ui.movecard;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.databinding.DialogMoveCardBinding;
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.Stack;
+import it.niedermann.nextcloud.deck.model.full.FullStack;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
+import it.niedermann.nextcloud.deck.ui.branding.BrandingUtil;
+import it.niedermann.nextcloud.deck.ui.pickstack.PickStackFragment;
+import it.niedermann.nextcloud.deck.ui.pickstack.PickStackListener;
+
+public class MoveCardDialogFragment extends BrandedDialogFragment implements PickStackListener {
+
+ private static final String KEY_ORIGIN_CARD_LOCAL_ID = "card_local_id";
+ private static final String KEY_ORIGIN_ACCOUNT_ID = "account_id";
+ private Long originCardLocalId;
+ private Long originAccountId;
+
+ private DialogMoveCardBinding binding;
+ private PickStackFragment fragment;
+ private MoveCardListener moveCardListener;
+
+ private Account selectedAccount;
+ private Board selectedBoard;
+ private FullStack selectedStack;
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (getParentFragment() instanceof MoveCardListener) {
+ this.moveCardListener = (MoveCardListener) getParentFragment();
+ } else if (context instanceof MoveCardListener) {
+ this.moveCardListener = (MoveCardListener) context;
+ } else {
+ throw new IllegalArgumentException("Caller must implement " + MoveCardListener.class.getSimpleName());
+ }
+
+ final Bundle args = requireArguments();
+ originAccountId = args.getLong(KEY_ORIGIN_ACCOUNT_ID, -1L);
+ if (originAccountId < 0) {
+ throw new IllegalArgumentException("Missing " + KEY_ORIGIN_ACCOUNT_ID);
+ }
+ originCardLocalId = args.getLong(KEY_ORIGIN_CARD_LOCAL_ID, -1L);
+ if (originCardLocalId < 0) {
+ throw new IllegalArgumentException("Missing " + KEY_ORIGIN_CARD_LOCAL_ID);
+ }
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = DialogMoveCardBinding.inflate(inflater);
+ binding.submit.setOnClickListener((v) -> {
+ DeckLog.verbose("MOVE - Attempt to move to " + Stack.class.getSimpleName() + " #" + selectedStack.getLocalId());
+ this.moveCardListener.move(originAccountId, originCardLocalId, selectedAccount.getId(), selectedBoard.getLocalId(), selectedStack.getLocalId());
+ dismiss();
+ });
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ fragment = new PickStackFragment();
+ getChildFragmentManager()
+ .beginTransaction()
+ .add(R.id.fragment_container, fragment)
+ .commit();
+ }
+
+ @Override
+ public void onStackPicked(@NonNull Account account, @Nullable Board board, @Nullable FullStack fullStack) {
+ this.selectedAccount = account;
+ this.selectedBoard = board;
+ this.selectedStack = fullStack;
+// DeckLog.log("MOVE - Stack changed to " + fullStack.getStack().getTitle());
+ if (board == null || fullStack == null) {
+ binding.submit.setEnabled(false);
+ } else {
+ binding.submit.setEnabled(true);
+ }
+ }
+
+ @Override
+ public void applyBrand(int mainColor) {
+ binding.submit.setTextColor(ColorStateList.valueOf(BrandingUtil.getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor)));
+ }
+
+ public static DialogFragment newInstance(long originAccountId, Long originCardLocalId) {
+ final DialogFragment dialogFragment = new MoveCardDialogFragment();
+ final Bundle args = new Bundle();
+ args.putLong(KEY_ORIGIN_ACCOUNT_ID, originAccountId);
+ args.putLong(KEY_ORIGIN_CARD_LOCAL_ID, originCardLocalId);
+ dialogFragment.setArguments(args);
+ return dialogFragment;
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardListener.java
new file mode 100644
index 000000000..f6f7a7a1f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/movecard/MoveCardListener.java
@@ -0,0 +1,5 @@
+package it.niedermann.nextcloud.deck.ui.movecard;
+
+public interface MoveCardListener {
+ void move(long originAccountId, long originCardLocalId, long targetAccountId, long targetBoardLocalId, long targetStackLocalId);
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackFragment.java
new file mode 100644
index 000000000..6ebbed99b
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackFragment.java
@@ -0,0 +1,195 @@
+package it.niedermann.nextcloud.deck.ui.pickstack;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.databinding.FragmentPickStackBinding;
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.full.FullStack;
+import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.ImportAccountActivity;
+import it.niedermann.nextcloud.deck.ui.preparecreate.AccountAdapter;
+import it.niedermann.nextcloud.deck.ui.preparecreate.BoardAdapter;
+import it.niedermann.nextcloud.deck.ui.preparecreate.SelectedListener;
+import it.niedermann.nextcloud.deck.ui.preparecreate.StackAdapter;
+
+import static androidx.lifecycle.Transformations.switchMap;
+import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentAccountId;
+import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentBoardId;
+import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentStackId;
+
+public class PickStackFragment extends Fragment {
+
+ private FragmentPickStackBinding binding;
+
+ private SyncManager syncManager;
+
+ private PickStackListener pickStackListener;
+
+ private long lastAccountId;
+ private long lastBoardId;
+ private long lastStackId;
+
+ private ArrayAdapter<Account> accountAdapter;
+ private ArrayAdapter<Board> boardAdapter;
+ private ArrayAdapter<FullStack> stackAdapter;
+
+ @Nullable
+ private LiveData<List<Board>> boardsLiveData;
+ @NonNull
+ private Observer<List<Board>> boardsObserver = (boards) -> {
+ boardAdapter.clear();
+ boardAdapter.addAll(boards);
+ binding.boardSelect.setEnabled(true);
+
+ if (boards.size() > 0) {
+ binding.boardSelect.setEnabled(true);
+
+ Board boardToSelect = null;
+ for (Board board : boards) {
+ if (board.getLocalId() == lastBoardId) {
+ boardToSelect = board;
+ break;
+ }
+ }
+ if(boardToSelect == null) {
+ boardToSelect = boards.get(0);
+ }
+ binding.boardSelect.setSelection(boardAdapter.getPosition(boardToSelect));
+ } else {
+ binding.boardSelect.setEnabled(false);
+ pickStackListener.onStackPicked((Account) binding.accountSelect.getSelectedItem(), null, null);
+ }
+ };
+
+ @Nullable
+ private LiveData<List<FullStack>> stacksLiveData;
+ @NonNull
+ private Observer<List<FullStack>> stacksObserver = (fullStacks) -> {
+ stackAdapter.clear();
+ stackAdapter.addAll(fullStacks);
+
+ if (fullStacks.size() > 0) {
+ binding.stackSelect.setEnabled(true);
+
+ FullStack fullStackToSelect = null;
+ for (FullStack fullStack : fullStacks) {
+ if (fullStack.getLocalId() == lastStackId) {
+ fullStackToSelect = fullStack;
+ break;
+ }
+ }
+ if (fullStackToSelect == null) {
+ fullStackToSelect = fullStacks.get(0);
+ }
+ binding.stackSelect.setSelection(stackAdapter.getPosition(fullStackToSelect));
+ } else {
+ binding.stackSelect.setEnabled(false);
+ pickStackListener.onStackPicked((Account) binding.accountSelect.getSelectedItem(), (Board) binding.boardSelect.getSelectedItem(), null);
+ }
+ };
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (getParentFragment() instanceof PickStackListener) {
+ this.pickStackListener = (PickStackListener) getParentFragment();
+ } else if (context instanceof PickStackListener) {
+ this.pickStackListener = (PickStackListener) context;
+ } else {
+ throw new IllegalArgumentException("Caller must implement " + PickStackListener.class.getSimpleName());
+ }
+ DeckLog.error("PICKSTACK: onAttach successful");
+ }
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ binding = FragmentPickStackBinding.inflate(getLayoutInflater());
+
+ accountAdapter = new AccountAdapter(requireContext());
+ binding.accountSelect.setAdapter(accountAdapter);
+ binding.accountSelect.setEnabled(false);
+ boardAdapter = new BoardAdapter(requireContext());
+ binding.boardSelect.setAdapter(boardAdapter);
+ binding.stackSelect.setEnabled(false);
+ stackAdapter = new StackAdapter(requireContext());
+ binding.stackSelect.setAdapter(stackAdapter);
+ binding.stackSelect.setEnabled(false);
+
+ syncManager = new SyncManager(requireContext());
+
+ switchMap(syncManager.hasAccounts(), hasAccounts -> {
+ if (hasAccounts) {
+ return syncManager.readAccounts();
+ } else {
+ startActivityForResult(new Intent(requireActivity(), ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT);
+ return null;
+ }
+ }).observe(getViewLifecycleOwner(), (List<Account> accounts) -> {
+ if (accounts == null || accounts.size() == 0) {
+ throw new IllegalStateException("hasAccounts() returns true, but readAccounts() returns null or has no entry");
+ }
+
+ lastAccountId = readCurrentAccountId(requireContext());
+ lastBoardId = readCurrentBoardId(requireContext(), lastAccountId);
+ lastStackId = readCurrentStackId(requireContext(), lastAccountId, lastBoardId);
+
+ accountAdapter.clear();
+ accountAdapter.addAll(accounts);
+ binding.accountSelect.setEnabled(true);
+
+ for (Account account : accounts) {
+ if (account.getId() == lastAccountId) {
+ binding.accountSelect.setSelection(accountAdapter.getPosition(account));
+ break;
+ }
+ }
+ });
+
+ binding.accountSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> {
+ updateLiveDataSource(boardsLiveData, boardsObserver, syncManager.getBoardsWithEditPermission(parent.getSelectedItemId()));
+ });
+
+ binding.boardSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> {
+ updateLiveDataSource(stacksLiveData, stacksObserver, syncManager.getStacksForBoard(binding.accountSelect.getSelectedItemId(), parent.getSelectedItemId()));
+ });
+
+ binding.stackSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> {
+ pickStackListener.onStackPicked((Account) binding.accountSelect.getSelectedItem(), (Board) binding.boardSelect.getSelectedItem(), (FullStack) parent.getSelectedItem());
+ });
+
+ return binding.getRoot();
+ }
+
+ /**
+ * Updates the source of the given liveData and de- and reregisters the given observer.
+ */
+ private <T> void updateLiveDataSource(@Nullable LiveData<T> liveData, Observer<T> observer, LiveData<T> newSource) {
+ if (liveData != null) {
+ liveData.removeObserver(observer);
+ }
+ liveData = newSource;
+ liveData.observe(getViewLifecycleOwner(), observer);
+ }
+
+ public static PickStackFragment newInstance() {
+ return new PickStackFragment();
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackListener.java
new file mode 100644
index 000000000..0abb4dac9
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackListener.java
@@ -0,0 +1,12 @@
+package it.niedermann.nextcloud.deck.ui.pickstack;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.full.FullStack;
+
+public interface PickStackListener {
+ void onStackPicked(@NonNull Account account, @Nullable Board board, @Nullable FullStack fullStack);
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java
index 726a74184..72c5ffc84 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java
@@ -20,15 +20,22 @@ import java.util.List;
import it.niedermann.android.crosstabdnd.DragAndDropTab;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.databinding.FragmentStackBinding;
+import it.niedermann.nextcloud.deck.model.Card;
+import it.niedermann.nextcloud.deck.model.Stack;
import it.niedermann.nextcloud.deck.model.full.FullCard;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData;
import it.niedermann.nextcloud.deck.ui.MainViewModel;
import it.niedermann.nextcloud.deck.ui.branding.BrandedFragment;
import it.niedermann.nextcloud.deck.ui.card.CardAdapter;
import it.niedermann.nextcloud.deck.ui.card.SelectCardListener;
+import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment;
import it.niedermann.nextcloud.deck.ui.filter.FilterViewModel;
+import it.niedermann.nextcloud.deck.ui.movecard.MoveCardListener;
-public class StackFragment extends BrandedFragment implements DragAndDropTab<CardAdapter> {
+import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce;
+
+public class StackFragment extends BrandedFragment implements DragAndDropTab<CardAdapter>, MoveCardListener {
private static final String KEY_STACK_ID = "stackId";
@@ -153,4 +160,17 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car
return fragment;
}
+
+ @Override
+ public void move(long originAccountId, long originCardLocalId, long targetAccountId, long targetBoardLocalId, long targetStackLocalId) {
+ WrappedLiveData<Void> liveData = syncManager.moveCard(originAccountId, originCardLocalId, targetAccountId, targetBoardLocalId, targetStackLocalId);
+ observeOnce(liveData, requireActivity(), (next) -> {
+ if (liveData.hasError()) {
+ ExceptionDialogFragment.newInstance(liveData.getError(), null).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ } else {
+ DeckLog.log("Moved " + Card.class.getSimpleName() + " \"" + originCardLocalId + "\" to " + Stack.class.getSimpleName() + " \"" + targetStackLocalId + "\"");
+ }
+ });
+ }
+
} \ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_move_card.xml b/app/src/main/res/layout/dialog_move_card.xml
new file mode 100644
index 000000000..b4c2beea0
--- /dev/null
+++ b/app/src/main/res/layout/dialog_move_card.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <FrameLayout
+ android:id="@+id/fragment_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </ScrollView>
+
+ <Button
+ android:id="@+id/submit"
+ style="@style/Widget.MaterialComponents.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:text="@string/action_card_move"
+ android:textColor="@color/defaultBrand" />
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_pick_stack.xml b/app/src/main/res/layout/fragment_pick_stack.xml
new file mode 100644
index 000000000..9769969ff
--- /dev/null
+++ b/app/src/main/res/layout/fragment_pick_stack.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/account_select"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/choose_account"
+ tools:listitem="@layout/item_prepare_create_account" />
+
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/board_select"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/choose_board"
+ tools:listitem="@layout/item_board" />
+
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/stack_select"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/choose_list"
+ tools:listitem="@layout/item_board" />
+</LinearLayout> \ No newline at end of file