diff options
author | Stefan Niedermann <info@niedermann.it> | 2020-12-09 20:00:04 +0300 |
---|---|---|
committer | Stefan Niedermann <info@niedermann.it> | 2020-12-09 20:00:04 +0300 |
commit | c9a7af81204f89ee2f72e108a5a83665b82089f1 (patch) | |
tree | 755219dc21556131daa3ec72d44236e6b4dd19c2 /app/src/main/java/it/niedermann/nextcloud/deck | |
parent | 51e3a19d817190fd6fcf0d4595c6db8414e1a21b (diff) | |
parent | f29eed9db4c0906fa7887e446cf0325718ef6827 (diff) |
Merge branch 'master' into webview-markdown
# Conflicts:
# app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java
Diffstat (limited to 'app/src/main/java/it/niedermann/nextcloud/deck')
41 files changed, 867 insertions, 431 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 c86f65340..d93835423 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 @@ -88,11 +88,11 @@ import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; public class SyncManager { @NonNull - private Context appContext; + private final Context appContext; @NonNull - private DataBaseAdapter dataBaseAdapter; + private final DataBaseAdapter dataBaseAdapter; @NonNull - private ServerAdapter serverAdapter; + private final ServerAdapter serverAdapter; private static final Map<Long, List<IResponseCallback<Boolean>>> RUNNING_SYNCS = new ConcurrentHashMap<>(); @@ -119,7 +119,7 @@ public class SyncManager { return dataBaseAdapter.getLocalBoardIdByCardRemoteIdAndAccountId(cardRemoteId, account.getId()); } - @AnyThread + @WorkerThread public boolean synchronizeEverything() { List<Account> accounts = dataBaseAdapter.getAllAccountsDirectly(); if (accounts.size() > 0) { @@ -348,14 +348,15 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Account> createAccount(@NonNull Account accout) { - return dataBaseAdapter.createAccount(accout); + public WrappedLiveData<Account> createAccount(@NonNull Account account) { + return dataBaseAdapter.createAccount(account); } public boolean hasInternetConnection() { return serverAdapter.hasInternetConnection(); } + @AnyThread public void deleteAccount(long id) { doAsync(() -> { dataBaseAdapter.deleteAccount(id); @@ -363,10 +364,6 @@ public class SyncManager { }); } - public void updateAccount(Account account) { - dataBaseAdapter.updateAccount(account); - } - @AnyThread public LiveData<Account> readAccount(long id) { return dataBaseAdapter.readAccount(id); @@ -590,6 +587,7 @@ public class SyncManager { String found = matcher.group(); newBoardTitleBaseName = newBoardTitleBaseName.substring(0, newBoardTitleBaseName.length() - found.length()); Matcher indexMatcher = Pattern.compile("[0-9]+").matcher(found); + //noinspection ResultOfMethodCallIgnored indexMatcher.find(); String oldIndexString = indexMatcher.group(); newBoardTitleCopyIndex = Integer.parseInt(oldIndexString); @@ -956,24 +954,22 @@ public class SyncManager { @AnyThread private void updateStack(@NonNull Account account, @NonNull FullBoard board, @NonNull FullStack stack, @Nullable WrappedLiveData<FullStack> liveData) { - doAsync(() -> { - new DataPropagationHelper(serverAdapter, dataBaseAdapter).updateEntity(new StackDataProvider(null, board), stack, new IResponseCallback<FullStack>(account) { - @Override - public void onResponse(FullStack response) { - if (liveData != null) { - liveData.postValue(response); - } + doAsync(() -> new DataPropagationHelper(serverAdapter, dataBaseAdapter).updateEntity(new StackDataProvider(null, board), stack, new IResponseCallback<FullStack>(account) { + @Override + public void onResponse(FullStack response) { + if (liveData != null) { + liveData.postValue(response); } + } - @SuppressLint("MissingSuperCall") - @Override - public void onError(Throwable throwable) { - if (liveData != null) { - liveData.postError(throwable); - } + @SuppressLint("MissingSuperCall") + @Override + public void onError(Throwable throwable) { + if (liveData != null) { + liveData.postError(throwable); } - }); - }); + } + })); } /** @@ -1319,36 +1315,35 @@ public class SyncManager { public WrappedLiveData<Void> moveCard(long originAccountId, long originCardLocalId, long targetAccountId, long targetBoardLocalId, long targetStackLocalId) { return LiveDataHelper.wrapInLiveData(() -> { - FullCard originalCard = dataBaseAdapter.getFullCardByLocalIdDirectly(originAccountId, originCardLocalId); + final FullCard originalCard = dataBaseAdapter.getFullCardByLocalIdDirectly(originAccountId, originCardLocalId); int newIndex = dataBaseAdapter.getHighestCardOrderInStack(targetStackLocalId) + 1; - FullBoard originalBoard = dataBaseAdapter.getFullBoardByLocalCardIdDirectly(originCardLocalId); + final FullBoard originalBoard = dataBaseAdapter.getFullBoardByLocalCardIdDirectly(originCardLocalId); // ### maybe shortcut possible? (just moved to another stack) if (targetBoardLocalId == originalBoard.getLocalId()) { reorder(originAccountId, originalCard, targetStackLocalId, newIndex); return null; } // ### get rid of original card where it is now. - Card originalInnerCard = originalCard.getCard(); + final Card originalInnerCard = originalCard.getCard(); deleteCard(new Card(originalInnerCard)); // ### clone card itself - Card targetCard = originalInnerCard; - targetCard.setAccountId(targetAccountId); - targetCard.setId(null); - targetCard.setLocalId(null); - targetCard.setStatusEnum(DBStatus.LOCAL_EDITED); - targetCard.setStackId(targetStackLocalId); - targetCard.setOrder(newIndex); - targetCard.setArchived(false); - targetCard.setAttachmentCount(0); - targetCard.setCommentsUnread(0); - FullCard fullCardForServerPropagation = new FullCard(); - fullCardForServerPropagation.setCard(targetCard); - - Account targetAccount = dataBaseAdapter.getAccountByIdDirectly(targetAccountId); - FullBoard targetBoard = dataBaseAdapter.getFullBoardByLocalIdDirectly(targetAccountId, targetBoardLocalId); - FullStack targetFullStack = dataBaseAdapter.getFullStackByLocalIdDirectly(targetStackLocalId); - User userOfTargetAccount = dataBaseAdapter.getUserByUidDirectly(targetAccountId, targetAccount.getUserName()); - CountDownLatch latch = new CountDownLatch(1); + originalInnerCard.setAccountId(targetAccountId); + originalInnerCard.setId(null); + originalInnerCard.setLocalId(null); + originalInnerCard.setStatusEnum(DBStatus.LOCAL_EDITED); + originalInnerCard.setStackId(targetStackLocalId); + originalInnerCard.setOrder(newIndex); + originalInnerCard.setArchived(false); + originalInnerCard.setAttachmentCount(0); + originalInnerCard.setCommentsUnread(0); + final FullCard fullCardForServerPropagation = new FullCard(); + fullCardForServerPropagation.setCard(originalInnerCard); + + final Account targetAccount = dataBaseAdapter.getAccountByIdDirectly(targetAccountId); + final FullBoard targetBoard = dataBaseAdapter.getFullBoardByLocalIdDirectly(targetAccountId, targetBoardLocalId); + final FullStack targetFullStack = dataBaseAdapter.getFullStackByLocalIdDirectly(targetStackLocalId); + final User userOfTargetAccount = dataBaseAdapter.getUserByUidDirectly(targetAccountId, targetAccount.getUserName()); + final CountDownLatch latch = new CountDownLatch(1); ServerAdapter serverToUse = serverAdapter; if (originAccountId != targetAccountId) { serverToUse = new ServerAdapter(appContext, targetAccount.getName()); @@ -1356,8 +1351,8 @@ public class SyncManager { new DataPropagationHelper(serverToUse, dataBaseAdapter).createEntity(new CardPropagationDataProvider(null, targetBoard.getBoard(), targetFullStack), fullCardForServerPropagation, new IResponseCallback<FullCard>(targetAccount) { @Override public void onResponse(FullCard response) { - targetCard.setId(response.getId()); - targetCard.setLocalId(response.getLocalId()); + originalInnerCard.setId(response.getId()); + originalInnerCard.setLocalId(response.getLocalId()); latch.countDown(); } @@ -1380,7 +1375,7 @@ public class SyncManager { throw new RuntimeException("error fulfilling countDownLatch", e); } - long newCardId = targetCard.getLocalId(); + long newCardId = originalInnerCard.getLocalId(); // ### clone labels, assign them // prepare @@ -1389,7 +1384,7 @@ public class SyncManager { List<AccessControl> aclOfTargetBoard = dataBaseAdapter.getAccessControlByLocalBoardIdDirectly(targetAccountId, targetBoard.getLocalId()); if (!hasManagePermission) { for (AccessControl accessControl : aclOfTargetBoard) { - if (accessControl.getUserId() == userOfTargetAccount.getLocalId() && accessControl.isPermissionManage()) { + if (accessControl.getUserId().equals(userOfTargetAccount.getLocalId()) && accessControl.isPermissionManage()) { hasManagePermission = true; break; } @@ -1416,7 +1411,7 @@ public class SyncManager { createAndAssignLabelToCard(targetBoard.getAccountId(), originalLabel, newCardId, serverToUse); } } else { - assignLabelToCard(existingMatch, targetCard, serverToUse); + assignLabelToCard(existingMatch, originalInnerCard, serverToUse); } } @@ -1429,7 +1424,7 @@ public class SyncManager { boolean hasViewPermission = targetBoard.getBoard().getOwnerId() == assignedUser.getLocalId(); if (!hasViewPermission) { for (AccessControl accessControl : aclOfTargetBoard) { - if (accessControl.getUserId() == userOfTargetAccount.getLocalId()) { + if (accessControl.getUserId().equals(userOfTargetAccount.getLocalId())) { // ACL exists, so viewing is granted hasViewPermission = true; break; @@ -1437,7 +1432,7 @@ public class SyncManager { } } if (hasViewPermission) { - assignUserToCard(assignedUser, targetCard); + assignUserToCard(assignedUser, originalInnerCard); } } } @@ -1469,9 +1464,7 @@ public class SyncManager { public void onError(Throwable throwable) { liveData.postError(throwable); } - }, (entity, response) -> { - response.setBoardId(board.getLocalId()); - }); + }, (entity, response) -> response.setBoardId(board.getLocalId())); }); return liveData; } @@ -1685,10 +1678,6 @@ public class SyncManager { return dataBaseAdapter.searchNotYetAssignedLabelsByTitle(accountId, boardId, notYetAssignedToLocalCardId, searchTerm); } - public String getServerUrl() { - return serverAdapter.getServerUrl(); - } - /** * @see <a href="https://github.com/stefan-niedermann/nextcloud-deck/issues/360">reenable reorder</a> */ diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java index 5056985fa..d7e726a7d 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java @@ -1,5 +1,6 @@ package it.niedermann.nextcloud.deck.ui; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -88,6 +89,7 @@ import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import it.niedermann.nextcloud.deck.ui.filter.FilterDialogFragment; import it.niedermann.nextcloud.deck.ui.filter.FilterViewModel; +import it.niedermann.nextcloud.deck.ui.pickstack.PickStackViewModel; import it.niedermann.nextcloud.deck.ui.settings.SettingsActivity; import it.niedermann.nextcloud.deck.ui.stack.DeleteStackDialogFragment; import it.niedermann.nextcloud.deck.ui.stack.DeleteStackListener; @@ -128,6 +130,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener protected MainViewModel mainViewModel; private FilterViewModel filterViewModel; + private PickStackViewModel pickStackViewModel; protected static final int ACTIVITY_ABOUT = 1; protected static final int ACTIVITY_SETTINGS = 2; @@ -135,7 +138,6 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @NonNull protected List<Account> accountsList = new ArrayList<>(); - protected SyncManager syncManager; protected SharedPreferences sharedPreferences; private StackAdapter stackAdapter; long lastBoardId; @@ -180,6 +182,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener mainViewModel = new ViewModelProvider(this).get(MainViewModel.class); filterViewModel = new ViewModelProvider(this).get(FilterViewModel.class); + pickStackViewModel = new ViewModelProvider(this).get(PickStackViewModel.class); addList = getString(R.string.add_list); addBoard = getString(R.string.add_board); @@ -193,12 +196,11 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener toggle.syncState(); binding.navigationView.setNavigationItemSelectedListener(this); - syncManager = new SyncManager(this); sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - switchMap(syncManager.hasAccounts(), hasAccounts -> { + switchMap(mainViewModel.hasAccounts(), hasAccounts -> { if (hasAccounts) { - return syncManager.readAccounts(); + return mainViewModel.readAccounts(); } else { startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); return null; @@ -222,7 +224,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { registerAutoSyncOnNetworkAvailable(); } else { - syncManager.synchronize(new IResponseCallback<Boolean>(mainViewModel.getCurrentAccount()) { + mainViewModel.synchronize(new IResponseCallback<Boolean>(mainViewModel.getCurrentAccount()) { @Override public void onResponse(Boolean response) { } @@ -242,7 +244,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener mainViewModel.getCurrentAccountLiveData().observe(this, (currentAccount) -> { SingleAccountHelper.setCurrentAccount(getApplicationContext(), mainViewModel.getCurrentAccount().getName()); - syncManager = new SyncManager(this); + mainViewModel.recreateSyncManager(); saveCurrentAccountId(this, mainViewModel.getCurrentAccount().getId()); if (mainViewModel.getCurrentAccount().isMaintenanceEnabled()) { @@ -255,7 +257,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener boardsLiveData.removeObserver(boardsLiveDataObserver); } - boardsLiveData = syncManager.getBoards(currentAccount.getId(), false); + boardsLiveData = mainViewModel.getBoards(currentAccount.getId(), false); boardsLiveDataObserver = (boards) -> { if (boards == null) { throw new IllegalStateException("List<Board> boards must not be null."); @@ -287,7 +289,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener if (hasArchivedBoardsLiveData != null && hasArchivedBoardsLiveDataObserver != null) { hasArchivedBoardsLiveData.removeObserver(hasArchivedBoardsLiveDataObserver); } - hasArchivedBoardsLiveData = syncManager.hasArchivedBoards(currentAccount.getId()); + hasArchivedBoardsLiveData = mainViewModel.hasArchivedBoards(currentAccount.getId()); hasArchivedBoardsLiveDataObserver = (hasArchivedBoards) -> { mainViewModel.setCurrentAccountHasArchivedBoards(Boolean.TRUE.equals(hasArchivedBoards)); inflateBoardMenu(); @@ -326,7 +328,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener CrossTabDragAndDrop<StackFragment, CardAdapter, FullCard> dragAndDrop = new CrossTabDragAndDrop<>(getResources(), ViewCompat.getLayoutDirection(binding.getRoot()) == ViewCompat.LAYOUT_DIRECTION_LTR); dragAndDrop.register(binding.viewPager, binding.stackTitles, getSupportFragmentManager()); dragAndDrop.addItemMovedByDragListener((movedCard, stackId, position) -> { - syncManager.reorder(mainViewModel.getCurrentAccount().getId(), movedCard, stackId, position); + mainViewModel.reorder(mainViewModel.getCurrentAccount().getId(), movedCard, stackId, position); DeckLog.info("Card \"" + movedCard.getCard().getTitle() + "\" was moved to Stack " + stackId + " on position " + position); }); @@ -399,7 +401,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener } } else DeckLog.warn("ConnectivityManager is null"); refreshCapabilities(mainViewModel.getCurrentAccount()); - syncManager.synchronize(new IResponseCallback<Boolean>(mainViewModel.getCurrentAccount()) { + mainViewModel.synchronize(new IResponseCallback<Boolean>(mainViewModel.getCurrentAccount()) { @Override public void onResponse(Boolean response) { runOnUiThread(() -> binding.swipeRefreshLayout.setRefreshing(false)); @@ -445,7 +447,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public void onCreateStack(String stackName) { DeckLog.info("Create Stack in account " + mainViewModel.getCurrentAccount().getName() + " on board " + mainViewModel.getCurrentBoardLocalId()); - WrappedLiveData<FullStack> createLiveData = syncManager.createStack(mainViewModel.getCurrentAccount().getId(), stackName, mainViewModel.getCurrentBoardLocalId()); + WrappedLiveData<FullStack> createLiveData = mainViewModel.createStack(mainViewModel.getCurrentAccount().getId(), stackName, mainViewModel.getCurrentBoardLocalId()); observeOnce(createLiveData, this, (fullStack) -> { if (createLiveData.hasError()) { final Throwable error = createLiveData.getError(); @@ -461,7 +463,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public void onUpdateStack(long localStackId, String stackName) { - final WrappedLiveData<FullStack> liveData = syncManager.updateStackTitle(localStackId, stackName); + final WrappedLiveData<FullStack> liveData = mainViewModel.updateStackTitle(localStackId, stackName); observeOnce(liveData, this, (v) -> { if (liveData.hasError()) { ExceptionDialogFragment.newInstance(liveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -479,7 +481,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener boardToCreate.setPermissionEdit(true); boardToCreate.setPermissionManage(true); - final WrappedLiveData<FullBoard> createLiveData = syncManager.createBoard(mainViewModel.getCurrentAccount().getId(), boardToCreate); + final WrappedLiveData<FullBoard> createLiveData = mainViewModel.createBoard(mainViewModel.getCurrentAccount().getId(), boardToCreate); observeOnce(createLiveData, this, (createdBoard) -> { if (createLiveData.hasError()) { BrandedSnackbar.make(binding.coordinatorLayout, R.string.synchronization_failed, Snackbar.LENGTH_LONG) @@ -499,7 +501,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public void onUpdateBoard(FullBoard fullBoard) { - final WrappedLiveData<FullBoard> updateLiveData = syncManager.updateBoard(fullBoard); + final WrappedLiveData<FullBoard> updateLiveData = mainViewModel.updateBoard(fullBoard); observeOnce(updateLiveData, this, (next) -> { if (updateLiveData.hasError()) { ExceptionDialogFragment.newInstance(updateLiveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -508,7 +510,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener } private void refreshCapabilities(final Account account) { - syncManager.refreshCapabilities(new IResponseCallback<Capabilities>(account) { + mainViewModel.refreshCapabilities(new IResponseCallback<Capabilities>(account) { @Override public void onResponse(Capabilities response) { if (response.isMaintenanceEnabled()) { @@ -565,7 +567,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener binding.emptyContentViewBoards.setVisibility(View.GONE); binding.swipeRefreshLayout.setVisibility(View.VISIBLE); - stacksLiveData = syncManager.getStacksForBoard(mainViewModel.getCurrentAccount().getId(), board.getLocalId()); + stacksLiveData = mainViewModel.getStacksForBoard(mainViewModel.getCurrentAccount().getId(), board.getLocalId()); stacksLiveData.observe(this, (List<Stack> stacks) -> { if (stacks == null) { throw new IllegalStateException("Given List<FullStack> must not be null"); @@ -667,74 +669,67 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.archive_cards: { - final Stack stack = stackAdapter.getItem(binding.viewPager.getCurrentItem()); - final long stackLocalId = stack.getLocalId(); - observeOnce(syncManager.countCardsInStack(mainViewModel.getCurrentAccount().getId(), stackLocalId), MainActivity.this, (numberOfCards) -> { - new BrandedAlertDialogBuilder(this) - .setTitle(R.string.archive_cards) - .setMessage(getString(FilterInformation.hasActiveFilter(filterViewModel.getFilterInformation().getValue()) - ? R.string.do_you_want_to_archive_all_cards_of_the_filtered_list - : R.string.do_you_want_to_archive_all_cards_of_the_list, stack.getTitle())) - .setPositiveButton(R.string.simple_archive, (dialog, whichButton) -> { - final FilterInformation filterInformation = filterViewModel.getFilterInformation().getValue(); - final WrappedLiveData<Void> archiveStackLiveData = syncManager.archiveCardsInStack(mainViewModel.getCurrentAccount().getId(), stackLocalId, filterInformation == null ? new FilterInformation() : filterInformation); - observeOnce(archiveStackLiveData, this, (result) -> { - if (archiveStackLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(archiveStackLiveData.getError())) { - ExceptionDialogFragment.newInstance(archiveStackLiveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); - } - }); - }) - .setNeutralButton(android.R.string.cancel, null) - .create() - .show(); - }); - return true; - } - case R.id.add_list: { - EditStackDialogFragment.newInstance(NO_STACK_ID).show(getSupportFragmentManager(), addList); - return true; - } - case R.id.rename_list: { - final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); - observeOnce(syncManager.getStack(mainViewModel.getCurrentAccount().getId(), stackId), MainActivity.this, fullStack -> - EditStackDialogFragment.newInstance(fullStack.getLocalId(), fullStack.getStack().getTitle()) - .show(getSupportFragmentManager(), EditStackDialogFragment.class.getCanonicalName())); - return true; - } - case R.id.move_list_left: { - final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); - // TODO error handling - final int stackLeftPosition = binding.viewPager.getCurrentItem() - 1; - final long stackLeftId = stackAdapter.getItem(stackLeftPosition).getLocalId(); - syncManager.swapStackOrder(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), new Pair<>(stackId, stackLeftId)); - stackMoved = true; - return true; - } - case R.id.move_list_right: { - final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); - // TODO error handling - final int stackRightPosition = binding.viewPager.getCurrentItem() + 1; - final long stackRightId = stackAdapter.getItem(stackRightPosition).getLocalId(); - syncManager.swapStackOrder(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), new Pair<>(stackId, stackRightId)); - stackMoved = true; - return true; - } - case R.id.delete_list: { - final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); - observeOnce(syncManager.countCardsInStack(mainViewModel.getCurrentAccount().getId(), stackId), MainActivity.this, (numberOfCards) -> { - if (numberOfCards != null && numberOfCards > 0) { - DeleteStackDialogFragment.newInstance(stackId, numberOfCards).show(getSupportFragmentManager(), DeleteStackDialogFragment.class.getCanonicalName()); - } else { - onStackDeleted(stackId); - } - }); - return true; - } - default: - return super.onOptionsItemSelected(item); + int itemId = item.getItemId(); + if (itemId == R.id.archive_cards) { + final Stack stack = stackAdapter.getItem(binding.viewPager.getCurrentItem()); + final long stackLocalId = stack.getLocalId(); + observeOnce(mainViewModel.countCardsInStack(mainViewModel.getCurrentAccount().getId(), stackLocalId), MainActivity.this, (numberOfCards) -> { + new BrandedAlertDialogBuilder(this) + .setTitle(R.string.archive_cards) + .setMessage(getString(FilterInformation.hasActiveFilter(filterViewModel.getFilterInformation().getValue()) + ? R.string.do_you_want_to_archive_all_cards_of_the_filtered_list + : R.string.do_you_want_to_archive_all_cards_of_the_list, stack.getTitle())) + .setPositiveButton(R.string.simple_archive, (dialog, whichButton) -> { + final FilterInformation filterInformation = filterViewModel.getFilterInformation().getValue(); + final WrappedLiveData<Void> archiveStackLiveData = mainViewModel.archiveCardsInStack(mainViewModel.getCurrentAccount().getId(), stackLocalId, filterInformation == null ? new FilterInformation() : filterInformation); + observeOnce(archiveStackLiveData, this, (result) -> { + if (archiveStackLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(archiveStackLiveData.getError())) { + ExceptionDialogFragment.newInstance(archiveStackLiveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); + } + }); + }) + .setNeutralButton(android.R.string.cancel, null) + .create() + .show(); + }); + return true; + } else if (itemId == R.id.add_list) { + EditStackDialogFragment.newInstance(NO_STACK_ID).show(getSupportFragmentManager(), addList); + return true; + } else if (itemId == R.id.rename_list) { + final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); + observeOnce(mainViewModel.getStack(mainViewModel.getCurrentAccount().getId(), stackId), MainActivity.this, fullStack -> + EditStackDialogFragment.newInstance(fullStack.getLocalId(), fullStack.getStack().getTitle()) + .show(getSupportFragmentManager(), EditStackDialogFragment.class.getCanonicalName())); + return true; + } else if (itemId == R.id.move_list_left) { + final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); + // TODO error handling + final int stackLeftPosition = binding.viewPager.getCurrentItem() - 1; + final long stackLeftId = stackAdapter.getItem(stackLeftPosition).getLocalId(); + mainViewModel.swapStackOrder(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), new Pair<>(stackId, stackLeftId)); + stackMoved = true; + return true; + } else if (itemId == R.id.move_list_right) { + final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); + // TODO error handling + final int stackRightPosition = binding.viewPager.getCurrentItem() + 1; + final long stackRightId = stackAdapter.getItem(stackRightPosition).getLocalId(); + mainViewModel.swapStackOrder(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), new Pair<>(stackId, stackRightId)); + stackMoved = true; + return true; + } else if (itemId == R.id.delete_list) { + final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); + observeOnce(mainViewModel.countCardsInStack(mainViewModel.getCurrentAccount().getId(), stackId), MainActivity.this, (numberOfCards) -> { + if (numberOfCards != null && numberOfCards > 0) { + DeleteStackDialogFragment.newInstance(stackId, numberOfCards).show(getSupportFragmentManager(), DeleteStackDialogFragment.class.getCanonicalName()); + } else { + onStackDeleted(stackId); + } + }); + return true; } + return super.onOptionsItemSelected(item); } protected void showFabIfEditPermissionGranted() { @@ -779,7 +774,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener default: try { AccountImporter.onActivityResult(requestCode, resultCode, data, this, (account) -> { - final WrappedLiveData<Account> accountLiveData = this.syncManager.createAccount(new Account(account.name, account.userId, account.url)); + final WrappedLiveData<Account> accountLiveData = mainViewModel.createAccount(new Account(account.name, account.userId, account.url)); accountLiveData.observe(this, (createdAccount) -> { if (!accountLiveData.hasError()) { if (createdAccount == null) { @@ -788,12 +783,13 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener final SyncManager importSyncManager = new SyncManager(this, account.name); importSyncManager.refreshCapabilities(new IResponseCallback<Capabilities>(createdAccount) { + @SuppressLint("StringFormatInvalid") @Override public void onResponse(Capabilities response) { if (!response.isMaintenanceEnabled()) { if (response.getDeckVersion().isSupported(getApplicationContext())) { runOnUiThread(() -> { - syncManager = importSyncManager; + mainViewModel.setSyncManager(importSyncManager); mainViewModel.setCurrentAccount(account); final Snackbar importSnackbar = BrandedSnackbar.make(binding.coordinatorLayout, R.string.account_is_getting_imported, Snackbar.LENGTH_INDEFINITE); @@ -826,7 +822,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener startActivity(openURL); finish(); }).show()); - syncManager.deleteAccount(createdAccount.getId()); + mainViewModel.deleteAccount(createdAccount.getId()); } } else { DeckLog.warn("Cannot import account because server version is currently in maintenance mode."); @@ -835,14 +831,14 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener .setMessage(getString(R.string.maintenance_mode_explanation, createdAccount.getUrl())) .setPositiveButton(R.string.simple_close, null) .show()); - syncManager.deleteAccount(createdAccount.getId()); + mainViewModel.deleteAccount(createdAccount.getId()); } } @Override public void onError(Throwable throwable) { super.onError(throwable); - syncManager.deleteAccount(createdAccount.getId()); + mainViewModel.deleteAccount(createdAccount.getId()); if (throwable instanceof OfflineException) { DeckLog.warn("Cannot import account because device is currently offline."); runOnUiThread(() -> new BrandedAlertDialogBuilder(MainActivity.this) @@ -892,7 +888,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public void onAvailable(@NonNull Network network) { DeckLog.log("Got Network connection"); - syncManager.synchronize(new IResponseCallback<Boolean>(mainViewModel.getCurrentAccount()) { + mainViewModel.synchronize(new IResponseCallback<Boolean>(mainViewModel.getCurrentAccount()) { @Override public void onResponse(Boolean response) { DeckLog.log("Auto-Sync after connection available successful"); @@ -923,7 +919,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public void onStackDeleted(Long stackLocalId) { long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId(); - final WrappedLiveData<Void> deleteStackLiveData = syncManager.deleteStack(mainViewModel.getCurrentAccount().getId(), stackId, mainViewModel.getCurrentBoardLocalId()); + final WrappedLiveData<Void> deleteStackLiveData = mainViewModel.deleteStack(mainViewModel.getCurrentAccount().getId(), stackId, mainViewModel.getCurrentBoardLocalId()); observeOnce(deleteStackLiveData, this, (v) -> { if (deleteStackLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteStackLiveData.getError())) { ExceptionDialogFragment.newInstance(deleteStackLiveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -946,7 +942,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener } } - final WrappedLiveData<Void> deleteLiveData = syncManager.deleteBoard(board); + final WrappedLiveData<Void> deleteLiveData = mainViewModel.deleteBoard(board); observeOnce(deleteLiveData, this, (next) -> { if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { ExceptionDialogFragment.newInstance(deleteLiveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -972,7 +968,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener @Override public void onArchive(@NonNull Board board) { - final WrappedLiveData<FullBoard> liveData = syncManager.archiveBoard(board); + final WrappedLiveData<FullBoard> liveData = mainViewModel.archiveBoard(board); observeOnce(liveData, this, (fullBoard) -> { if (liveData.hasError()) { ExceptionDialogFragment.newInstance(liveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -991,7 +987,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener binding.drawerLayout.closeDrawer(GravityCompat.START); final Snackbar snackbar = BrandedSnackbar.make(binding.coordinatorLayout, getString(R.string.cloning_board, board.getTitle()), Snackbar.LENGTH_INDEFINITE); snackbar.show(); - final WrappedLiveData<FullBoard> liveData = syncManager.cloneBoard(board.getAccountId(), board.getLocalId(), board.getAccountId(), board.getColor(), checkedItems[0]); + final WrappedLiveData<FullBoard> liveData = mainViewModel.cloneBoard(board.getAccountId(), board.getLocalId(), board.getAccountId(), board.getColor(), checkedItems[0]); observeOnce(liveData, this, (fullBoard -> { snackbar.dismiss(); if (liveData.hasError()) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java index b73b86b33..ac244b88e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java @@ -2,19 +2,41 @@ package it.niedermann.nextcloud.deck.ui; import android.app.Application; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.util.Pair; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import java.io.File; +import java.util.List; + +import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.model.AccessControl; import it.niedermann.nextcloud.deck.model.Account; +import it.niedermann.nextcloud.deck.model.Attachment; import it.niedermann.nextcloud.deck.model.Board; +import it.niedermann.nextcloud.deck.model.Card; +import it.niedermann.nextcloud.deck.model.Label; +import it.niedermann.nextcloud.deck.model.Stack; +import it.niedermann.nextcloud.deck.model.User; +import it.niedermann.nextcloud.deck.model.full.FullBoard; +import it.niedermann.nextcloud.deck.model.full.FullCard; +import it.niedermann.nextcloud.deck.model.full.FullStack; +import it.niedermann.nextcloud.deck.model.internal.FilterInformation; +import it.niedermann.nextcloud.deck.model.ocs.Capabilities; +import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData; @SuppressWarnings("WeakerAccess") public class MainViewModel extends AndroidViewModel { - private MutableLiveData<Account> currentAccount = new MutableLiveData<>(); + private SyncManager syncManager; + + private final MutableLiveData<Account> currentAccount = new MutableLiveData<>(); @Nullable private Board currentBoard; private boolean currentAccountHasArchivedBoards = false; @@ -23,6 +45,7 @@ public class MainViewModel extends AndroidViewModel { public MainViewModel(@NonNull Application application) { super(application); + this.syncManager = new SyncManager(application); } public Account getCurrentAccount() { @@ -43,14 +66,14 @@ public class MainViewModel extends AndroidViewModel { } public Long getCurrentBoardLocalId() { - if(currentBoard == null) { + if (currentBoard == null) { throw new IllegalStateException("getCurrentBoardLocalId() called before setCurrentBoard()"); } return this.currentBoard.getLocalId(); } public Long getCurrentBoardRemoteId() { - if(currentBoard == null) { + if (currentBoard == null) { throw new IllegalStateException("getCurrentBoardRemoteId() called before setCurrentBoard()"); } return this.currentBoard.getId(); @@ -71,4 +94,192 @@ public class MainViewModel extends AndroidViewModel { public boolean isCurrentAccountIsSupportedVersion() { return currentAccountIsSupportedVersion; } + + public void recreateSyncManager() { + this.syncManager = new SyncManager(getApplication()); + } + + public void setSyncManager(@NonNull SyncManager syncManager) { + this.syncManager = syncManager; + } + + public void synchronize(@NonNull IResponseCallback<Boolean> responseCallback) { + syncManager.synchronize(responseCallback); + } + + public void refreshCapabilities(@NonNull IResponseCallback<Capabilities> callback) { + syncManager.refreshCapabilities(callback); + } + + public LiveData<Boolean> hasAccounts() { + return syncManager.hasAccounts(); + } + + public WrappedLiveData<Account> createAccount(@NonNull Account accout) { + return syncManager.createAccount(accout); + } + + public void deleteAccount(long id) { + syncManager.deleteAccount(id); + } + + public LiveData<List<Account>> readAccounts() { + return syncManager.readAccounts(); + } + + public WrappedLiveData<FullBoard> createBoard(long accountId, @NonNull Board board) { + return syncManager.createBoard(accountId, board); + } + + public WrappedLiveData<FullBoard> updateBoard(@NonNull FullBoard board) { + return syncManager.updateBoard(board); + } + + public LiveData<List<Board>> getBoards(long accountId, boolean archived) { + return syncManager.getBoards(accountId, archived); + } + + public LiveData<FullBoard> getFullBoardById(Long accountId, Long localId) { + return syncManager.getFullBoardById(accountId, localId); + } + + public WrappedLiveData<FullBoard> archiveBoard(@NonNull Board board) { + return syncManager.archiveBoard(board); + } + + public WrappedLiveData<FullBoard> dearchiveBoard(@NonNull Board board) { + return syncManager.dearchiveBoard(board); + } + + public WrappedLiveData<FullBoard> cloneBoard(long originAccountId, long originBoardLocalId, long targetAccountId, @ColorInt int targetBoardColor, boolean cloneCards) { + return syncManager.cloneBoard(originAccountId, originBoardLocalId, targetAccountId, targetBoardColor, cloneCards); + } + + public WrappedLiveData<Void> deleteBoard(@NonNull Board board) { + return syncManager.deleteBoard(board); + } + + public LiveData<Boolean> hasArchivedBoards(long accountId) { + return syncManager.hasArchivedBoards(accountId); + } + + public WrappedLiveData<AccessControl> createAccessControl(long accountId, AccessControl entity) { + return syncManager.createAccessControl(accountId, entity); + } + + public WrappedLiveData<AccessControl> updateAccessControl(@NonNull AccessControl entity) { + return syncManager.updateAccessControl(entity); + } + + public LiveData<List<AccessControl>> getAccessControlByLocalBoardId(long accountId, Long id) { + return syncManager.getAccessControlByLocalBoardId(accountId, id); + } + + public WrappedLiveData<Void> deleteAccessControl(@NonNull AccessControl entity) { + return syncManager.deleteAccessControl(entity); + } + + public WrappedLiveData<Label> createLabel(long accountId, Label label, long localBoardId) { + return syncManager.createLabel(accountId, label, localBoardId); + } + + public LiveData<Integer> countCardsWithLabel(long localLabelId) { + return syncManager.countCardsWithLabel(localLabelId); + } + + public WrappedLiveData<Label> updateLabel(@NonNull Label label) { + return syncManager.updateLabel(label); + } + + public WrappedLiveData<Void> deleteLabel(@NonNull Label label) { + return syncManager.deleteLabel(label); + } + + public LiveData<List<Stack>> getStacksForBoard(long accountId, long localBoardId) { + return syncManager.getStacksForBoard(accountId, localBoardId); + } + + public WrappedLiveData<FullStack> createStack(long accountId, @NonNull String title, long boardLocalId) { + return syncManager.createStack(accountId, title, boardLocalId); + } + + public LiveData<FullStack> getStack(long accountId, long localStackId) { + return syncManager.getStack(accountId, localStackId); + } + + public void swapStackOrder(long accountId, long boardLocalId, @NonNull Pair<Long, Long> stackLocalIds) { + syncManager.swapStackOrder(accountId, boardLocalId, stackLocalIds); + } + + public WrappedLiveData<FullStack> updateStackTitle(long localStackId, @NonNull String newTitle) { + return syncManager.updateStackTitle(localStackId, newTitle); + } + + public WrappedLiveData<Void> deleteStack(long accountId, long stackLocalId, long boardLocalId) { + return syncManager.deleteStack(accountId, stackLocalId, boardLocalId); + } + + public void reorder(long accountId, @NonNull FullCard movedCard, long newStackId, int newIndex) { + syncManager.reorder(accountId, movedCard, newStackId, newIndex); + } + + public LiveData<Integer> countCardsInStack(long accountId, long localStackId) { + return syncManager.countCardsInStack(accountId, localStackId); + } + + public WrappedLiveData<Void> archiveCardsInStack(long accountId, long stackLocalId, @NonNull FilterInformation filterInformation) { + return syncManager.archiveCardsInStack(accountId, stackLocalId, filterInformation); + } + + public WrappedLiveData<FullCard> updateCard(@NonNull FullCard fullCard) { + return syncManager.updateCard(fullCard); + } + + public void addCommentToCard(long accountId, long cardId, @NonNull DeckComment comment) { + syncManager.addCommentToCard(accountId, cardId, comment); + } + + public WrappedLiveData<Attachment> addAttachmentToCard(long accountId, long localCardId, @NonNull String mimeType, @NonNull File file) { + return syncManager.addAttachmentToCard(accountId, localCardId, mimeType, file); + } + + public void addOrUpdateSingleCardWidget(int widgetId, long accountId, long boardId, long localCardId) { + syncManager.addOrUpdateSingleCardWidget(widgetId, accountId, boardId, localCardId); + } + + public LiveData<List<FullCard>> getFullCardsForStack(long accountId, long localStackId, @Nullable FilterInformation filter) { + return syncManager.getFullCardsForStack(accountId, localStackId, filter); + } + + public WrappedLiveData<Void> moveCard(long originAccountId, long originCardLocalId, long targetAccountId, long targetBoardLocalId, long targetStackLocalId) { + return syncManager.moveCard(originAccountId, originCardLocalId, targetAccountId, targetBoardLocalId, targetStackLocalId); + } + + public LiveData<List<FullCard>> getArchivedFullCardsForBoard(long accountId, long localBoardId) { + return syncManager.getArchivedFullCardsForBoard(accountId, localBoardId); + } + + public void assignUserToCard(@NonNull User user, @NonNull Card card) { + syncManager.assignUserToCard(user, card); + } + + public void unassignUserFromCard(@NonNull User user, @NonNull Card card) { + syncManager.unassignUserFromCard(user, card); + } + + public User getUserByUidDirectly(long accountId, String uid) { + return syncManager.getUserByUidDirectly(accountId, uid); + } + + public WrappedLiveData<FullCard> archiveCard(@NonNull FullCard card) { + return syncManager.archiveCard(card); + } + + public WrappedLiveData<FullCard> dearchiveCard(@NonNull FullCard card) { + return syncManager.dearchiveCard(card); + } + + public WrappedLiveData<Void> deleteCard(@NonNull Card card) { + return syncManager.deleteCard(card); + } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PickStackActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PickStackActivity.java index e0a9b6a06..2339a8783 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PickStackActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PickStackActivity.java @@ -11,6 +11,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; +import androidx.lifecycle.ViewModelProvider; import java.util.List; @@ -21,11 +22,11 @@ import it.niedermann.nextcloud.deck.databinding.ActivityPickStackBinding; 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.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.branding.Branded; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import it.niedermann.nextcloud.deck.ui.pickstack.PickStackFragment; import it.niedermann.nextcloud.deck.ui.pickstack.PickStackListener; +import it.niedermann.nextcloud.deck.ui.pickstack.PickStackViewModel; import static androidx.lifecycle.Transformations.switchMap; import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; @@ -36,8 +37,7 @@ import static it.niedermann.nextcloud.deck.util.DeckColorUtil.contrastRatioIsSuf public abstract class PickStackActivity extends AppCompatActivity implements Branded, PickStackListener { protected ActivityPickStackBinding binding; - - protected SyncManager syncManager; + protected PickStackViewModel viewModel; private boolean brandingEnabled; @@ -55,14 +55,14 @@ public abstract class PickStackActivity extends AppCompatActivity implements Bra brandingEnabled = isBrandingEnabled(this); binding = ActivityPickStackBinding.inflate(getLayoutInflater()); + viewModel = new ViewModelProvider(this).get(PickStackViewModel.class); + setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); - syncManager = new SyncManager(this); - - switchMap(syncManager.hasAccounts(), hasAccounts -> { + switchMap(viewModel.hasAccounts(), hasAccounts -> { if (hasAccounts) { - return syncManager.readAccounts(); + return viewModel.readAccounts(); } else { startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); return null; @@ -89,11 +89,7 @@ public abstract class PickStackActivity extends AppCompatActivity implements Bra binding.submit.setEnabled(false); } else { applyBrand(board.getColor()); - if (stack == null) { - binding.submit.setEnabled(false); - } else { - binding.submit.setEnabled(true); - } + binding.submit.setEnabled(stack != null); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java index a02f5aad3..cdc20ed50 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java @@ -9,8 +9,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.UiThread; import androidx.appcompat.app.AppCompatActivity; - -import com.nextcloud.android.sso.helper.SingleAccountHelper; +import androidx.lifecycle.ViewModelProvider; import it.niedermann.android.util.ColorUtil; import it.niedermann.nextcloud.deck.DeckLog; @@ -18,7 +17,6 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.databinding.ActivityPushNotificationBinding; import it.niedermann.nextcloud.deck.model.Account; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.card.EditActivity; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import it.niedermann.nextcloud.deck.util.ProjectUtil; @@ -28,6 +26,7 @@ import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.Liv public class PushNotificationActivity extends AppCompatActivity { private ActivityPushNotificationBinding binding; + private PushNotificationViewModel viewModel; // Provided by Files app NotificationJob private static final String KEY_SUBJECT = "subject"; @@ -47,6 +46,8 @@ public class PushNotificationActivity extends AppCompatActivity { } binding = ActivityPushNotificationBinding.inflate(getLayoutInflater()); + viewModel = new ViewModelProvider(this).get(PushNotificationViewModel.class); + setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); @@ -63,7 +64,6 @@ public class PushNotificationActivity extends AppCompatActivity { binding.cancel.setOnClickListener((v) -> finish()); - final SyncManager accountReadingSyncManager = new SyncManager(this); final String cardRemoteIdString = getIntent().getStringExtra(KEY_CARD_REMOTE_ID); final String accountString = getIntent().getStringExtra(KEY_ACCOUNT); @@ -72,18 +72,17 @@ public class PushNotificationActivity extends AppCompatActivity { if (cardRemoteIdString != null) { try { final int cardRemoteId = Integer.parseInt(cardRemoteIdString); - observeOnce(accountReadingSyncManager.readAccount(accountString), this, (account -> { + observeOnce(viewModel.readAccount(accountString), this, (account -> { if (account != null) { - SingleAccountHelper.setCurrentAccount(this, account.getName()); - final SyncManager syncManager = new SyncManager(this); + viewModel.setAccount(account.getName()); DeckLog.verbose("account: " + account); - observeOnce(syncManager.getBoardByRemoteId(account.getId(), ids[0]), PushNotificationActivity.this, (board -> { + observeOnce(viewModel.getBoardByRemoteId(account.getId(), ids[0]), PushNotificationActivity.this, (board -> { DeckLog.verbose("BoardLocalId " + board); if (board != null) { - observeOnce(syncManager.getCardByRemoteID(account.getId(), cardRemoteId), PushNotificationActivity.this, (card -> { + observeOnce(viewModel.getCardByRemoteID(account.getId(), cardRemoteId), PushNotificationActivity.this, (card -> { DeckLog.verbose("Card: " + card); if (card != null) { - syncManager.synchronizeCard(new IResponseCallback<Boolean>(account) { + viewModel.synchronizeCard(new IResponseCallback<Boolean>(account) { @Override public void onResponse(Boolean response) { openCardOnSubmit(account, board.getLocalId(), card.getLocalId()); @@ -98,11 +97,11 @@ public class PushNotificationActivity extends AppCompatActivity { } else { DeckLog.info("Card is not yet available locally. Synchronize board with localId " + board); - syncManager.synchronizeBoard(new IResponseCallback<Boolean>(account) { + viewModel.synchronizeBoard(new IResponseCallback<Boolean>(account) { @Override public void onResponse(Boolean response) { runOnUiThread(() -> { - observeOnce(syncManager.getCardByRemoteID(account.getId(), cardRemoteId), PushNotificationActivity.this, (card -> { + observeOnce(viewModel.getCardByRemoteID(account.getId(), cardRemoteId), PushNotificationActivity.this, (card -> { DeckLog.verbose("Card: " + card); if (card != null) { openCardOnSubmit(account, board.getLocalId(), card.getLocalId()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationViewModel.java new file mode 100644 index 000000000..d15b412f4 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationViewModel.java @@ -0,0 +1,52 @@ +package it.niedermann.nextcloud.deck.ui; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +import com.nextcloud.android.sso.helper.SingleAccountHelper; + +import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.model.Account; +import it.niedermann.nextcloud.deck.model.Board; +import it.niedermann.nextcloud.deck.model.Card; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; + +public class PushNotificationViewModel extends AndroidViewModel { + + private final SyncManager readAccountSyncManager; + private SyncManager accountSpecificSyncManager; + + public PushNotificationViewModel(@NonNull Application application) { + super(application); + this.readAccountSyncManager = new SyncManager(application); + } + + public LiveData<Account> readAccount(@Nullable String name) { + return readAccountSyncManager.readAccount(name); + } + + public void setAccount(@NonNull String accountName) { + SingleAccountHelper.setCurrentAccount(getApplication(), accountName); + accountSpecificSyncManager = new SyncManager(getApplication()); + } + + public LiveData<Board> getBoardByRemoteId(long accountId, long remoteId) { + return accountSpecificSyncManager.getBoardByRemoteId(accountId, remoteId); + } + + public LiveData<Card> getCardByRemoteID(long accountId, long remoteId) { + return accountSpecificSyncManager.getCardByRemoteID(accountId, remoteId); + } + + public void synchronizeCard(@NonNull IResponseCallback<Boolean> responseCallback, Card card) { + accountSpecificSyncManager.synchronizeCard(responseCallback, card); + } + + public void synchronizeBoard(@NonNull IResponseCallback<Boolean> responseCallback, long localBoadId) { + accountSpecificSyncManager.synchronizeBoard(responseCallback, localBoadId); + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java index e54923d1e..744498c4a 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java @@ -1,7 +1,6 @@ package it.niedermann.nextcloud.deck.ui.accountswitcher; import android.app.Dialog; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -22,7 +21,6 @@ import it.niedermann.android.util.DimensionUtil; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogAccountSwitcherBinding; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.MainViewModel; import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment; import it.niedermann.nextcloud.deck.ui.manageaccounts.ManageAccountsActivity; @@ -33,21 +31,15 @@ import static it.niedermann.nextcloud.deck.ui.MainActivity.ACTIVITY_MANAGE_ACCOU public class AccountSwitcherDialog extends BrandedDialogFragment { private AccountSwitcherAdapter adapter; - private SyncManager syncManager; private DialogAccountSwitcherBinding binding; private MainViewModel viewModel; - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class); - syncManager = new SyncManager(requireActivity()); - } - @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { binding = DialogAccountSwitcherBinding.inflate(requireActivity().getLayoutInflater()); + viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class); + binding.accountName.setText(viewModel.getCurrentAccount().getUserName()); binding.accountHost.setText(Uri.parse(viewModel.getCurrentAccount().getUrl()).getHost()); binding.check.setSelected(true); @@ -66,7 +58,7 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { dismiss(); })); - observeOnce(syncManager.readAccounts(), requireActivity(), (accounts) -> { + observeOnce(viewModel.readAccounts(), requireActivity(), (accounts) -> { accounts.remove(viewModel.getCurrentAccount()); adapter.setAccounts(accounts); }); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java index ed55c2411..d6d9cac1e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java @@ -33,7 +33,6 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa private MainViewModel viewModel; private ActivityArchivedBinding binding; private ArchivedBoardsAdapter adapter; - private SyncManager syncManager; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -58,10 +57,9 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa viewModel = new ViewModelProvider(this).get(MainViewModel.class); viewModel.setCurrentAccount(account); - syncManager = new SyncManager(this); adapter = new ArchivedBoardsAdapter(viewModel.isCurrentAccountIsSupportedVersion(), getSupportFragmentManager(), (board) -> { - final WrappedLiveData<FullBoard> liveData = syncManager.dearchiveBoard(board); + final WrappedLiveData<FullBoard> liveData = viewModel.dearchiveBoard(board); observeOnce(liveData, this, (fullBoard) -> { if (liveData.hasError()) { ExceptionDialogFragment.newInstance(liveData.getError(), viewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -70,7 +68,7 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa }); binding.recyclerView.setAdapter(adapter); - syncManager.getBoards(account.getId(), true).observe(this, (boards) -> { + viewModel.getBoards(account.getId(), true).observe(this, (boards) -> { viewModel.setCurrentAccountHasArchivedBoards(boards != null && boards.size() > 0); adapter.setBoards(boards == null ? Collections.emptyList() : boards); }); @@ -91,7 +89,7 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa @Override public void onBoardDeleted(Board board) { - final WrappedLiveData<Void> deleteLiveData = syncManager.deleteBoard(board); + final WrappedLiveData<Void> deleteLiveData = viewModel.deleteBoard(board); observeOnce(deleteLiveData, this, (next) -> { if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { ExceptionDialogFragment.newInstance(deleteLiveData.getError(), viewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -101,7 +99,7 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa @Override public void onUpdateBoard(FullBoard fullBoard) { - final WrappedLiveData<FullBoard> updateLiveData = syncManager.updateBoard(fullBoard); + final WrappedLiveData<FullBoard> updateLiveData = viewModel.updateBoard(fullBoard); observeOnce(updateLiveData, this, (next) -> { if (updateLiveData.hasError()) { ExceptionDialogFragment.newInstance(updateLiveData.getError(), viewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -111,7 +109,7 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa @Override public void onArchive(Board board) { - final WrappedLiveData<FullBoard> liveData = syncManager.dearchiveBoard(board); + final WrappedLiveData<FullBoard> liveData = viewModel.dearchiveBoard(board); observeOnce(liveData, this, (fullBoard) -> { if (liveData.hasError()) { ExceptionDialogFragment.newInstance(liveData.getError(), viewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java index ed2ee7097..b3533528e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java @@ -6,12 +6,15 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; import it.niedermann.nextcloud.deck.databinding.ActivityArchivedBinding; import it.niedermann.nextcloud.deck.model.Account; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper; +import it.niedermann.nextcloud.deck.ui.MainViewModel; import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; +import it.niedermann.nextcloud.deck.ui.pickstack.PickStackViewModel; public class ArchivedCardsActvitiy extends BrandedActivity { @@ -21,7 +24,8 @@ public class ArchivedCardsActvitiy extends BrandedActivity { private ActivityArchivedBinding binding; private ArchivedCardsAdapter adapter; - private SyncManager syncManager; + private MainViewModel viewModel; + private PickStackViewModel pickStackViewModel; private Account account; private long boardId; @@ -50,16 +54,20 @@ public class ArchivedCardsActvitiy extends BrandedActivity { } binding = ActivityArchivedBinding.inflate(getLayoutInflater()); + viewModel = new ViewModelProvider(this).get(MainViewModel.class); + pickStackViewModel = new ViewModelProvider(this).get(PickStackViewModel.class); + setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); - syncManager = new SyncManager(this); + viewModel.setCurrentAccount(account); + LiveDataHelper.observeOnce(viewModel.getFullBoardById(account.getId(), boardId), this, (fullBoard) -> { + viewModel.setCurrentBoard(fullBoard.getBoard()); - adapter = new ArchivedCardsAdapter(this, getSupportFragmentManager(), account, boardId, false, syncManager, this); - binding.recyclerView.setAdapter(adapter); + adapter = new ArchivedCardsAdapter(this, getSupportFragmentManager(), viewModel, this); + binding.recyclerView.setAdapter(adapter); - syncManager.getArchivedFullCardsForBoard(account.getId(), boardId).observe(this, (fullCards) -> { - adapter.setCardList(fullCards); + viewModel.getArchivedFullCardsForBoard(account.getId(), boardId).observe(this, (fullCards) -> adapter.setCardList(fullCards)); }); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsAdapter.java index 324d8362c..b5034ebfa 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsAdapter.java @@ -8,10 +8,10 @@ import androidx.fragment.app.FragmentManager; import androidx.lifecycle.LifecycleOwner; import it.niedermann.nextcloud.deck.R; -import it.niedermann.nextcloud.deck.model.Account; 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.card.AbstractCardViewHolder; import it.niedermann.nextcloud.deck.ui.card.CardAdapter; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; @@ -21,39 +21,35 @@ import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.Liv public class ArchivedCardsAdapter extends CardAdapter { @SuppressWarnings("WeakerAccess") - public ArchivedCardsAdapter(@NonNull Context context, @NonNull FragmentManager fragmentManager, @NonNull Account account, long boardId, boolean hasEditPermission, @NonNull SyncManager syncManager, @NonNull LifecycleOwner lifecycleOwner) { - super(context, fragmentManager, account, boardId, 0L, 0L, hasEditPermission, syncManager, lifecycleOwner, null); + public ArchivedCardsAdapter(@NonNull Context context, @NonNull FragmentManager fragmentManager, @NonNull MainViewModel viewModel, @NonNull LifecycleOwner lifecycleOwner) { + super(context, fragmentManager, 0L, viewModel, lifecycleOwner, null); } @Override public void onBindViewHolder(@NonNull AbstractCardViewHolder viewHolder, int position) { - viewHolder.bind(cardList.get(position), account, boardRemoteId, hasEditPermission, R.menu.archived_card_menu, this, counterMaxValue, mainColor); + viewHolder.bind(cardList.get(position), mainViewModel.getCurrentAccount(), mainViewModel.getCurrentBoardRemoteId(), false, R.menu.archived_card_menu, this, counterMaxValue, mainColor); } @Override public boolean onCardOptionsItemSelected(@NonNull MenuItem menuItem, @NonNull FullCard fullCard) { - switch (menuItem.getItemId()) { - case R.id.action_card_dearchive: { - final WrappedLiveData<FullCard> liveData = syncManager.dearchiveCard(fullCard); - observeOnce(liveData, lifecycleOwner, (next) -> { - if (liveData.hasError()) { - ExceptionDialogFragment.newInstance(liveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); - } - }); - return true; - } - case R.id.action_card_delete: { - final WrappedLiveData<Void> liveData = syncManager.deleteCard(fullCard.getCard()); - observeOnce(liveData, lifecycleOwner, (next) -> { - if (liveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(liveData.getError())) { - ExceptionDialogFragment.newInstance(liveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); - } - }); - return true; - } - default: { - return super.onCardOptionsItemSelected(menuItem, fullCard); - } + int itemId = menuItem.getItemId(); + if (itemId == R.id.action_card_dearchive) { + final WrappedLiveData<FullCard> liveData = mainViewModel.dearchiveCard(fullCard); + observeOnce(liveData, lifecycleOwner, (next) -> { + if (liveData.hasError()) { + ExceptionDialogFragment.newInstance(liveData.getError(), mainViewModel.getCurrentAccount()).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); + } + }); + return true; + } else if (itemId == R.id.action_card_delete) { + final WrappedLiveData<Void> liveData = mainViewModel.deleteCard(fullCard.getCard()); + observeOnce(liveData, lifecycleOwner, (next) -> { + if (liveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(liveData.getError())) { + ExceptionDialogFragment.newInstance(liveData.getError(), mainViewModel.getCurrentAccount()).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); + } + }); + return true; } + return super.onCardOptionsItemSelected(menuItem, fullCard); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java index 2eefd0c83..6618f7f72 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java @@ -12,6 +12,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.SharedElementCallback; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; +import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.widget.ViewPager2; @@ -24,7 +25,6 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ActivityAttachmentsBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.Attachment; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import it.niedermann.nextcloud.deck.util.MimeTypeUtil; @@ -35,6 +35,7 @@ public class AttachmentsActivity extends AppCompatActivity { private static final String BUNDLE_KEY_CURRENT_ATTACHMENT_LOCAL_ID = "currentAttachmenLocaltId"; private ActivityAttachmentsBinding binding; + private AttachmentsViewModel viewModel; private ViewPager2.OnPageChangeCallback onPageChangeCallback; @Override @@ -43,6 +44,8 @@ public class AttachmentsActivity extends AppCompatActivity { Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler(this)); binding = ActivityAttachmentsBinding.inflate(getLayoutInflater()); + viewModel = new ViewModelProvider(this).get(AttachmentsViewModel.class); + setContentView(binding.getRoot()); supportPostponeEnterTransition(); @@ -64,8 +67,7 @@ public class AttachmentsActivity extends AppCompatActivity { long cardId = args.getLong(BUNDLE_KEY_CARD_ID); - final SyncManager syncManager = new SyncManager(this); - syncManager.getFullCardWithProjectsByLocalId(account.getId(), cardId).observe(this, fullCard -> { + viewModel.getFullCardWithProjectsByLocalId(account.getId(), cardId).observe(this, fullCard -> { final List<Attachment> attachments = new ArrayList<>(); for (Attachment a : fullCard.getAttachments()) { if (MimeTypeUtil.isImage(a.getMimetype())) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsViewModel.java new file mode 100644 index 000000000..87a17470c --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsViewModel.java @@ -0,0 +1,25 @@ +package it.niedermann.nextcloud.deck.ui.attachments; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +import it.niedermann.nextcloud.deck.model.full.FullCardWithProjects; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; + +@SuppressWarnings("WeakerAccess") +public class AttachmentsViewModel extends AndroidViewModel { + + private final SyncManager syncManager; + + public AttachmentsViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } + + public LiveData<FullCardWithProjects> getFullCardWithProjectsByLocalId(long accountId, long cardLocalId) { + return syncManager.getFullCardWithProjectsByLocalId(accountId, cardLocalId); + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java index 1ee23abfa..9da836c4c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java @@ -14,7 +14,6 @@ import androidx.lifecycle.ViewModelProvider; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogTextColorInputBinding; import it.niedermann.nextcloud.deck.model.full.FullBoard; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.MainViewModel; import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment; @@ -59,7 +58,7 @@ public class EditBoardDialogFragment extends BrandedDialogFragment { this.editBoardListener.onUpdateBoard(fullBoard); }); final MainViewModel viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class); - new SyncManager(requireActivity()).getFullBoardById(viewModel.getCurrentAccount().getId(), args.getLong(KEY_BOARD_ID)).observe(EditBoardDialogFragment.this, (FullBoard fb) -> { + viewModel.getFullBoardById(viewModel.getCurrentAccount().getId(), args.getLong(KEY_BOARD_ID)).observe(EditBoardDialogFragment.this, (FullBoard fb) -> { if (fb.board != null) { this.fullBoard = fb; String title = this.fullBoard.getBoard().getTitle(); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java index e2320ca45..78ccd5333 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java @@ -43,7 +43,6 @@ public class AccessControlDialogFragment extends BrandedDialogFragment implement private static final String KEY_BOARD_ID = "board_id"; private long boardId; - private SyncManager syncManager; private UserAutoCompleteAdapter userAutoCompleteAdapter; private AccessControlAdapter adapter; @@ -75,10 +74,9 @@ public class AccessControlDialogFragment extends BrandedDialogFragment implement adapter = new AccessControlAdapter(viewModel.getCurrentAccount(), this, requireContext()); binding.peopleList.setAdapter(adapter); - syncManager = new SyncManager(requireActivity()); - syncManager.getFullBoardById(viewModel.getCurrentAccount().getId(), boardId).observe(this, (FullBoard fullBoard) -> { + viewModel.getFullBoardById(viewModel.getCurrentAccount().getId(), boardId).observe(this, (FullBoard fullBoard) -> { if (fullBoard != null) { - syncManager.getAccessControlByLocalBoardId(viewModel.getCurrentAccount().getId(), boardId).observe(this, (List<AccessControl> accessControlList) -> { + viewModel.getAccessControlByLocalBoardId(viewModel.getCurrentAccount().getId(), boardId).observe(this, (List<AccessControl> accessControlList) -> { final AccessControl ownerControl = new AccessControl(); ownerControl.setLocalId(HEADER_ITEM_LOCAL_ID); ownerControl.setUser(fullBoard.getOwner()); @@ -103,7 +101,7 @@ public class AccessControlDialogFragment extends BrandedDialogFragment implement @Override public void updateAccessControl(AccessControl accessControl) { - WrappedLiveData<AccessControl> updateLiveData = syncManager.updateAccessControl(accessControl); + WrappedLiveData<AccessControl> updateLiveData = viewModel.updateAccessControl(accessControl); observeOnce(updateLiveData, requireActivity(), (next) -> { if (updateLiveData.hasError()) { ExceptionDialogFragment.newInstance(updateLiveData.getError(), viewModel.getCurrentAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); @@ -113,7 +111,7 @@ public class AccessControlDialogFragment extends BrandedDialogFragment implement @Override public void deleteAccessControl(AccessControl ac) { - final WrappedLiveData<Void> wrappedDeleteLiveData = syncManager.deleteAccessControl(ac); + final WrappedLiveData<Void> wrappedDeleteLiveData = viewModel.deleteAccessControl(ac); adapter.remove(ac); observeOnce(wrappedDeleteLiveData, this, (ignored) -> { if (wrappedDeleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(wrappedDeleteLiveData.getError())) { @@ -134,7 +132,7 @@ public class AccessControlDialogFragment extends BrandedDialogFragment implement ac.setType(0L); // https://github.com/nextcloud/deck/blob/master/docs/API.md#post-boardsboardidacl---add-new-acl-rule ac.setUserId(user.getLocalId()); ac.setUser(user); - final WrappedLiveData<AccessControl> createLiveData = syncManager.createAccessControl(viewModel.getCurrentAccount().getId(), ac); + final WrappedLiveData<AccessControl> createLiveData = viewModel.createAccessControl(viewModel.getCurrentAccount().getId(), ac); observeOnce(createLiveData, this, (next) -> { if (createLiveData.hasError()) { ExceptionDialogFragment.newInstance(createLiveData.getError(), viewModel.getCurrentAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java index e06606493..bc0d98ca3 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java @@ -38,7 +38,6 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements private static final String KEY_BOARD_ID = "board_id"; private long boardId; - private SyncManager syncManager; @Override public void onAttach(@NonNull Context context) { @@ -67,8 +66,7 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements colors = getResources().getStringArray(R.array.board_default_colors); adapter = new ManageLabelsAdapter(this, requireContext()); binding.labels.setAdapter(adapter); - syncManager = new SyncManager(requireActivity()); - syncManager.getFullBoardById(viewModel.getCurrentAccount().getId(), boardId).observe(this, (fullBoard) -> { + viewModel.getFullBoardById(viewModel.getCurrentAccount().getId(), boardId).observe(this, (fullBoard) -> { if (fullBoard == null) { throw new IllegalStateException("FullBoard should not be null"); } @@ -82,7 +80,7 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements label.setTitle(binding.addLabelTitle.getText().toString()); label.setColor(colors[new Random().nextInt(colors.length)]); - WrappedLiveData<Label> createLiveData = syncManager.createLabel(viewModel.getCurrentAccount().getId(), label, boardId); + WrappedLiveData<Label> createLiveData = viewModel.createLabel(viewModel.getCurrentAccount().getId(), label, boardId); observeOnce(createLiveData, this, (createdLabel) -> { if (createLiveData.hasError()) { final Throwable error = createLiveData.getError(); @@ -126,7 +124,7 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements @Override public void requestDelete(@NonNull Label label) { - observeOnce(syncManager.countCardsWithLabel(label.getLocalId()), this, (count) -> { + observeOnce(viewModel.countCardsWithLabel(label.getLocalId()), this, (count) -> { if (count > 0) { new BrandedDeleteAlertDialogBuilder(requireContext()) .setTitle(getString(R.string.delete_something, label.getTitle())) @@ -141,7 +139,7 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements } private void deleteLabel(@NonNull Label label) { - final WrappedLiveData<Void> deleteLiveData = syncManager.deleteLabel(label); + final WrappedLiveData<Void> deleteLiveData = viewModel.deleteLabel(label); observeOnce(deleteLiveData, this, (v) -> { if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { final Throwable error = deleteLiveData.getError(); @@ -159,7 +157,7 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements @Override public void onLabelUpdated(@NonNull Label label) { - WrappedLiveData<Label> updateLiveData = syncManager.updateLabel(label); + WrappedLiveData<Label> updateLiveData = viewModel.updateLabel(label); observeOnce(updateLiveData, this, (updatedLabel) -> { if (updateLiveData.hasError()) { final Throwable error = updateLiveData.getError(); 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 ecb06c7a8..87140e544 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 @@ -33,6 +33,7 @@ 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.Branded; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import it.niedermann.nextcloud.deck.ui.movecard.MoveCardDialogFragment; @@ -46,16 +47,10 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im private final boolean compactMode; @NonNull - protected final SyncManager syncManager; + protected final MainViewModel mainViewModel; @NonNull protected final FragmentManager fragmentManager; - @NonNull - protected final Account account; - @Nullable - protected final Long boardRemoteId; - private final long boardLocalId; private final long stackId; - protected final boolean hasEditPermission; @NonNull private final Context context; @Nullable @@ -69,20 +64,16 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im @ColorInt protected int mainColor; @StringRes - private int shareLinkRes; + private final int shareLinkRes; - public CardAdapter(@NonNull Context context, @NonNull FragmentManager fragmentManager, @NonNull Account account, long boardLocalId, @Nullable Long boardRemoteId, long stackId, boolean hasEditPermission, @NonNull SyncManager syncManager, @NonNull LifecycleOwner lifecycleOwner, @Nullable SelectCardListener selectCardListener) { + public CardAdapter(@NonNull Context context, @NonNull FragmentManager fragmentManager, long stackId, @NonNull MainViewModel mainViewModel, @NonNull LifecycleOwner lifecycleOwner, @Nullable SelectCardListener selectCardListener) { this.context = context; this.counterMaxValue = context.getString(R.string.counter_max_value); this.fragmentManager = fragmentManager; this.lifecycleOwner = lifecycleOwner; - this.account = account; - this.shareLinkRes = account.getServerDeckVersionAsObject().getShareLinkResource(); - this.boardLocalId = boardLocalId; - this.boardRemoteId = boardRemoteId; + this.shareLinkRes = mainViewModel.getCurrentAccount().getServerDeckVersionAsObject().getShareLinkResource(); this.stackId = stackId; - this.hasEditPermission = hasEditPermission; - this.syncManager = syncManager; + this.mainViewModel = mainViewModel; this.selectCardListener = selectCardListener; this.mainColor = ContextCompat.getColor(context, R.color.defaultBrand); this.compactMode = getDefaultSharedPreferences(context).getBoolean(context.getString(R.string.pref_key_compact), false); @@ -97,15 +88,12 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im @NonNull @Override public AbstractCardViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { - switch (viewType) { - case R.layout.item_card_compact: - return new CompactCardViewHolder(ItemCardCompactBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false)); - case R.layout.item_card_default_only_title: - return new DefaultCardOnlyTitleViewHolder(ItemCardDefaultOnlyTitleBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false)); - case R.layout.item_card_default: - default: - return new DefaultCardViewHolder(ItemCardDefaultBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false)); + if (viewType == R.layout.item_card_compact) { + return new CompactCardViewHolder(ItemCardCompactBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false)); + } else if (viewType == R.layout.item_card_default_only_title) { + return new DefaultCardOnlyTitleViewHolder(ItemCardDefaultOnlyTitleBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false)); } + return new DefaultCardViewHolder(ItemCardDefaultBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false)); } @Override @@ -127,12 +115,12 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im @Override public void onBindViewHolder(@NonNull AbstractCardViewHolder viewHolder, int position) { @NonNull FullCard fullCard = cardList.get(position); - viewHolder.bind(fullCard, account, boardRemoteId, hasEditPermission, R.menu.card_menu, this, counterMaxValue, mainColor); + viewHolder.bind(fullCard, mainViewModel.getCurrentAccount(), mainViewModel.getCurrentBoardRemoteId(), mainViewModel.currentBoardHasEditPermission(), R.menu.card_menu, this, counterMaxValue, mainColor); // Only enable details view if there is no one waiting for selecting a card. viewHolder.bindCardClickListener((v) -> { if (selectCardListener == null) { - context.startActivity(EditActivity.createEditCardIntent(context, account, boardLocalId, fullCard.getLocalId())); + context.startActivity(EditActivity.createEditCardIntent(context, mainViewModel.getCurrentAccount(), mainViewModel.getCurrentBoardLocalId(), fullCard.getLocalId())); } else { selectCardListener.onCardSelected(fullCard); } @@ -194,47 +182,44 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im @Override public boolean onCardOptionsItemSelected(@NonNull MenuItem menuItem, @NonNull FullCard fullCard) { - switch (menuItem.getItemId()) { - case R.id.share_link: { - Intent shareIntent = new Intent() - .setAction(Intent.ACTION_SEND) - .setType(TEXT_PLAIN) - .putExtra(Intent.EXTRA_SUBJECT, fullCard.getCard().getTitle()) - .putExtra(Intent.EXTRA_TITLE, fullCard.getCard().getTitle()) - .putExtra(Intent.EXTRA_TEXT, account.getUrl() + context.getString(shareLinkRes, boardRemoteId, fullCard.getCard().getId())); - context.startActivity(Intent.createChooser(shareIntent, fullCard.getCard().getTitle())); - } - case R.id.action_card_assign: { - new Thread(() -> syncManager.assignUserToCard(syncManager.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); - return true; - } - case R.id.action_card_unassign: { - new Thread(() -> syncManager.unassignUserFromCard(syncManager.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); - return true; - } - case R.id.action_card_move: { - DeckLog.verbose("[Move card] Launch move dialog for " + Card.class.getSimpleName() + " \"" + fullCard.getCard().getTitle() + "\" (#" + fullCard.getLocalId() + ") from " + Stack.class.getSimpleName() + " #" + +stackId); - MoveCardDialogFragment.newInstance(fullCard.getAccountId(), boardLocalId, fullCard.getCard().getTitle(), fullCard.getLocalId()).show(fragmentManager, MoveCardDialogFragment.class.getSimpleName()); - return true; - } - case R.id.action_card_archive: { - final WrappedLiveData<FullCard> archiveLiveData = syncManager.archiveCard(fullCard); - observeOnce(archiveLiveData, lifecycleOwner, (v) -> { - if (archiveLiveData.hasError()) { - ExceptionDialogFragment.newInstance(archiveLiveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); - } - }); - return true; - } - case R.id.action_card_delete: { - final WrappedLiveData<Void> deleteLiveData = syncManager.deleteCard(fullCard.getCard()); - observeOnce(deleteLiveData, lifecycleOwner, (v) -> { - if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { - ExceptionDialogFragment.newInstance(deleteLiveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); - } - }); - return true; - } + int itemId = menuItem.getItemId(); + final Account account = mainViewModel.getCurrentAccount(); + if (itemId == R.id.share_link) { + Intent shareIntent = new Intent() + .setAction(Intent.ACTION_SEND) + .setType(TEXT_PLAIN) + .putExtra(Intent.EXTRA_SUBJECT, fullCard.getCard().getTitle()) + .putExtra(Intent.EXTRA_TITLE, fullCard.getCard().getTitle()) + .putExtra(Intent.EXTRA_TEXT, account.getUrl() + context.getString(shareLinkRes, mainViewModel.getCurrentBoardRemoteId(), fullCard.getCard().getId())); + context.startActivity(Intent.createChooser(shareIntent, fullCard.getCard().getTitle())); + new Thread(() -> mainViewModel.assignUserToCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); + return true; + } else if (itemId == R.id.action_card_assign) { + new Thread(() -> mainViewModel.assignUserToCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); + return true; + } else if (itemId == R.id.action_card_unassign) { + new Thread(() -> mainViewModel.unassignUserFromCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); + return true; + } else if (itemId == R.id.action_card_move) { + DeckLog.verbose("[Move card] Launch move dialog for " + Card.class.getSimpleName() + " \"" + fullCard.getCard().getTitle() + "\" (#" + fullCard.getLocalId() + ") from " + Stack.class.getSimpleName() + " #" + +stackId); + MoveCardDialogFragment.newInstance(fullCard.getAccountId(), mainViewModel.getCurrentBoardLocalId(), fullCard.getCard().getTitle(), fullCard.getLocalId()).show(fragmentManager, MoveCardDialogFragment.class.getSimpleName()); + return true; + } else if (itemId == R.id.action_card_archive) { + final WrappedLiveData<FullCard> archiveLiveData = mainViewModel.archiveCard(fullCard); + observeOnce(archiveLiveData, lifecycleOwner, (v) -> { + if (archiveLiveData.hasError()) { + ExceptionDialogFragment.newInstance(archiveLiveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); + } + }); + return true; + } else if (itemId == R.id.action_card_delete) { + final WrappedLiveData<Void> deleteLiveData = mainViewModel.deleteCard(fullCard.getCard()); + observeOnce(deleteLiveData, lifecycleOwner, (v) -> { + if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { + ExceptionDialogFragment.newInstance(deleteLiveData.getError(), account).show(fragmentManager, ExceptionDialogFragment.class.getSimpleName()); + } + }); + return true; } return true; } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java index fcc9d24e6..2e1ff5e06 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java @@ -26,7 +26,6 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ActivityEditBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.full.FullCard; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; @@ -45,7 +44,6 @@ public class EditActivity extends BrandedActivity { private ActivityEditBinding binding; private EditCardViewModel viewModel; - private SyncManager syncManager; private static final int[] tabTitles = new int[]{ R.string.card_edit_details, @@ -116,11 +114,10 @@ public class EditActivity extends BrandedActivity { throw new IllegalArgumentException(BUNDLE_KEY_ACCOUNT + " must not be null."); } viewModel.setAccount(account); - syncManager = new SyncManager(this, viewModel.getAccount().getName()); final long boardId = args.getLong(BUNDLE_KEY_BOARD_ID); - observeOnce(syncManager.getFullBoardById(account.getId(), boardId), EditActivity.this, (fullBoard -> { + observeOnce(viewModel.getFullBoardById(account.getId(), boardId), EditActivity.this, (fullBoard -> { applyBrand(fullBoard.getBoard().getColor()); viewModel.setCanEdit(fullBoard.getBoard().isPermissionEdit()); invalidateOptionsMenu(); @@ -138,7 +135,7 @@ public class EditActivity extends BrandedActivity { setupViewPager(); setupTitle(); } else { - observeOnce(syncManager.getFullCardWithProjectsByLocalId(account.getId(), cardId), EditActivity.this, (fullCard) -> { + observeOnce(viewModel.getFullCardWithProjectsByLocalId(account.getId(), cardId), EditActivity.this, (fullCard) -> { if (fullCard == null) { new BrandedAlertDialogBuilder(this) .setTitle(R.string.card_not_found) @@ -199,9 +196,9 @@ public class EditActivity extends BrandedActivity { .show(); } else { if (viewModel.isCreateMode()) { - observeOnce(syncManager.createFullCard(viewModel.getAccount().getId(), viewModel.getBoardId(), viewModel.getFullCard().getCard().getStackId(), viewModel.getFullCard()), EditActivity.this, (card) -> runnable.run()); + observeOnce(viewModel.createFullCard(viewModel.getAccount().getId(), viewModel.getBoardId(), viewModel.getFullCard().getCard().getStackId(), viewModel.getFullCard()), EditActivity.this, (card) -> runnable.run()); } else { - observeOnce(syncManager.updateCard(viewModel.getFullCard()), EditActivity.this, (card) -> runnable.run()); + observeOnce(viewModel.updateCard(viewModel.getFullCard()), EditActivity.this, (card) -> runnable.run()); } } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditCardViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditCardViewModel.java index 62fe6785f..c754d0800 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditCardViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditCardViewModel.java @@ -1,18 +1,32 @@ package it.niedermann.nextcloud.deck.ui.card; +import android.app.Application; + import androidx.annotation.NonNull; -import androidx.lifecycle.ViewModel; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import java.io.File; import java.util.ArrayList; +import java.util.List; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.model.Account; +import it.niedermann.nextcloud.deck.model.Attachment; +import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.Card; +import it.niedermann.nextcloud.deck.model.Label; +import it.niedermann.nextcloud.deck.model.full.FullBoard; +import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.model.full.FullCardWithProjects; +import it.niedermann.nextcloud.deck.model.ocs.Activity; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData; @SuppressWarnings("WeakerAccess") -public class EditCardViewModel extends ViewModel { +public class EditCardViewModel extends AndroidViewModel { + private SyncManager syncManager; private Account account; private long boardId; private FullCardWithProjects originalCard; @@ -23,6 +37,11 @@ public class EditCardViewModel extends ViewModel { private boolean canEdit = false; private boolean createMode = false; + public EditCardViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } + /** * Stores a deep copy of the given fullCard to be able to compare the state at every time in #{@link EditCardViewModel#hasChanges()} * @@ -55,11 +74,12 @@ public class EditCardViewModel extends ViewModel { public void setAccount(@NonNull Account account) { this.account = account; + this.syncManager = new SyncManager(getApplication(), account.getName()); hasCommentsAbility = account.getServerDeckVersionAsObject().supportsComments(); } public boolean hasChanges() { - if(fullCard == null) { + if (fullCard == null) { DeckLog.info("Can not check for changes because fullCard is null → assuming no changes have been made yet."); return false; } @@ -105,4 +125,44 @@ public class EditCardViewModel extends ViewModel { public long getBoardId() { return boardId; } + + public LiveData<FullBoard> getFullBoardById(Long accountId, Long localId) { + return syncManager.getFullBoardById(accountId, localId); + } + + public WrappedLiveData<Label> createLabel(long accountId, Label label, long localBoardId) { + return syncManager.createLabel(accountId, label, localBoardId); + } + + public LiveData<FullCardWithProjects> getFullCardWithProjectsByLocalId(long accountId, long cardLocalId) { + return syncManager.getFullCardWithProjectsByLocalId(accountId, cardLocalId); + } + + public WrappedLiveData<FullCard> createFullCard(long accountId, long localBoardId, long localStackId, @NonNull FullCard card) { + return syncManager.createFullCard(accountId, localBoardId, localStackId, card); + } + + public WrappedLiveData<FullCard> updateCard(@NonNull FullCard card) { + return syncManager.updateCard(card); + } + + public LiveData<List<Activity>> syncActivitiesForCard(@NonNull Card card) { + return syncManager.syncActivitiesForCard(card); + } + + public WrappedLiveData<Attachment> addAttachmentToCard(long accountId, long localCardId, @NonNull String mimeType, @NonNull File file) { + return syncManager.addAttachmentToCard(accountId, localCardId, mimeType, file); + } + + public WrappedLiveData<Void> deleteAttachmentOfCard(long accountId, long localCardId, long localAttachmentId) { + return syncManager.deleteAttachmentOfCard(accountId, localCardId, localAttachmentId); + } + + public LiveData<Card> getCardByRemoteID(long accountId, long remoteId) { + return syncManager.getCardByRemoteID(accountId, remoteId); + } + + public LiveData<Board> getBoardByRemoteId(long accountId, long remoteId) { + return syncManager.getBoardByRemoteId(accountId, remoteId); + } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityFragment.java index 08d960257..f95eea89f 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityFragment.java @@ -8,11 +8,9 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; -import androidx.recyclerview.widget.RecyclerView; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabActivitiesBinding; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; public class CardActivityFragment extends Fragment { @@ -39,17 +37,14 @@ public class CardActivityFragment extends Fragment { } if (!viewModel.isCreateMode()) { - final SyncManager syncManager = new SyncManager(requireContext()); - - syncManager.syncActivitiesForCard(viewModel.getFullCard().getCard()).observe(getViewLifecycleOwner(), (activities -> { + viewModel.syncActivitiesForCard(viewModel.getFullCard().getCard()).observe(getViewLifecycleOwner(), (activities -> { if (activities == null || activities.size() == 0) { binding.emptyContentView.setVisibility(View.VISIBLE); binding.activitiesList.setVisibility(View.GONE); } else { binding.emptyContentView.setVisibility(View.GONE); binding.activitiesList.setVisibility(View.VISIBLE); - RecyclerView.Adapter adapter = new CardActivityAdapter(activities, requireActivity().getMenuInflater()); - binding.activitiesList.setAdapter(adapter); + binding.activitiesList.setAdapter(new CardActivityAdapter(activities, requireActivity().getMenuInflater())); } })); } else { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java index 81a166cb6..07e8d39dd 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java @@ -104,7 +104,6 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme @ColorInt private int primaryColor; - private SyncManager syncManager; private CardAttachmentAdapter adapter; private AbstractPickerAdapter<?> pickerAdapter; @@ -146,7 +145,6 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme return binding.getRoot(); } - syncManager = new SyncManager(requireContext()); adapter = new CardAttachmentAdapter( getChildFragmentManager(), requireActivity().getMenuInflater(), @@ -436,7 +434,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme editViewModel.getFullCard().getAttachments().add(0, a); adapter.addAttachment(a); if (!editViewModel.isCreateMode()) { - WrappedLiveData<Attachment> liveData = syncManager.addAttachmentToCard(editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId(), a.getMimetype(), fileToUpload); + WrappedLiveData<Attachment> liveData = editViewModel.addAttachmentToCard(editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId(), a.getMimetype(), fileToUpload); observeOnce(liveData, getViewLifecycleOwner(), (next) -> { if (liveData.hasError()) { Throwable t = liveData.getError(); @@ -500,7 +498,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme adapter.removeAttachment(attachment); editViewModel.getFullCard().getAttachments().remove(attachment); if (!editViewModel.isCreateMode() && attachment.getLocalId() != null) { - final WrappedLiveData<Void> deleteLiveData = syncManager.deleteAttachmentOfCard(editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId(), attachment.getLocalId()); + final WrappedLiveData<Void> deleteLiveData = editViewModel.deleteAttachmentOfCard(editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId(), attachment.getLocalId()); observeOnce(deleteLiveData, this, (next) -> { if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { ExceptionDialogFragment.newInstance(deleteLiveData.getError(), editViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java index 44667bda8..bd6fdda43 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java @@ -40,7 +40,6 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit private FragmentCardEditTabCommentsBinding binding; private EditCardViewModel mainViewModel; private CommentsViewModel commentsViewModel; - private SyncManager syncManager; private CardCommentsAdapter adapter; public static Fragment newInstance() { @@ -70,7 +69,6 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit commentsViewModel = new ViewModelProvider(this).get(CommentsViewModel.class); - syncManager = new SyncManager(requireActivity()); adapter = new CardCommentsAdapter(requireContext(), mainViewModel.getAccount(), requireActivity().getMenuInflater(), this, this, getChildFragmentManager()); binding.comments.setAdapter(adapter); @@ -84,7 +82,7 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit // setupMentions(mainViewModel.getAccount(), comment.getComment().getMentions(), binding.replyCommentText); } }); - syncManager.getFullCommentsForLocalCardId(mainViewModel.getFullCard().getLocalId()).observe(getViewLifecycleOwner(), + commentsViewModel.getFullCommentsForLocalCardId(mainViewModel.getFullCard().getLocalId()).observe(getViewLifecycleOwner(), (comments) -> { if (comments != null && comments.size() > 0) { binding.emptyContentView.setVisibility(GONE); @@ -108,7 +106,7 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit comment.setParentId(parent.getId()); commentsViewModel.setReplyToComment(null); } - syncManager.addCommentToCard(mainViewModel.getAccount().getId(), mainViewModel.getFullCard().getLocalId(), comment); + commentsViewModel.addCommentToCard(mainViewModel.getAccount().getId(), mainViewModel.getFullCard().getLocalId(), comment); } binding.message.setText(null); }); @@ -136,12 +134,12 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit @Override public void onCommentEdited(Long id, String comment) { - syncManager.updateComment(mainViewModel.getAccount().getId(), mainViewModel.getFullCard().getLocalId(), id, comment); + commentsViewModel.updateComment(mainViewModel.getAccount().getId(), mainViewModel.getFullCard().getLocalId(), id, comment); } @Override public void onCommentDeleted(Long localId) { - final WrappedLiveData<Void> deleteLiveData = syncManager.deleteComment(mainViewModel.getAccount().getId(), mainViewModel.getFullCard().getLocalId(), localId); + final WrappedLiveData<Void> deleteLiveData = commentsViewModel.deleteComment(mainViewModel.getAccount().getId(), mainViewModel.getFullCard().getLocalId(), localId); observeOnce(deleteLiveData, this, (next) -> { if (deleteLiveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(deleteLiveData.getError())) { ExceptionDialogFragment.newInstance(deleteLiveData.getError(), mainViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CommentsViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CommentsViewModel.java index f7fd247a9..dada94d5b 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CommentsViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CommentsViewModel.java @@ -1,15 +1,30 @@ package it.niedermann.nextcloud.deck.ui.card.comments; +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; +import java.util.List; + +import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment; import it.niedermann.nextcloud.deck.model.ocs.comment.full.FullDeckComment; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData; @SuppressWarnings("WeakerAccess") -public class CommentsViewModel extends ViewModel { +public class CommentsViewModel extends AndroidViewModel { - private MutableLiveData<FullDeckComment> replyToComment = new MutableLiveData<>(); + private final SyncManager syncManager; + + private final MutableLiveData<FullDeckComment> replyToComment = new MutableLiveData<>(); + + public CommentsViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } public void setReplyToComment(FullDeckComment replyToComment) { this.replyToComment.postValue(replyToComment); @@ -18,4 +33,20 @@ public class CommentsViewModel extends ViewModel { public LiveData<FullDeckComment> getReplyToComment() { return this.replyToComment; } + + public LiveData<List<FullDeckComment>> getFullCommentsForLocalCardId(long localCardId) { + return syncManager.getFullCommentsForLocalCardId(localCardId); + } + + public void addCommentToCard(long accountId, long cardId, @NonNull DeckComment comment) { + syncManager.addCommentToCard(accountId, cardId, comment); + } + + public void updateComment(long accountId, long localCardId, long localCommentId, String comment) { + syncManager.updateComment(accountId, localCardId, localCommentId, comment); + } + + public WrappedLiveData<Void> deleteComment(long accountId, long localCardId, long localCommentId) { + return syncManager.deleteComment(accountId, localCardId, localCommentId); + } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java index 971a8cf6e..0b8541193 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java @@ -42,7 +42,6 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabDetailsBinding; import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.model.User; -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.BrandedDatePickerDialog; import it.niedermann.nextcloud.deck.ui.branding.BrandedFragment; @@ -64,7 +63,6 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis private FragmentCardEditTabDetailsBinding binding; private EditCardViewModel viewModel; - private SyncManager syncManager; private AssigneeAdapter adapter; private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT); @@ -99,8 +97,6 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis return binding.getRoot(); } - syncManager = new SyncManager(requireContext()); - @Px final int avatarSize = DimensionUtil.INSTANCE.dpToPx(requireContext(), R.dimen.avatar_size); final LinearLayout.LayoutParams avatarLayoutParams = new LinearLayout.LayoutParams(avatarSize, avatarSize); avatarLayoutParams.setMargins(0, 0, DimensionUtil.INSTANCE.dpToPx(requireContext(), R.dimen.spacer_1x), 0); @@ -235,7 +231,7 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis newLabel.setBoardId(boardId); newLabel.setTitle(((LabelAutoCompleteAdapter) binding.labels.getAdapter()).getLastFilterText()); newLabel.setLocalId(null); - WrappedLiveData<Label> createLabelLiveData = syncManager.createLabel(accountId, newLabel, boardId); + WrappedLiveData<Label> createLabelLiveData = viewModel.createLabel(accountId, newLabel, boardId); observeOnce(createLabelLiveData, CardDetailsFragment.this, createdLabel -> { if (createLabelLiveData.hasError()) { DeckLog.logError(createLabelLiveData.getError()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceAdapter.java index b6747a11c..4c95574c3 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceAdapter.java @@ -11,20 +11,20 @@ import java.util.ArrayList; import java.util.List; import it.niedermann.nextcloud.deck.databinding.ItemProjectResourceBinding; -import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProjectResource; +import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; public class CardProjectResourceAdapter extends RecyclerView.Adapter<CardProjectResourceViewHolder> { @NonNull - private final Account account; + private final EditCardViewModel viewModel; @NonNull private final List<OcsProjectResource> resources; @NonNull private final LifecycleOwner owner; - public CardProjectResourceAdapter(@NonNull Account account, @NonNull List<OcsProjectResource> resources, @NonNull LifecycleOwner owner) { - this.account = account; + public CardProjectResourceAdapter(@NonNull EditCardViewModel viewModel, @NonNull List<OcsProjectResource> resources, @NonNull LifecycleOwner owner) { + this.viewModel = viewModel; this.resources = new ArrayList<>(resources.size()); this.resources.addAll(resources); this.owner = owner; @@ -44,7 +44,7 @@ public class CardProjectResourceAdapter extends RecyclerView.Adapter<CardProject @Override public void onBindViewHolder(@NonNull CardProjectResourceViewHolder holder, int position) { - holder.bind(account, resources.get(position), owner); + holder.bind(viewModel, resources.get(position), owner); } @Override diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceViewHolder.java index d599ad5b5..272945e45 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourceViewHolder.java @@ -13,8 +13,8 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ItemProjectResourceBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProjectResource; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.card.EditActivity; +import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; import it.niedermann.nextcloud.deck.util.ProjectUtil; import static android.view.View.GONE; @@ -30,12 +30,12 @@ public class CardProjectResourceViewHolder extends RecyclerView.ViewHolder { this.binding = binding; } - public void bind(@NonNull Account account, @NonNull OcsProjectResource resource, @NonNull LifecycleOwner owner) { + public void bind(@NonNull EditCardViewModel viewModel, @NonNull OcsProjectResource resource, @NonNull LifecycleOwner owner) { + final Account account = viewModel.getAccount(); final Resources resources = itemView.getResources(); binding.name.setText(resource.getName()); final @Nullable String link = resource.getLink(); binding.type.setVisibility(VISIBLE); - final SyncManager syncManager = new SyncManager(itemView.getContext()); if (resource.getType() != null) { switch (resource.getType()) { case "deck": { @@ -49,9 +49,9 @@ public class CardProjectResourceViewHolder extends RecyclerView.ViewHolder { try { long[] ids = ProjectUtil.extractBoardIdAndCardIdFromUrl(link); if (ids.length == 2) { - syncManager.getCardByRemoteID(account.getId(), ids[1]).observe(owner, (fullCard) -> { + viewModel.getCardByRemoteID(account.getId(), ids[1]).observe(owner, (fullCard) -> { if (fullCard != null) { - syncManager.getBoardByRemoteId(account.getId(), ids[0]).observe(owner, (board) -> { + viewModel.getBoardByRemoteId(account.getId(), ids[0]).observe(owner, (board) -> { if (board != null) { binding.getRoot().setOnClickListener((v) -> itemView.getContext().startActivity(EditActivity.createEditCardIntent(itemView.getContext(), account, board.getLocalId(), fullCard.getLocalId()))); } else { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourcesDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourcesDialog.java index 9dc056634..46195b309 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourcesDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/projectresources/CardProjectResourcesDialog.java @@ -62,7 +62,7 @@ public class CardProjectResourcesDialog extends BrandedDialogFragment { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { - final CardProjectResourceAdapter adapter = new CardProjectResourceAdapter(viewModel.getAccount(), resources, requireActivity()); + final CardProjectResourceAdapter adapter = new CardProjectResourceAdapter(viewModel, resources, requireActivity()); binding.getRoot().setAdapter(adapter); super.onActivityCreated(savedInstanceState); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsFragment.java index fadf33b88..e7d693185 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsFragment.java @@ -12,7 +12,6 @@ import androidx.lifecycle.ViewModelProvider; import it.niedermann.nextcloud.deck.databinding.DialogFilterLabelsBinding; import it.niedermann.nextcloud.deck.model.Label; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.MainViewModel; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; @@ -31,7 +30,7 @@ public class FilterLabelsFragment extends Fragment implements SelectionListener< filterViewModel = new ViewModelProvider(requireActivity()).get(FilterViewModel.class); - observeOnce(new SyncManager(requireContext()).findProposalsForLabelsToAssign(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()), requireActivity(), (labels) -> { + observeOnce(filterViewModel.findProposalsForLabelsToAssign(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()), requireActivity(), (labels) -> { binding.labels.setNestedScrollingEnabled(false); binding.labels.setAdapter(new FilterLabelsAdapter( labels, diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserFragment.java index ffd558b65..6ffaec6a6 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterUserFragment.java @@ -14,7 +14,6 @@ import it.niedermann.android.util.DimensionUtil; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogFilterAssigneesBinding; import it.niedermann.nextcloud.deck.model.User; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.MainViewModel; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; @@ -33,7 +32,7 @@ public class FilterUserFragment extends Fragment implements SelectionListener<Us filterViewModel = new ViewModelProvider(requireActivity()).get(FilterViewModel.class); - observeOnce(new SyncManager(requireContext()).findProposalsForUsersToAssign(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()), requireActivity(), (users) -> { + observeOnce(filterViewModel.findProposalsForUsersToAssign(mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()), requireActivity(), (users) -> { binding.users.setNestedScrollingEnabled(false); binding.users.setAdapter(new FilterUserAdapter( DimensionUtil.INSTANCE.dpToPx(requireContext(), R.dimen.avatar_size), diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java index 50f287d62..c42a61ebd 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java @@ -1,28 +1,40 @@ package it.niedermann.nextcloud.deck.ui.filter; +import android.app.Application; + import androidx.annotation.IntRange; import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; + +import java.util.List; import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.model.User; import it.niedermann.nextcloud.deck.model.enums.EDueType; import it.niedermann.nextcloud.deck.model.internal.FilterInformation; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import static it.niedermann.nextcloud.deck.model.internal.FilterInformation.hasActiveFilter; @SuppressWarnings("WeakerAccess") -public class FilterViewModel extends ViewModel { +public class FilterViewModel extends AndroidViewModel { + + private final SyncManager syncManager; @IntRange(from = 0, to = 2) private int currentFilterTab = 0; @NonNull - private MutableLiveData<FilterInformation> filterInformationDraft = new MutableLiveData<>(new FilterInformation()); + private final MutableLiveData<FilterInformation> filterInformationDraft = new MutableLiveData<>(new FilterInformation()); @NonNull - private MutableLiveData<FilterInformation> filterInformation = new MutableLiveData<>(); + private final MutableLiveData<FilterInformation> filterInformation = new MutableLiveData<>(); + + public FilterViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } public void publishFilterInformationDraft() { this.filterInformation.postValue(hasActiveFilter(filterInformationDraft.getValue()) ? filterInformationDraft.getValue() : null); @@ -98,4 +110,12 @@ public class FilterViewModel extends ViewModel { public int getCurrentFilterTab() { return this.currentFilterTab; } + + public LiveData<List<User>> findProposalsForUsersToAssign(final long accountId, long boardId) { + return syncManager.findProposalsForUsersToAssign(accountId, boardId, -1L, -1); + } + + public LiveData<List<Label>> findProposalsForLabelsToAssign(final long accountId, final long boardId) { + return syncManager.findProposalsForLabelsToAssign(accountId, boardId, -1L); + } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java index 9d273cdcb..8aa45e39a 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java @@ -5,15 +5,12 @@ import android.util.Log; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; - -import com.nextcloud.android.sso.helper.SingleAccountHelper; +import androidx.lifecycle.ViewModelProvider; import it.niedermann.nextcloud.deck.databinding.ActivityManageAccountsBinding; import it.niedermann.nextcloud.deck.model.Account; -import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentAccountId; -import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentAccountId; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; public class ManageAccountsActivity extends AppCompatActivity { @@ -21,44 +18,37 @@ public class ManageAccountsActivity extends AppCompatActivity { private static final String TAG = ManageAccountsActivity.class.getSimpleName(); private ActivityManageAccountsBinding binding; + private ManageAccountsViewModel viewModel; private ManageAccountAdapter adapter; - private SyncManager syncManager = null; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityManageAccountsBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); + viewModel = new ViewModelProvider(this).get(ManageAccountsViewModel.class); + setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); - syncManager = new SyncManager(this); - - adapter = new ManageAccountAdapter((account) -> { - SingleAccountHelper.setCurrentAccount(getApplicationContext(), account.getName()); - syncManager = new SyncManager(this); - saveCurrentAccountId(this, account.getId()); - }, (accountPair) -> { + adapter = new ManageAccountAdapter((account) -> viewModel.setNewAccount(account), (accountPair) -> { if (accountPair.first != null) { - syncManager.deleteAccount(accountPair.first.getId()); + viewModel.deleteAccount(accountPair.first.getId()); } else { throw new IllegalArgumentException("Could not delete account because given account was null."); } Account newAccount = accountPair.second; if (newAccount != null) { - SingleAccountHelper.setCurrentAccount(getApplicationContext(), newAccount.getName()); - saveCurrentAccountId(this, newAccount.getId()); - syncManager = new SyncManager(this); + viewModel.setNewAccount(newAccount); } else { Log.i(TAG, "Got delete account request, but new account is null. Maybe last account has been deleted?"); } }); binding.accounts.setAdapter(adapter); - observeOnce(syncManager.readAccount(readCurrentAccountId(this)), this, (account -> { + observeOnce(viewModel.readAccount(readCurrentAccountId(this)), this, (account -> { adapter.setCurrentAccount(account); - syncManager.readAccounts().observe(this, (localAccounts -> { + viewModel.readAccounts().observe(this, (localAccounts -> { if (localAccounts.size() == 0) { Log.i(TAG, "No accounts, finishing " + ManageAccountsActivity.class.getSimpleName()); setResult(AppCompatActivity.RESULT_FIRST_USER); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsViewModel.java new file mode 100644 index 000000000..66e9d3850 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsViewModel.java @@ -0,0 +1,45 @@ +package it.niedermann.nextcloud.deck.ui.manageaccounts; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +import com.nextcloud.android.sso.helper.SingleAccountHelper; + +import java.util.List; + +import it.niedermann.nextcloud.deck.model.Account; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; + +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentAccountId; + +@SuppressWarnings("WeakerAccess") +public class ManageAccountsViewModel extends AndroidViewModel { + + private SyncManager syncManager; + + public ManageAccountsViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } + + public LiveData<Account> readAccount(long id) { + return syncManager.readAccount(id); + } + + public LiveData<List<Account>> readAccounts() { + return syncManager.readAccounts(); + } + + public void setNewAccount(@NonNull Account account) { + SingleAccountHelper.setCurrentAccount(getApplication(), account.getName()); + syncManager = new SyncManager(getApplication()); + saveCurrentAccountId(getApplication(), account.getId()); + } + + public void deleteAccount(long id) { + syncManager.deleteAccount(id); + } +} 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 index b14b60a7a..2b7eb52fe 100644 --- 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 @@ -21,6 +21,7 @@ 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; +import it.niedermann.nextcloud.deck.ui.pickstack.PickStackViewModel; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -37,6 +38,7 @@ public class MoveCardDialogFragment extends BrandedDialogFragment implements Pic private Long originCardLocalId; private DialogMoveCardBinding binding; + private PickStackViewModel viewModel; private MoveCardListener moveCardListener; private Account selectedAccount; 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 index 8e0d7179a..d65971cf4 100644 --- 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 @@ -13,6 +13,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; import java.util.List; @@ -20,7 +21,6 @@ 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.Stack; -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; @@ -35,11 +35,10 @@ import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentStackId; public class PickStackFragment extends Fragment { private FragmentPickStackBinding binding; + private PickStackViewModel viewModel; private static final String KEY_SHOW_BOARDS_WITHOUT_EDIT_PERMISSION = "show_boards_without_edit_permission"; - private SyncManager syncManager; - private PickStackListener pickStackListener; private boolean showBoardsWithoutEditPermission = false; @@ -127,6 +126,7 @@ public class PickStackFragment extends Fragment { super.onCreate(savedInstanceState); binding = FragmentPickStackBinding.inflate(getLayoutInflater()); + viewModel = new ViewModelProvider(requireActivity()).get(PickStackViewModel.class); accountAdapter = new AccountAdapter(requireContext()); binding.accountSelect.setAdapter(accountAdapter); @@ -138,11 +138,9 @@ public class PickStackFragment extends Fragment { binding.stackSelect.setAdapter(stackAdapter); binding.stackSelect.setEnabled(false); - syncManager = new SyncManager(requireContext()); - - switchMap(syncManager.hasAccounts(), hasAccounts -> { + switchMap(viewModel.hasAccounts(), hasAccounts -> { if (hasAccounts) { - return syncManager.readAccounts(); + return viewModel.readAccounts(); } else { startActivityForResult(new Intent(requireActivity(), ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); return null; @@ -170,12 +168,12 @@ public class PickStackFragment extends Fragment { binding.accountSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> { updateLiveDataSource(boardsLiveData, boardsObserver, showBoardsWithoutEditPermission - ? syncManager.getBoards(parent.getSelectedItemId()) - : syncManager.getBoardsWithEditPermission(parent.getSelectedItemId())); + ? viewModel.getBoards(parent.getSelectedItemId()) + : viewModel.getBoardsWithEditPermission(parent.getSelectedItemId())); }); binding.boardSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> { - updateLiveDataSource(stacksLiveData, stacksObserver, syncManager.getStacksForBoard(binding.accountSelect.getSelectedItemId(), parent.getSelectedItemId())); + updateLiveDataSource(stacksLiveData, stacksObserver, viewModel.getStacksForBoard(binding.accountSelect.getSelectedItemId(), parent.getSelectedItemId())); }); binding.stackSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java new file mode 100644 index 000000000..cc9fc2259 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java @@ -0,0 +1,45 @@ +package it.niedermann.nextcloud.deck.ui.pickstack; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +import java.util.List; + +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.persistence.sync.SyncManager; + +@SuppressWarnings("WeakerAccess") +public class PickStackViewModel extends AndroidViewModel { + + private final SyncManager syncManager; + + public PickStackViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } + + public LiveData<Boolean> hasAccounts() { + return syncManager.hasAccounts(); + } + + public LiveData<List<Account>> readAccounts() { + return syncManager.readAccounts(); + } + + public LiveData<List<Board>> getBoards(long accountId) { + return syncManager.getBoards(accountId); + } + + public LiveData<List<Board>> getBoardsWithEditPermission(long accountId) { + return syncManager.getBoardsWithEditPermission(accountId); + } + + public LiveData<List<Stack>> getStacksForBoard(long accountId, long localBoardId) { + return syncManager.getStacksForBoard(accountId, localBoardId); + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareTargetActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareTargetActivity.java index d5be7c04d..3a0005fb1 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareTargetActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareTargetActivity.java @@ -126,7 +126,7 @@ public class ShareTargetActivity extends MainActivity implements SelectCardListe throw new IllegalArgumentException("MimeType of uri is null. [" + uri + "]"); } runOnUiThread(() -> { - final WrappedLiveData<Attachment> liveData = syncManager.addAttachmentToCard(fullCard.getAccountId(), fullCard.getCard().getLocalId(), mimeType, tempFile); + final WrappedLiveData<Attachment> liveData = mainViewModel.addAttachmentToCard(fullCard.getAccountId(), fullCard.getCard().getLocalId(), mimeType, tempFile); liveData.observe(ShareTargetActivity.this, (next) -> { if (liveData.hasError()) { if (liveData.getError() instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) liveData.getError()).getStatusCode() == HTTP_CONFLICT) { @@ -160,7 +160,7 @@ public class ShareTargetActivity extends MainActivity implements SelectCardListe ? receivedText : oldDescription + "\n\n" + receivedText ); - WrappedLiveData<FullCard> liveData = syncManager.updateCard(fullCard); + WrappedLiveData<FullCard> liveData = mainViewModel.updateCard(fullCard); observeOnce(liveData, this, (next) -> { if (liveData.hasError()) { cardSelected = false; @@ -174,7 +174,7 @@ public class ShareTargetActivity extends MainActivity implements SelectCardListe case 1: final Account currentAccount = mainViewModel.getCurrentAccount(); final DeckComment comment = new DeckComment(receivedText.trim(), currentAccount.getUserName(), Instant.now()); - syncManager.addCommentToCard(currentAccount.getId(), fullCard.getLocalId(), comment); + mainViewModel.addCommentToCard(currentAccount.getId(), fullCard.getLocalId(), comment); Toast.makeText(getApplicationContext(), getString(R.string.share_success, "\"" + receivedText + "\"", "\"" + fullCard.getCard().getTitle() + "\""), Toast.LENGTH_LONG).show(); finish(); break; diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackAdapter.java index 4fe61794a..8fc56759f 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackAdapter.java @@ -12,7 +12,7 @@ import it.niedermann.nextcloud.deck.model.Stack; public class StackAdapter extends FragmentStateAdapter { @NonNull - private List<Stack> stackList = new ArrayList<>(); + private final List<Stack> stackList = new ArrayList<>(); public StackAdapter(@NonNull FragmentActivity fragmentActivity) { super(fragmentActivity); 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 7b0d2f20f..313e6e821 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 @@ -40,7 +40,7 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car private static final String KEY_STACK_ID = "stackId"; private FragmentStackBinding binding; - private SyncManager syncManager; + private MainViewModel mainViewModel; private FragmentActivity activity; private OnScrollListener onScrollListener; @@ -68,10 +68,10 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - binding = FragmentStackBinding.inflate(inflater, container, false); activity = requireActivity(); + binding = FragmentStackBinding.inflate(inflater, container, false); + mainViewModel = new ViewModelProvider(activity).get(MainViewModel.class); - final MainViewModel mainViewModel = new ViewModelProvider(activity).get(MainViewModel.class); final FilterViewModel filterViewModel = new ViewModelProvider(activity).get(FilterViewModel.class); // This might be a zombie fragment with an empty MainViewModel after Android killed the activity (but not the fragment instance @@ -81,19 +81,10 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car return binding.getRoot(); } - syncManager = new SyncManager(activity); - - adapter = new CardAdapter( - requireContext(), - getChildFragmentManager(), - mainViewModel.getCurrentAccount(), - mainViewModel.getCurrentBoardLocalId(), - mainViewModel.getCurrentBoardRemoteId(), - stackId, - mainViewModel.currentBoardHasEditPermission(), - syncManager, - this, - (requireActivity() instanceof SelectCardListener) ? (SelectCardListener) requireActivity() : null); + adapter = new CardAdapter(requireContext(), getChildFragmentManager(), stackId, mainViewModel, this, + (requireActivity() instanceof SelectCardListener) + ? (SelectCardListener) requireActivity() + : null); binding.recyclerView.setAdapter(adapter); if (onScrollListener != null) { @@ -121,12 +112,12 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car } }); - cardsLiveData = syncManager.getFullCardsForStack(mainViewModel.getCurrentAccount().getId(), stackId, filterViewModel.getFilterInformation().getValue()); + cardsLiveData = mainViewModel.getFullCardsForStack(mainViewModel.getCurrentAccount().getId(), stackId, filterViewModel.getFilterInformation().getValue()); cardsLiveData.observe(getViewLifecycleOwner(), cardsObserver); filterViewModel.getFilterInformation().observe(getViewLifecycleOwner(), (filterInformation -> { cardsLiveData.removeObserver(cardsObserver); - cardsLiveData = syncManager.getFullCardsForStack(mainViewModel.getCurrentAccount().getId(), stackId, filterInformation); + cardsLiveData = mainViewModel.getFullCardsForStack(mainViewModel.getCurrentAccount().getId(), stackId, filterInformation); cardsLiveData.observe(getViewLifecycleOwner(), cardsObserver); })); @@ -163,7 +154,7 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car @Override public void move(long originAccountId, long originCardLocalId, long targetAccountId, long targetBoardLocalId, long targetStackLocalId) { - WrappedLiveData<Void> liveData = syncManager.moveCard(originAccountId, originCardLocalId, targetAccountId, targetBoardLocalId, targetStackLocalId); + final WrappedLiveData<Void> liveData = mainViewModel.moveCard(originAccountId, originCardLocalId, targetAccountId, targetBoardLocalId, targetStackLocalId); observeOnce(liveData, requireActivity(), (next) -> { if (liveData.hasError() && !SyncManager.ignoreExceptionOnVoidError(liveData.getError())) { ExceptionDialogFragment.newInstance(liveData.getError(), null).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java index 8c1fbe1fa..fe6e969e7 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java @@ -45,7 +45,7 @@ public class SelectCardForWidgetActivity extends MainActivity implements SelectC @Override public void onCardSelected(FullCard fullCard) { - syncManager.addOrUpdateSingleCardWidget(appWidgetId, mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), fullCard.getLocalId()); + mainViewModel.addOrUpdateSingleCardWidget(appWidgetId, mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), fullCard.getLocalId()); final Intent updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, getApplicationContext(), SingleCardWidget.class) .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java index 771feabc2..96b5cf672 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.ActionBar; +import androidx.lifecycle.ViewModelProvider; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; @@ -13,10 +14,14 @@ import it.niedermann.nextcloud.deck.ui.PickStackActivity; public class StackWidgetConfigurationActivity extends PickStackActivity { private int appWidgetId; + private StackWidgetConfigurationViewModel stackWidgetConfigurationViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + stackWidgetConfigurationViewModel = new ViewModelProvider(this).get(StackWidgetConfigurationViewModel.class); + final ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setTitle(R.string.add_stack_widget); @@ -40,9 +45,9 @@ public class StackWidgetConfigurationActivity extends PickStackActivity { protected void onSubmit(Account account, long boardId, long stackId) { final Bundle extras = new Bundle(); - syncManager.addStackWidget(appWidgetId, account.getId(), stackId, false); + stackWidgetConfigurationViewModel.addStackWidget(appWidgetId, account.getId(), stackId, false); Intent updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, - getApplicationContext(), StackWidget.class); + getApplicationContext(), StackWidget.class); extras.putSerializable(StackWidget.ACCOUNT_KEY, account); extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationViewModel.java new file mode 100644 index 000000000..cc669accf --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationViewModel.java @@ -0,0 +1,23 @@ +package it.niedermann.nextcloud.deck.ui.widget.stack; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; + +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; + +@SuppressWarnings("WeakerAccess") +public class StackWidgetConfigurationViewModel extends AndroidViewModel { + + private final SyncManager syncManager; + + public StackWidgetConfigurationViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } + + public void addStackWidget(int appWidgetId, long accountId, long stackId, boolean darkTheme) { + syncManager.addStackWidget(appWidgetId, accountId, stackId, darkTheme); + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/SpannableUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/SpannableUtil.java index 54f3c8adc..c2ba6f46a 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/util/SpannableUtil.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/SpannableUtil.java @@ -21,28 +21,28 @@ import it.niedermann.nextcloud.deck.R; public class SpannableUtil { public static SpannableString strong(@NonNull CharSequence text) { - SpannableString span = new SpannableString(text); + final SpannableString span = new SpannableString(text); span.setSpan(new StyleSpan(Typeface.BOLD), 0, span.length(), 0); return span; } public static SpannableString disabled(@NonNull CharSequence text, @NonNull Context context) { - SpannableString span = new SpannableString(text); + final SpannableString span = new SpannableString(text); span.setSpan(new StyleSpan(Typeface.ITALIC), 0, span.length(), 0); span.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.fg_secondary)), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return span; } public static SpannableString url(@NonNull CharSequence text, @NonNull String target) { - SpannableString span = new SpannableString(text); + final SpannableString span = new SpannableString(text); span.setSpan(new URLSpan(target), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return span; } public static void setTextWithURL(@NonNull TextView textView, @NonNull Resources resources, @StringRes int containerTextId, @StringRes int linkLabelId, @StringRes int urlId) { - String linkLabel = resources.getString(linkLabelId); - String finalText = resources.getString(containerTextId, linkLabel); - SpannableStringBuilder finalTextBuilder = new SpannableStringBuilder(finalText); + final String linkLabel = resources.getString(linkLabelId); + final String finalText = resources.getString(containerTextId, linkLabel); + final SpannableStringBuilder finalTextBuilder = new SpannableStringBuilder(finalText); finalTextBuilder.setSpan(new URLSpan(resources.getString(urlId)), finalText.indexOf(linkLabel), finalText.indexOf(linkLabel) + linkLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(finalTextBuilder); textView.setMovementMethod(new LinkMovementMethod()); |