diff options
author | Stefan Niedermann <info@niedermann.it> | 2020-04-21 18:35:55 +0300 |
---|---|---|
committer | Niedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com> | 2020-04-21 21:18:28 +0300 |
commit | 47f79909944ffd2e0fa8b47deeb4a62d21f4c1e4 (patch) | |
tree | 4132e17ace253aa54368f13526cae32bad97caaf /app/src/main/java/it/niedermann | |
parent | b8a0a33cdbed5363b7552f78660a010cba567adb (diff) |
Use ViewModel for EditActivity
This is capable of solving #270 (NullPointerException when saving new card after rotating the device)
Diffstat (limited to 'app/src/main/java/it/niedermann')
5 files changed, 242 insertions, 230 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardTabAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardTabAdapter.java index 408e1123c..0c384837f 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardTabAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardTabAdapter.java @@ -40,7 +40,7 @@ public class CardTabAdapter extends FragmentStateAdapter { public Fragment createFragment(int position) { switch (position) { case 0: - return CardDetailsFragment.newInstance(accountId, localId, boardId, canEdit); + return CardDetailsFragment.newInstance(); case 1: return CardAttachmentsFragment.newInstance(accountId, localId, boardId, canEdit); case 2: 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 1b4348c35..cbfd5047b 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 @@ -9,19 +9,14 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.WindowManager; +import androidx.lifecycle.ViewModelProvider; + import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; -import java.util.ArrayList; -import java.util.Date; - import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ActivityEditBinding; import it.niedermann.nextcloud.deck.model.Attachment; -import it.niedermann.nextcloud.deck.model.Card; -import it.niedermann.nextcloud.deck.model.Label; -import it.niedermann.nextcloud.deck.model.User; -import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.model.ocs.Version; import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; @@ -30,7 +25,6 @@ import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.card.attachments.NewCardAttachmentHandler; import it.niedermann.nextcloud.deck.ui.card.comments.CommentAddedListener; import it.niedermann.nextcloud.deck.ui.card.comments.CommentDeletedListener; -import it.niedermann.nextcloud.deck.ui.card.details.CardDetailsListener; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import it.niedermann.nextcloud.deck.util.CardUtil; @@ -41,11 +35,12 @@ import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_STACK_ID; import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID; -public class EditActivity extends BrandedActivity implements CardDetailsListener, CommentAddedListener, CommentDeletedListener, NewCardAttachmentHandler { +public class EditActivity extends BrandedActivity implements CommentAddedListener, CommentDeletedListener, NewCardAttachmentHandler { private ActivityEditBinding binding; private SyncManager syncManager; - boolean hasCommentsAbility = false; + + private EditCardViewModel viewModel; private static final int[] tabTitles = new int[]{ R.string.card_edit_details, @@ -73,18 +68,11 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener R.drawable.ic_activity_light_grey }; - private FullCard originalCard; - private FullCard fullCard; - private long accountId; private long boardId; private long stackId; private long localId; - private boolean pendingCreation = false; - private boolean canEdit; - private boolean createMode; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -96,7 +84,7 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener setSupportActionBar(binding.toolbar); - Bundle args = getIntent().getExtras(); + final Bundle args = getIntent().getExtras(); if (args == null || !args.containsKey(BUNDLE_KEY_ACCOUNT_ID) || !args.containsKey(BUNDLE_KEY_BOARD_ID)) { throw new IllegalArgumentException("Provide at least " + BUNDLE_KEY_ACCOUNT_ID + " and " + BUNDLE_KEY_BOARD_ID + " so we know where to create this new card."); @@ -106,8 +94,11 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener boardId = args.getLong(BUNDLE_KEY_BOARD_ID); localId = args.getLong(BUNDLE_KEY_LOCAL_ID, NO_LOCAL_ID); + viewModel = new ViewModelProvider(this).get(EditCardViewModel.class); + syncManager = new SyncManager(this); + if (localId == NO_LOCAL_ID) { - createMode = true; + viewModel.setCreateMode(true); if (args.containsKey(BUNDLE_KEY_STACK_ID)) { stackId = args.getLong(BUNDLE_KEY_STACK_ID); } else { @@ -115,28 +106,19 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener } } - syncManager = new SyncManager(this); - observeOnce(syncManager.getFullBoardById(accountId, boardId), EditActivity.this, (fullBoard -> { - canEdit = fullBoard.getBoard().isPermissionEdit(); + viewModel.setCanEdit(fullBoard.getBoard().isPermissionEdit()); invalidateOptionsMenu(); - if (createMode) { - fullCard = new FullCard(); - originalCard = new FullCard(); - fullCard.setLabels(new ArrayList<>()); - fullCard.setAssignedUsers(new ArrayList<>()); - fullCard.setAttachments(new ArrayList<>()); - Card card = new Card(); - card.setStackId(stackId); - fullCard.setCard(card); + if (viewModel.isCreateMode()) { + viewModel.initializeNewCard(accountId, boardId, stackId); + setupViewPager(); - setupTitle(createMode); + setupTitle(viewModel.isCreateMode()); } else { observeOnce(syncManager.getCardByLocalId(accountId, localId), EditActivity.this, (next) -> { - fullCard = next; - originalCard = new FullCard(fullCard); + viewModel.initializeExistingCard(accountId, boardId, next); setupViewPager(); - setupTitle(createMode); + setupTitle(viewModel.isCreateMode()); }); } })); @@ -144,7 +126,7 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener @Override public boolean onCreateOptionsMenu(Menu menu) { - if (canEdit) { + if (viewModel.canEdit()) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.card_edit_menu, menu); } else { @@ -162,23 +144,24 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener } private void saveAndFinish() { - if (!pendingCreation) { - pendingCreation = true; - if (fullCard.getCard().getTitle() == null || fullCard.getCard().getTitle().isEmpty()) { - fullCard.getCard().setTitle(CardUtil.generateTitleFromDescription(fullCard.getCard().getDescription())); + if (!viewModel.isPendingCreation()) { + viewModel.setPendingCreation(true); + final String title = viewModel.getFullCard().getCard().getTitle(); + if (title == null || title.isEmpty()) { + viewModel.getFullCard().getCard().setTitle(CardUtil.generateTitleFromDescription(viewModel.getFullCard().getCard().getDescription())); } - if (fullCard.getCard().getTitle().isEmpty()) { + if (viewModel.getFullCard().getCard().getTitle().isEmpty()) { new BrandedAlertDialogBuilder(this) .setTitle(R.string.title_is_mandatory) .setMessage(R.string.provide_at_least_a_title_or_description) .setPositiveButton(android.R.string.ok, null) - .setOnDismissListener(dialog -> pendingCreation = false) + .setOnDismissListener(dialog -> viewModel.setPendingCreation(false)) .show(); } else { - if (createMode) { - observeOnce(syncManager.createFullCard(accountId, boardId, stackId, fullCard), EditActivity.this, (card) -> super.finish()); + if (viewModel.isCreateMode()) { + observeOnce(syncManager.createFullCard(accountId, boardId, stackId, viewModel.getFullCard()), EditActivity.this, (card) -> super.finish()); } else { - observeOnce(syncManager.updateCard(fullCard), EditActivity.this, (card) -> super.finish()); + observeOnce(syncManager.updateCard(viewModel.getFullCard()), EditActivity.this, (card) -> super.finish()); } } } @@ -188,23 +171,21 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener binding.tabLayout.removeAllTabs(); binding.tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); - CardTabAdapter adapter = new CardTabAdapter( + final CardTabAdapter adapter = new CardTabAdapter( getSupportFragmentManager(), getLifecycle(), accountId, localId, boardId, - canEdit); - TabLayoutMediator mediator = new TabLayoutMediator(binding.tabLayout, binding.pager, (tab, position) -> { - tab.setIcon( - hasCommentsAbility - ? tabIconsWithComments[position] - : tabIcons[position] + viewModel.canEdit()); + final TabLayoutMediator mediator = new TabLayoutMediator(binding.tabLayout, binding.pager, (tab, position) -> { + tab.setIcon(viewModel.isHasCommentsAbility() + ? tabIconsWithComments[position] + : tabIcons[position] ); - tab.setContentDescription( - hasCommentsAbility - ? tabTitlesWithComments[position] - : tabTitles[position] + tab.setContentDescription(viewModel.isHasCommentsAbility() + ? tabTitlesWithComments[position] + : tabTitles[position] ); }); runOnUiThread(() -> { @@ -214,10 +195,10 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener }); // Comments API only available starting with version 1.0.0-alpha1 - if (!createMode) { + if (!viewModel.isCreateMode()) { syncManager.readAccount(accountId).observe(this, (account) -> { - hasCommentsAbility = ((account.getServerDeckVersionAsObject().compareTo(new Version("1.0.0", 1, 0, 0)) >= 0)); - if (hasCommentsAbility) { + viewModel.setHasCommentsAbility(account.getServerDeckVersionAsObject().isGreaterOrEqualTo(new Version("1.0.0", 1, 0, 0))); + if (viewModel.isHasCommentsAbility()) { runOnUiThread(() -> { mediator.detach(); adapter.enableComments(); @@ -230,20 +211,20 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener } private void setupTitle(boolean createMode) { - binding.title.setText(fullCard.getCard().getTitle()); - if (canEdit) { + binding.title.setText(viewModel.getFullCard().getCard().getTitle()); + if (viewModel.canEdit()) { if (createMode) { binding.title.requestFocus(); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - if (fullCard.getCard().getTitle() != null) { - binding.title.setSelection(fullCard.getCard().getTitle().length()); + if (viewModel.getFullCard().getCard().getTitle() != null) { + binding.title.setSelection(viewModel.getFullCard().getCard().getTitle().length()); } } binding.title.setHint(getString(createMode ? R.string.simple_add : R.string.edit)); binding.title.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - fullCard.getCard().setTitle(binding.title.getText().toString()); + viewModel.getFullCard().getCard().setTitle(binding.title.getText().toString()); } @Override @@ -261,36 +242,6 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener } @Override - public void onDescriptionChanged(String description) { - this.fullCard.getCard().setDescription(description); - } - - @Override - public void onUserAdded(User user) { - this.fullCard.getAssignedUsers().add(user); - } - - @Override - public void onUserRemoved(User user) { - this.fullCard.getAssignedUsers().remove(user); - } - - @Override - public void onLabelAdded(Label label) { - this.fullCard.getLabels().add(label); - } - - @Override - public void onLabelRemoved(Label label) { - this.fullCard.getLabels().remove(label); - } - - @Override - public void onDueDateChanged(Date dueDate) { - this.fullCard.getCard().setDueDate(dueDate); - } - - @Override public boolean onSupportNavigateUp() { finish(); // close this activity as oppose to navigating up return true; @@ -303,7 +254,7 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener @Override public void finish() { - if (!fullCard.equals(originalCard) && canEdit) { + if (!viewModel.hasChanges() && viewModel.canEdit()) { new BrandedAlertDialogBuilder(this) .setTitle(R.string.simple_save) .setMessage(R.string.do_you_want_to_save_your_changes) @@ -321,12 +272,12 @@ public class EditActivity extends BrandedActivity implements CardDetailsListener @Override public void attachmentAdded(Attachment attachment) { - fullCard.getAttachments().add(attachment); + viewModel.getFullCard().getAttachments().add(attachment); } @Override public void attachmentRemoved(Attachment attachment) { - fullCard.getAttachments().remove(attachment); + viewModel.getFullCard().getAttachments().remove(attachment); } @Override 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 new file mode 100644 index 000000000..f89a95a66 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditCardViewModel.java @@ -0,0 +1,102 @@ +package it.niedermann.nextcloud.deck.ui.card; + +import androidx.annotation.NonNull; +import androidx.lifecycle.ViewModel; + +import java.util.ArrayList; + +import it.niedermann.nextcloud.deck.model.Card; +import it.niedermann.nextcloud.deck.model.full.FullCard; + +@SuppressWarnings("WeakerAccess") +public class EditCardViewModel extends ViewModel { + + private long accountId; + private long boardId; + private FullCard originalCard; + private FullCard fullCard; + private boolean hasCommentsAbility = false; + private boolean pendingCreation = false; + private boolean canEdit = false; + private boolean createMode = false; + + /** + * Stores a deep copy of the given fullCard to be able to compare the state at every time in #{@link EditCardViewModel#hasChanges()} + * + * @param accountId Expecting a positive long value + * @param boardId Local ID, expecting a positive long value + * @param fullCard The card that is currently edited + */ + public void initializeExistingCard(long accountId, long boardId, @NonNull FullCard fullCard) { + this.accountId = accountId; + this.boardId = boardId; + this.fullCard = fullCard; + this.originalCard = new FullCard(this.fullCard); + } + + /** + * Stores a deep copy of the given fullCard to be able to compare the state at every time in #{@link EditCardViewModel#hasChanges()} + * + * @param accountId Expecting a positive long value + * @param boardId Local ID, expecting a positive long value + * @param stackId Local ID, expecting a positive long value where the card should be created + */ + public void initializeNewCard(long accountId, long boardId, long stackId) { + final FullCard fullCard = new FullCard(); + fullCard.setLabels(new ArrayList<>()); + fullCard.setAssignedUsers(new ArrayList<>()); + fullCard.setAttachments(new ArrayList<>()); + final Card card = new Card(); + card.setStackId(stackId); + fullCard.setCard(card); + initializeExistingCard(accountId, boardId, fullCard); + } + + public boolean hasChanges() { + return fullCard.equals(originalCard); + } + + public boolean isHasCommentsAbility() { + return hasCommentsAbility; + } + + public void setHasCommentsAbility(boolean hasCommentsAbility) { + this.hasCommentsAbility = hasCommentsAbility; + } + + public long getAccountId() { + return accountId; + } + + public FullCard getFullCard() { + return fullCard; + } + + public boolean isPendingCreation() { + return pendingCreation; + } + + public void setPendingCreation(boolean pendingCreation) { + this.pendingCreation = pendingCreation; + } + + public boolean canEdit() { + return canEdit; + } + + public void setCanEdit(boolean canEdit) { + this.canEdit = canEdit; + } + + public boolean isCreateMode() { + return createMode; + } + + public void setCreateMode(boolean createMode) { + this.createMode = createMode; + } + + public long getBoardId() { + return boardId; + } +} 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 81efacba8..adb8e15e3 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 @@ -15,9 +15,12 @@ import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.Px; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.ColorUtils; import androidx.core.graphics.drawable.DrawableCompat; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import com.google.android.material.chip.Chip; import com.google.android.material.snackbar.Snackbar; @@ -39,55 +42,40 @@ import java.util.Locale; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabDetailsBinding; -import it.niedermann.nextcloud.deck.model.Card; import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.model.User; -import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.branding.BrandedDatePickerDialog; import it.niedermann.nextcloud.deck.ui.branding.BrandedFragment; import it.niedermann.nextcloud.deck.ui.branding.BrandedTimePickerDialog; +import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; import it.niedermann.nextcloud.deck.ui.card.LabelAutoCompleteAdapter; import it.niedermann.nextcloud.deck.ui.card.UserAutoCompleteAdapter; import it.niedermann.nextcloud.deck.util.ColorUtil; -import it.niedermann.nextcloud.deck.util.DimensionUtil; import it.niedermann.nextcloud.deck.util.MarkDownUtil; import it.niedermann.nextcloud.deck.util.ViewUtil; +import static android.text.format.DateFormat.getDateFormat; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToEditText; -import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID; -import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_BOARD_ID; -import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_CAN_EDIT; -import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ID; -import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID; +import static it.niedermann.nextcloud.deck.util.DimensionUtil.dpToPx; public class CardDetailsFragment extends BrandedFragment implements OnDateSetListener, OnTimeSetListener { private FragmentCardEditTabDetailsBinding binding; - - private boolean canEdit = false; - private FullCard fullCard; + private EditCardViewModel viewModel; private SyncManager syncManager; private DateFormat dateFormat; private DateFormat dueTime = new SimpleDateFormat("HH:mm", Locale.ROOT); private String baseUrl; + @Px private int avatarSize; private LinearLayout.LayoutParams avatarLayoutParams; - private CardDetailsListener cardDetailsListener; private AppCompatActivity activity; - public CardDetailsFragment() { - } - @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - if (context instanceof CardDetailsListener) { - this.cardDetailsListener = (CardDetailsListener) context; - } else { - throw new ClassCastException("Caller must implement " + CardDetailsListener.class.getCanonicalName()); - } if (context instanceof AppCompatActivity) { this.activity = (AppCompatActivity) context; } else { @@ -95,17 +83,8 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } } - public static CardDetailsFragment newInstance(long accountId, long localId, long boardId, boolean canEdit) { - Bundle bundle = new Bundle(); - bundle.putLong(BUNDLE_KEY_ACCOUNT_ID, accountId); - bundle.putLong(BUNDLE_KEY_BOARD_ID, boardId); - bundle.putLong(BUNDLE_KEY_LOCAL_ID, localId); - bundle.putBoolean(BUNDLE_KEY_CAN_EDIT, canEdit); - - CardDetailsFragment fragment = new CardDetailsFragment(); - fragment.setArguments(bundle); - - return fragment; + public static Fragment newInstance() { + return new CardDetailsFragment(); } @Override @@ -113,53 +92,58 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis ViewGroup container, Bundle savedInstanceState) { binding = FragmentCardEditTabDetailsBinding.inflate(inflater, container, false); - dateFormat = android.text.format.DateFormat.getDateFormat(activity); - - Bundle args = getArguments(); - if (args != null) { - long accountId = args.getLong(BUNDLE_KEY_ACCOUNT_ID); - long localId = args.getLong(BUNDLE_KEY_LOCAL_ID); - long boardId = args.getLong(BUNDLE_KEY_BOARD_ID); - if (args.containsKey(BUNDLE_KEY_CAN_EDIT)) { - this.canEdit = args.getBoolean(BUNDLE_KEY_CAN_EDIT); - } + dateFormat = getDateFormat(activity); - syncManager = new SyncManager(activity); - - if (NO_LOCAL_ID.equals(localId)) { - fullCard = new FullCard(); - fullCard.setCard(new Card()); - setupView(accountId, boardId, canEdit); - } else { - observeOnce(syncManager.getCardByLocalId(accountId, localId), CardDetailsFragment.this, (next) -> { - fullCard = next; - binding.description.setText(fullCard.getCard().getDescription()); - setupView(accountId, boardId, canEdit); - }); - } - } + viewModel = new ViewModelProvider(activity).get(EditCardViewModel.class); + syncManager = new SyncManager(activity); - avatarSize = DimensionUtil.dpToPx(requireContext(), R.dimen.avatar_size); + avatarSize = dpToPx(requireContext(), R.dimen.avatar_size); avatarLayoutParams = new LinearLayout.LayoutParams(avatarSize, avatarSize); - avatarLayoutParams.setMargins(0, 0, requireContext().getResources().getDimensionPixelSize(R.dimen.spacer_1x), 0); + avatarLayoutParams.setMargins(0, 0, dpToPx(requireContext(), R.dimen.spacer_1x), 0); try { baseUrl = syncManager.getServerUrl(); } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) { DeckLog.logError(e); } - return binding.getRoot(); - } - private void setupView(long accountId, long boardId, boolean canEdit) { - setupPeople(accountId, boardId); - setupLabels(accountId, boardId, canEdit); + setupPeople(); + setupLabels(); setupDueDate(); setupDescription(); + binding.description.setText(viewModel.getFullCard().getCard().getDescription()); + + return binding.getRoot(); + } + + + @Override + public void onResume() { + super.onResume(); + + // https://github.com/wdullaer/MaterialDateTimePicker#why-are-my-callbacks-lost-when-the-device-changes-orientation + final DatePickerDialog dpd = (DatePickerDialog) getChildFragmentManager().findFragmentByTag(BrandedDatePickerDialog.class.getCanonicalName()); + final TimePickerDialog tpd = (TimePickerDialog) getChildFragmentManager().findFragmentByTag(BrandedTimePickerDialog.class.getCanonicalName()); + if (tpd != null) tpd.setOnTimeSetListener(this); + if (dpd != null) dpd.setOnDateSetListener(this); + } + + @Override + public void onPause() { + super.onPause(); + } + + @Override + public void applyBrand(int mainColor, int textColor) { + applyBrandToEditText(mainColor, textColor, binding.labels); + applyBrandToEditText(mainColor, textColor, binding.dueDateDate); + applyBrandToEditText(mainColor, textColor, binding.dueDateTime); + applyBrandToEditText(mainColor, textColor, binding.people); + applyBrandToEditText(mainColor, textColor, binding.description); } private void setupDescription() { - if (canEdit) { + if (viewModel.canEdit()) { MarkdownProcessor markdownProcessor = new MarkdownProcessor(requireContext()); markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(binding.description.getContext()).build()); markdownProcessor.factory(EditFactory.create()); @@ -167,9 +151,8 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis binding.description.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - if (fullCard != null) { - cardDetailsListener.onDescriptionChanged(binding.description.getText().toString()); - fullCard.getCard().setDescription(binding.description.getText().toString()); + if (viewModel.getFullCard() != null) { + viewModel.getFullCard().getCard().setDescription(binding.description.getText().toString()); } } @@ -225,9 +208,9 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } private void setupDueDate() { - if (this.fullCard.getCard().getDueDate() != null) { - binding.dueDateDate.setText(dateFormat.format(this.fullCard.getCard().getDueDate())); - binding.dueDateTime.setText(dueTime.format(this.fullCard.getCard().getDueDate())); + if (this.viewModel.getFullCard().getCard().getDueDate() != null) { + binding.dueDateDate.setText(dateFormat.format(this.viewModel.getFullCard().getCard().getDueDate())); + binding.dueDateTime.setText(dueTime.format(this.viewModel.getFullCard().getCard().getDueDate())); binding.clearDueDate.setVisibility(View.VISIBLE); } else { binding.clearDueDate.setVisibility(View.GONE); @@ -235,29 +218,28 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis binding.dueDateTime.setText(null); } - if (canEdit) { + if (viewModel.canEdit()) { binding.dueDateDate.setOnClickListener(v -> { - if (fullCard != null && fullCard.getCard() != null) { - createDatePickerDialogFromDate(this, fullCard.getCard().getDueDate()).show(getChildFragmentManager(), BrandedDatePickerDialog.class.getCanonicalName()); + if (viewModel.getFullCard() != null && viewModel.getFullCard().getCard() != null) { + createDatePickerDialogFromDate(this, viewModel.getFullCard().getCard().getDueDate()).show(getChildFragmentManager(), BrandedDatePickerDialog.class.getCanonicalName()); } else { createDatePickerDialogFromDate(this, null).show(getChildFragmentManager(), BrandedDatePickerDialog.class.getCanonicalName()); } }); binding.dueDateTime.setOnClickListener(v -> { - if (fullCard != null && fullCard.getCard() != null) { - createTimePickerDialogFromDate(this, fullCard.getCard().getDueDate()).show(getChildFragmentManager(), BrandedTimePickerDialog.class.getCanonicalName()); + if (viewModel.getFullCard() != null && viewModel.getFullCard().getCard() != null) { + createTimePickerDialogFromDate(this, viewModel.getFullCard().getCard().getDueDate()).show(getChildFragmentManager(), BrandedTimePickerDialog.class.getCanonicalName()); } else { createTimePickerDialogFromDate(this, null).show(getChildFragmentManager(), BrandedTimePickerDialog.class.getCanonicalName()); } }); binding.clearDueDate.setOnClickListener(v -> { - cardDetailsListener.onDueDateChanged(null); binding.dueDateDate.setText(null); binding.dueDateTime.setText(null); - fullCard.getCard().setDueDate(null); + viewModel.getFullCard().getCard().setDueDate(null); binding.clearDueDate.setVisibility(View.GONE); }); } else { @@ -267,10 +249,12 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } } - private void setupLabels(long accountId, long boardId, boolean canEdit) { + private void setupLabels() { + long accountId = viewModel.getAccountId(); + long boardId = viewModel.getBoardId(); binding.labelsGroup.removeAllViews(); - if (canEdit) { - Long localCardId = fullCard.getCard().getLocalId(); + if (viewModel.canEdit()) { + Long localCardId = viewModel.getFullCard().getCard().getLocalId(); localCardId = localCardId == null ? -1 : localCardId; binding.labels.setAdapter(new LabelAutoCompleteAdapter(activity, accountId, boardId, localCardId)); binding.labels.setOnItemClickListener((adapterView, view, position, id) -> { @@ -283,13 +267,13 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis observeOnce(syncManager.createLabel(accountId, newLabel, boardId), CardDetailsFragment.this, createdLabel -> { newLabel.setLocalId(createdLabel.getLocalId()); ((LabelAutoCompleteAdapter) binding.labels.getAdapter()).exclude(createdLabel); - cardDetailsListener.onLabelAdded(createdLabel); + viewModel.getFullCard().getLabels().add(createdLabel); binding.labelsGroup.addView(createChipFromLabel(newLabel)); binding.labelsGroup.setVisibility(View.VISIBLE); }); } else { ((LabelAutoCompleteAdapter) binding.labels.getAdapter()).exclude(label); - cardDetailsListener.onLabelAdded(label); + viewModel.getFullCard().getLabels().add(label); binding.labelsGroup.addView(createChipFromLabel(label)); binding.labelsGroup.setVisibility(View.VISIBLE); } @@ -299,8 +283,8 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } else { binding.labels.setEnabled(false); } - if (fullCard.getLabels() != null && fullCard.getLabels().size() > 0) { - for (Label label : fullCard.getLabels()) { + if (viewModel.getFullCard().getLabels() != null && viewModel.getFullCard().getLabels().size() > 0) { + for (Label label : viewModel.getFullCard().getLabels()) { binding.labelsGroup.addView(createChipFromLabel(label)); } binding.labelsGroup.setVisibility(View.VISIBLE); @@ -313,12 +297,12 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis private Chip createChipFromLabel(Label label) { final Chip chip = new Chip(activity); chip.setText(label.getTitle()); - if (canEdit) { + if (viewModel.canEdit()) { chip.setCloseIcon(getResources().getDrawable(R.drawable.ic_close_circle_grey600)); chip.setCloseIconVisible(true); chip.setOnCloseIconClickListener(v -> { binding.labelsGroup.removeView(chip); - cardDetailsListener.onLabelRemoved(label); + viewModel.getFullCard().getLabels().remove(label); ((LabelAutoCompleteAdapter) binding.labels.getAdapter()).exclude(label); }); } @@ -338,14 +322,14 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis return chip; } - private void setupPeople(long accountId, long boardId) { - if (canEdit) { - Long localCardId = fullCard.getCard().getLocalId(); + private void setupPeople() { + if (viewModel.canEdit()) { + Long localCardId = viewModel.getFullCard().getCard().getLocalId(); localCardId = localCardId == null ? -1 : localCardId; - binding.people.setAdapter(new UserAutoCompleteAdapter(activity, accountId, boardId, localCardId)); + binding.people.setAdapter(new UserAutoCompleteAdapter(activity, viewModel.getAccountId(), viewModel.getBoardId(), localCardId)); binding.people.setOnItemClickListener((adapterView, view, position, id) -> { User user = (User) adapterView.getItemAtPosition(position); - cardDetailsListener.onUserAdded(user); + viewModel.getFullCard().getAssignedUsers().add(user); ((UserAutoCompleteAdapter) binding.people.getAdapter()).exclude(user); if (baseUrl != null) { addAvatar(baseUrl, user); @@ -353,10 +337,10 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis binding.people.setText(""); }); - if (this.fullCard.getAssignedUsers() != null) { + if (this.viewModel.getFullCard().getAssignedUsers() != null) { binding.peopleList.removeAllViews(); if (baseUrl != null) { - for (User user : this.fullCard.getAssignedUsers()) { + for (User user : this.viewModel.getFullCard().getAssignedUsers()) { addAvatar(baseUrl, user); } } @@ -369,16 +353,16 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis private void addAvatar(String baseUrl, User user) { ImageView avatar = new ImageView(activity); avatar.setLayoutParams(avatarLayoutParams); - if (canEdit) { + if (viewModel.canEdit()) { avatar.setOnClickListener(v -> { - cardDetailsListener.onUserRemoved(user); + viewModel.getFullCard().getAssignedUsers().remove(user); binding.peopleList.removeView(avatar); ((UserAutoCompleteAdapter) binding.people.getAdapter()).include(user); Snackbar.make( requireView(), getString(R.string.unassigned_user, user.getDisplayname()), Snackbar.LENGTH_LONG) .setAction(R.string.simple_undo, v1 -> { - cardDetailsListener.onUserAdded(user); + viewModel.getFullCard().getAssignedUsers().add(user); ((UserAutoCompleteAdapter) binding.people.getAdapter()).exclude(user); addAvatar(baseUrl, user); }).show(); @@ -390,50 +374,24 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } @Override - public void onResume() { - super.onResume(); - - // https://github.com/wdullaer/MaterialDateTimePicker#why-are-my-callbacks-lost-when-the-device-changes-orientation - final DatePickerDialog dpd = (DatePickerDialog) getChildFragmentManager().findFragmentByTag(BrandedDatePickerDialog.class.getCanonicalName()); - final TimePickerDialog tpd = (TimePickerDialog) getChildFragmentManager().findFragmentByTag(BrandedTimePickerDialog.class.getCanonicalName()); - if (tpd != null) tpd.setOnTimeSetListener(this); - if (dpd != null) dpd.setOnDateSetListener(this); - } - - @Override - public void onPause() { - super.onPause(); - } - - @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToEditText(mainColor, textColor, binding.labels); - applyBrandToEditText(mainColor, textColor, binding.dueDateDate); - applyBrandToEditText(mainColor, textColor, binding.dueDateTime); - applyBrandToEditText(mainColor, textColor, binding.people); - applyBrandToEditText(mainColor, textColor, binding.description); - } - - @Override public void onDateSet(com.wdullaer.materialdatetimepicker.date.DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) { Calendar c = Calendar.getInstance(); int hourOfDay; int minute; if (binding.dueDateTime.getText() != null && binding.dueDateTime.length() > 0) { - hourOfDay = this.fullCard.getCard().getDueDate().getHours(); - minute = this.fullCard.getCard().getDueDate().getMinutes(); + hourOfDay = this.viewModel.getFullCard().getCard().getDueDate().getHours(); + minute = this.viewModel.getFullCard().getCard().getDueDate().getMinutes(); } else { hourOfDay = 0; minute = 0; } c.set(year, monthOfYear, dayOfMonth, hourOfDay, minute); - this.fullCard.getCard().setDueDate(c.getTime()); + this.viewModel.getFullCard().getCard().setDueDate(c.getTime()); binding.dueDateDate.setText(dateFormat.format(c.getTime())); - cardDetailsListener.onDueDateChanged(fullCard.card.getDueDate()); - if (this.fullCard.getCard().getDueDate() == null || this.fullCard.getCard().getDueDate().getTime() == 0) { + if (this.viewModel.getFullCard().getCard().getDueDate() == null || this.viewModel.getFullCard().getCard().getDueDate().getTime() == 0) { binding.clearDueDate.setVisibility(View.GONE); } else { binding.clearDueDate.setVisibility(View.VISIBLE); @@ -442,14 +400,13 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis @Override public void onTimeSet(com.wdullaer.materialdatetimepicker.time.TimePickerDialog view, int hourOfDay, int minute, int second) { - if (this.fullCard.getCard().getDueDate() == null) { - this.fullCard.getCard().setDueDate(new Date()); + if (this.viewModel.getFullCard().getCard().getDueDate() == null) { + this.viewModel.getFullCard().getCard().setDueDate(new Date()); } - this.fullCard.getCard().getDueDate().setHours(hourOfDay); - this.fullCard.getCard().getDueDate().setMinutes(minute); - binding.dueDateTime.setText(dueTime.format(this.fullCard.getCard().getDueDate().getTime())); - cardDetailsListener.onDueDateChanged(fullCard.card.getDueDate()); - if (this.fullCard.getCard().getDueDate() == null || this.fullCard.getCard().getDueDate().getTime() == 0) { + this.viewModel.getFullCard().getCard().getDueDate().setHours(hourOfDay); + this.viewModel.getFullCard().getCard().getDueDate().setMinutes(minute); + binding.dueDateTime.setText(dueTime.format(this.viewModel.getFullCard().getCard().getDueDate().getTime())); + if (this.viewModel.getFullCard().getCard().getDueDate() == null || this.viewModel.getFullCard().getCard().getDueDate().getTime() == 0) { binding.clearDueDate.setVisibility(View.GONE); } else { binding.clearDueDate.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/DimensionUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/DimensionUtil.java index 19c01a06f..6ff22eace 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/util/DimensionUtil.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/DimensionUtil.java @@ -4,11 +4,13 @@ import android.content.Context; import androidx.annotation.DimenRes; import androidx.annotation.NonNull; +import androidx.annotation.Px; public final class DimensionUtil { private DimensionUtil() { } + @Px public static int dpToPx(@NonNull Context context, @DimenRes int resource) { return context.getResources().getDimensionPixelSize(resource); } |