diff options
author | desperateCoder <echotodevnull@gmail.com> | 2020-12-10 18:37:16 +0300 |
---|---|---|
committer | desperateCoder <echotodevnull@gmail.com> | 2020-12-10 18:37:16 +0300 |
commit | 044bdc5ae949890284bccf419c155ae817641ec1 (patch) | |
tree | a5bac46a4b0e84cc41a366599077cc7bf669792e /app/src/main | |
parent | 191e16973a362ac2b488d33e634cee7117d85635 (diff) | |
parent | 92bf6199255f7abe472e84c683c7acb7d1a8c582 (diff) |
merged origin/master into branch
Diffstat (limited to 'app/src/main')
24 files changed, 151 insertions, 204 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java index 3ded31bb7..1ba1415b2 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java @@ -1,6 +1,7 @@ package it.niedermann.nextcloud.deck.ui; import android.annotation.SuppressLint; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteConstraintException; @@ -251,4 +252,8 @@ public class ImportAccountActivity extends AppCompatActivity { editor.putBoolean(prefKeyWifiOnly, originalWifiOnlyValue); editor.apply(); } + + public static Intent createIntent(@NonNull Context context) { + return new Intent(context, ImportAccountActivity.class); + } }
\ No newline at end of file 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 d7e726a7d..06fa3186b 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 @@ -132,9 +132,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener private FilterViewModel filterViewModel; private PickStackViewModel pickStackViewModel; - protected static final int ACTIVITY_ABOUT = 1; protected static final int ACTIVITY_SETTINGS = 2; - public static final int ACTIVITY_MANAGE_ACCOUNTS = 4; @NonNull protected List<Account> accountsList = new ArrayList<>(); @@ -158,8 +156,6 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener private boolean firstAccountAdded = false; private ConnectivityManager.NetworkCallback networkCallback; - private String accountAlreadyAdded; - private String urlFragmentUpdateDeck; private String addList; private String addBoard; @Nullable @@ -186,8 +182,6 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener addList = getString(R.string.add_list); addBoard = getString(R.string.add_board); - accountAlreadyAdded = getString(R.string.account_already_added); - urlFragmentUpdateDeck = getString(R.string.url_fragment_update_deck); setSupportActionBar(binding.toolbar); @@ -202,7 +196,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener if (hasAccounts) { return mainViewModel.readAccounts(); } else { - startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); + startActivityForResult(ImportAccountActivity.createIntent(this), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); return null; } }).observe(this, (List<Account> accounts) -> { @@ -300,7 +294,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener Glide .with(binding.accountSwitcher.getContext()) - .load(currentAccount.getAvatarUrl(64)) + .load(currentAccount.getAvatarUrl(binding.accountSwitcher.getWidth())) .placeholder(R.drawable.ic_baseline_account_circle_24) .error(R.drawable.ic_baseline_account_circle_24) .apply(RequestOptions.circleCropTransform()) @@ -314,7 +308,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener binding.infoBoxVersionNotSupportedText.setText(getString(R.string.info_box_version_not_supported, mainViewModel.getCurrentAccount().getServerDeckVersion(), Version.minimumSupported(this).getOriginalVersion())); binding.infoBoxVersionNotSupportedText.setOnClickListener((v) -> { Intent openURL = new Intent(Intent.ACTION_VIEW); - openURL.setData(Uri.parse(mainViewModel.getCurrentAccount().getUrl() + urlFragmentUpdateDeck)); + openURL.setData(Uri.parse(mainViewModel.getCurrentAccount().getUrl() + getString(R.string.url_fragment_update_deck))); startActivity(openURL); }); binding.infoBoxVersionNotSupported.setVisibility(View.VISIBLE); @@ -648,10 +642,10 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case MENU_ID_ABOUT: - startActivityForResult(AboutActivity.createIntent(this, mainViewModel.getCurrentAccount()), MainActivity.ACTIVITY_ABOUT); + startActivity(AboutActivity.createIntent(this, mainViewModel.getCurrentAccount())); break; case MENU_ID_SETTINGS: - startActivityForResult(new Intent(this, SettingsActivity.class), MainActivity.ACTIVITY_SETTINGS); + startActivityForResult(SettingsActivity.createIntent(this), MainActivity.ACTIVITY_SETTINGS); break; case MENU_ID_ADD_BOARD: EditBoardDialogFragment.newInstance().show(getSupportFragmentManager(), addBoard); @@ -818,7 +812,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener .setNegativeButton(R.string.simple_discard, null) .setPositiveButton(R.string.simple_update, (dialog, whichButton) -> { final Intent openURL = new Intent(Intent.ACTION_VIEW); - openURL.setData(Uri.parse(createdAccount.getUrl() + urlFragmentUpdateDeck)); + openURL.setData(Uri.parse(createdAccount.getUrl() + getString(R.string.url_fragment_update_deck))); startActivity(openURL); finish(); }).show()); @@ -855,7 +849,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener final Throwable error = accountLiveData.getError(); if (error instanceof SQLiteConstraintException) { DeckLog.warn("Account already added"); - BrandedSnackbar.make(binding.coordinatorLayout, accountAlreadyAdded, Snackbar.LENGTH_LONG).show(); + BrandedSnackbar.make(binding.coordinatorLayout, R.string.account_already_added, Snackbar.LENGTH_LONG).show(); } else { ExceptionDialogFragment.newInstance(error, createdAccount).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); } 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 2339a8783..5103cf3c1 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 @@ -1,6 +1,5 @@ package it.niedermann.nextcloud.deck.ui; -import android.content.Intent; import android.content.res.ColorStateList; import android.graphics.Color; import android.os.Bundle; @@ -64,7 +63,7 @@ public abstract class PickStackActivity extends AppCompatActivity implements Bra if (hasAccounts) { return viewModel.readAccounts(); } else { - startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); + startActivityForResult(ImportAccountActivity.createIntent(this), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); return null; } }).observe(this, (List<Account> accounts) -> { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java index bf3734b72..d931d5c92 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java @@ -42,8 +42,6 @@ public class AboutActivity extends BrandedActivity { setSupportActionBar(binding.toolbar); binding.viewPager.setAdapter(new TabsPagerAdapter(getSupportFragmentManager(), getLifecycle(), (Account) getIntent().getSerializableExtra(BUNDLE_KEY_ACCOUNT))); new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> tab.setText(tabTitles[position])).attach(); - - setResult(RESULT_OK); } private static class TabsPagerAdapter extends FragmentStateAdapter { 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 744498c4a..8a70cf12d 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.Intent; import android.net.Uri; import android.os.Bundle; @@ -26,7 +25,6 @@ import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment; import it.niedermann.nextcloud.deck.ui.manageaccounts.ManageAccountsActivity; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; -import static it.niedermann.nextcloud.deck.ui.MainActivity.ACTIVITY_MANAGE_ACCOUNTS; public class AccountSwitcherDialog extends BrandedDialogFragment { @@ -80,7 +78,7 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { }); binding.manageAccounts.setOnClickListener((v) -> { - requireActivity().startActivityForResult(new Intent(requireContext(), ManageAccountsActivity.class), ACTIVITY_MANAGE_ACCOUNTS); + requireActivity().startActivity(ManageAccountsActivity.createIntent(requireContext())); dismiss(); }); 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 2e1ff5e06..9f170af1e 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,6 +26,7 @@ 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.adapters.db.util.WrappedLiveData; import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; @@ -76,12 +77,13 @@ public class EditActivity extends BrandedActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler(this)); + binding = ActivityEditBinding.inflate(getLayoutInflater()); + viewModel = new ViewModelProvider(this).get(EditCardViewModel.class); + setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); - viewModel = new ViewModelProvider(this).get(EditCardViewModel.class); - loadDataFromIntent(); } @@ -169,16 +171,15 @@ public class EditActivity extends BrandedActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_card_save) { - saveAndRun(super::finish); + saveAndFinish(); } return super.onOptionsItemSelected(item); } /** - * Tries to save the current {@link FullCard} from the {@link EditCardViewModel} and then runs the given {@link Runnable} - * @param runnable + * Tries to save the current {@link FullCard} from the {@link EditCardViewModel} and then finishes this activity. */ - private void saveAndRun(@NonNull Runnable runnable) { + private void saveAndFinish() { if (!viewModel.isPendingCreation()) { viewModel.setPendingCreation(true); final String title = viewModel.getFullCard().getCard().getTitle(); @@ -195,11 +196,13 @@ public class EditActivity extends BrandedActivity { .setOnDismissListener(dialog -> viewModel.setPendingCreation(false)) .show(); } else { - if (viewModel.isCreateMode()) { - observeOnce(viewModel.createFullCard(viewModel.getAccount().getId(), viewModel.getBoardId(), viewModel.getFullCard().getCard().getStackId(), viewModel.getFullCard()), EditActivity.this, (card) -> runnable.run()); - } else { - observeOnce(viewModel.updateCard(viewModel.getFullCard()), EditActivity.this, (card) -> runnable.run()); - } + final WrappedLiveData<FullCard> save$ = viewModel.saveCard(); + save$.observe(this, (fullCard) -> { + if (save$.hasError()) { + DeckLog.logError(save$.getError()); + } + }); + super.finish(); } } } @@ -272,7 +275,7 @@ public class EditActivity extends BrandedActivity { new BrandedAlertDialogBuilder(this) .setTitle(R.string.simple_save) .setMessage(R.string.do_you_want_to_save_your_changes) - .setPositiveButton(R.string.simple_save, (dialog, whichButton) -> saveAndRun(super::finish)) + .setPositiveButton(R.string.simple_save, (dialog, whichButton) -> saveAndFinish()) .setNegativeButton(R.string.simple_discard, (dialog, whichButton) -> super.finish()).show(); } else { super.finish(); 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 c754d0800..697566f84 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 @@ -138,12 +138,13 @@ public class EditCardViewModel extends AndroidViewModel { 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); + /** + * Saves the current {@link #fullCard}. If it is a new card, it will be created, otherwise it will be updated. + */ + public WrappedLiveData<FullCard> saveCard() { + return isCreateMode() + ? syncManager.createFullCard(getAccount().getId(), getBoardId(), getFullCard().getCard().getStackId(), getFullCard()) + : syncManager.updateCard(getFullCard()); } public LiveData<List<Activity>> syncActivitiesForCard(@NonNull Card card) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java index 34d2eb3f3..b18f35de0 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/assignee/CardAssigneeDialog.java @@ -24,10 +24,13 @@ import it.niedermann.nextcloud.deck.model.User; import it.niedermann.nextcloud.deck.ui.branding.BrandedDeleteAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment; import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; +import it.niedermann.nextcloud.deck.ui.card.attachments.previewdialog.PreviewDialog; import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; -@Deprecated +/** + * TODO maybe this can be merged with {@link PreviewDialog} + */ public class CardAssigneeDialog extends BrandedDialogFragment { private static final String KEY_USER = "user"; 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 3fd536aa6..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 @@ -34,7 +34,6 @@ import static android.view.View.VISIBLE; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToEditText; import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToFAB; -import static it.niedermann.nextcloud.deck.util.ViewUtil.setupMentions; public class CardCommentsFragment extends BrandedFragment implements CommentEditedListener, CommentDeletedListener, CommentSelectAsReplyListener { @@ -78,9 +77,9 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit if (comment == null) { binding.replyComment.setVisibility(GONE); } else { - binding.replyCommentText.setText(comment.getComment().getMessage()); + binding.replyCommentText.setMarkdownString(comment.getComment().getMessage()); binding.replyComment.setVisibility(VISIBLE); - setupMentions(mainViewModel.getAccount(), comment.getComment().getMentions(), binding.replyCommentText); +// setupMentions(mainViewModel.getAccount(), comment.getComment().getMentions(), binding.replyCommentText); } }); commentsViewModel.getFullCommentsForLocalCardId(mainViewModel.getFullCard().getLocalId()).observe(getViewLifecycleOwner(), diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java index 3e540c95e..df44e58ef 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/ItemCommentViewHolder.java @@ -14,6 +14,8 @@ import androidx.recyclerview.widget.RecyclerView; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; +import java.util.HashMap; +import java.util.Map; import it.niedermann.android.util.ClipboardUtil; import it.niedermann.android.util.DimensionUtil; @@ -21,12 +23,11 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ItemCommentBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.enums.DBStatus; +import it.niedermann.nextcloud.deck.model.ocs.comment.Mention; import it.niedermann.nextcloud.deck.model.ocs.comment.full.FullDeckComment; import it.niedermann.nextcloud.deck.util.DateUtil; import it.niedermann.nextcloud.deck.util.ViewUtil; -import static it.niedermann.nextcloud.deck.util.ViewUtil.setupMentions; - public class ItemCommentViewHolder extends RecyclerView.ViewHolder { private final ItemCommentBinding binding; private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM); @@ -39,11 +40,15 @@ public class ItemCommentViewHolder extends RecyclerView.ViewHolder { public void bind(@NonNull FullDeckComment comment, @NonNull Account account, @ColorInt int mainColor, @NonNull MenuInflater inflater, @NonNull CommentDeletedListener deletedListener, @NonNull CommentSelectAsReplyListener selectAsReplyListener, @NonNull FragmentManager fragmentManager) { ViewUtil.addAvatar(binding.avatar, account.getUrl(), comment.getComment().getActorId(), DimensionUtil.INSTANCE.dpToPx(binding.avatar.getContext(), R.dimen.icon_size_details), R.drawable.ic_person_grey600_24dp); - binding.message.setText(comment.getComment().getMessage()); + final Map<String, String> mentions = new HashMap<>(comment.getComment().getMentions().size()); + for (Mention mention : comment.getComment().getMentions()) { + mentions.put(mention.getMentionId(), mention.getMentionDisplayName()); + } + binding.message.setMarkdownString(comment.getComment().getMessage(), mentions); binding.actorDisplayName.setText(comment.getComment().getActorDisplayName()); binding.creationDateTime.setText(DateUtil.getRelativeDateTimeString(binding.creationDateTime.getContext(), comment.getComment().getCreationDateTime().toEpochMilli())); - itemView.setOnClickListener(View::showContextMenu); + itemView.setOnClickListener(View::showContextMenu); itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> { inflater.inflate(R.menu.comment_menu, menu); menu.findItem(android.R.id.copy).setOnMenuItemClickListener(item -> ClipboardUtil.INSTANCE.copyToClipboard(itemView.getContext(), comment.getComment().getMessage())); @@ -72,12 +77,10 @@ public class ItemCommentViewHolder extends RecyclerView.ViewHolder { } }); + TooltipCompat.setTooltipText(binding.creationDateTime, comment.getComment().getCreationDateTime().atZone(ZoneId.systemDefault()).format(dateFormatter)); DrawableCompat.setTint(binding.notSyncedYet.getDrawable(), mainColor); binding.notSyncedYet.setVisibility(DBStatus.LOCAL_EDITED.equals(comment.getStatusEnum()) ? View.VISIBLE : View.GONE); - TooltipCompat.setTooltipText(binding.creationDateTime, comment.getComment().getCreationDateTime().atZone(ZoneId.systemDefault()).format(dateFormatter)); - setupMentions(account, comment.getComment().getMentions(), binding.message); - if (comment.getParent() == null) { binding.parentContainer.setVisibility(View.GONE); } else { 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 2c697de08..9db572867 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 @@ -4,9 +4,7 @@ import android.content.Context; import android.content.res.ColorStateList; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.text.Editable; import android.text.TextUtils; -import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -28,8 +26,6 @@ import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; import com.wdullaer.materialdatetimepicker.date.DatePickerDialog.OnDateSetListener; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog.OnTimeSetListener; -import com.yydcdut.markdown.MarkdownProcessor; -import com.yydcdut.markdown.syntax.edit.EditFactory; import java.time.Instant; import java.time.LocalDate; @@ -46,6 +42,7 @@ 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.model.full.FullCard; 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; @@ -57,7 +54,6 @@ import it.niedermann.nextcloud.deck.ui.card.UserAutoCompleteAdapter; import it.niedermann.nextcloud.deck.ui.card.assignee.CardAssigneeDialog; import it.niedermann.nextcloud.deck.ui.card.assignee.CardAssigneeListener; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; -import it.niedermann.nextcloud.deck.util.MarkDownUtil; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -72,6 +68,7 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT); private AppCompatActivity activity; + boolean editorActive = true; @Override public void onAttach(@NonNull Context context) { @@ -110,7 +107,6 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis setupDueDate(); setupDescription(); setupProjects(); - binding.description.setText(viewModel.getFullCard().getCard().getDescription()); return binding.getRoot(); } @@ -137,35 +133,41 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis applyBrandToEditText(mainColor, binding.dueDateDate); applyBrandToEditText(mainColor, binding.dueDateTime); applyBrandToEditText(mainColor, binding.people); - applyBrandToEditText(mainColor, binding.description); } private void setupDescription() { if (viewModel.canEdit()) { - MarkdownProcessor markdownProcessor = new MarkdownProcessor(requireContext()); - markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(binding.description.getContext()).build()); - markdownProcessor.factory(EditFactory.create()); - markdownProcessor.live(binding.description); - binding.description.addTextChangedListener(new TextWatcher() { - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - if (viewModel.getFullCard() != null) { - viewModel.getFullCard().getCard().setDescription(binding.description.getText().toString()); - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // Nothing to do + binding.descriptionBar.setOnClickListener((v) -> binding.descriptionEditor.requestFocus()); + binding.descriptionToggle.setOnClickListener((v) -> { + editorActive = !editorActive; + if (editorActive) { + binding.descriptionBar.setOnClickListener((view) -> binding.descriptionEditor.requestFocus()); + binding.descriptionEditor.setVisibility(VISIBLE); + binding.descriptionViewer.setVisibility(GONE); + binding.descriptionToggle.setImageResource(R.drawable.ic_baseline_eye_24); + } else { + binding.descriptionBar.setOnClickListener(null); + binding.descriptionEditor.setVisibility(GONE); + binding.descriptionViewer.setVisibility(VISIBLE); + binding.descriptionToggle.setImageResource(R.drawable.ic_edit_grey600_24dp); } - - @Override - public void afterTextChanged(Editable s) { - // Nothing to do + }); + binding.descriptionEditor.setMarkdownString(viewModel.getFullCard().getCard().getDescription()); + binding.descriptionEditor.getMarkdownString().observe(getViewLifecycleOwner(), (newText) -> { + if (viewModel.getFullCard() != null) { + viewModel.getFullCard().getCard().setDescription(newText == null ? "" : newText.toString()); + binding.descriptionViewer.setMarkdownString(viewModel.getFullCard().getCard().getDescription()); + } else { + DeckLog.logError(new IllegalStateException(FullCard.class.getSimpleName() + " was empty when trying to setup description")); } + binding.descriptionToggle.setVisibility(TextUtils.isEmpty(newText) ? GONE : VISIBLE); }); } else { - binding.description.setEnabled(false); + binding.descriptionEditor.setEnabled(false); + binding.descriptionEditor.setVisibility(VISIBLE); + binding.descriptionViewer.setEnabled(false); + binding.descriptionViewer.setVisibility(GONE); + binding.descriptionViewer.setMarkdownString(viewModel.getFullCard().getCard().getDescription()); } } 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 8aa45e39a..aec258d59 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 @@ -1,8 +1,11 @@ package it.niedermann.nextcloud.deck.ui.manageaccounts; +import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.ViewModelProvider; @@ -51,7 +54,6 @@ public class ManageAccountsActivity extends AppCompatActivity { viewModel.readAccounts().observe(this, (localAccounts -> { if (localAccounts.size() == 0) { Log.i(TAG, "No accounts, finishing " + ManageAccountsActivity.class.getSimpleName()); - setResult(AppCompatActivity.RESULT_FIRST_USER); finish(); } else { adapter.setAccounts(localAccounts); @@ -64,4 +66,8 @@ public class ManageAccountsActivity extends AppCompatActivity { public void onBackPressed() { onSupportNavigateUp(); } + + public static Intent createIntent(@NonNull Context context) { + return new Intent(context, ManageAccountsActivity.class); + } } 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 d65971cf4..6408f6b64 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 @@ -1,7 +1,6 @@ package it.niedermann.nextcloud.deck.ui.pickstack; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -142,7 +141,7 @@ public class PickStackFragment extends Fragment { if (hasAccounts) { return viewModel.readAccounts(); } else { - startActivityForResult(new Intent(requireActivity(), ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); + startActivityForResult(ImportAccountActivity.createIntent(requireContext()), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); return null; } }).observe(getViewLifecycleOwner(), (List<Account> accounts) -> { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java index f537c9fb4..9534b51b4 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java @@ -50,7 +50,7 @@ public class AccountAdapter extends AbstractAdapter<Account> { } Glide.with(getContext()) - .load(new SingleSignOnUrl(item.getName(), item.getAvatarUrl(DimensionUtil.INSTANCE.dpToPx(binding.avatar.getContext(), R.dimen.icon_size_details)))) + .load(new SingleSignOnUrl(item.getName(), item.getAvatarUrl(DimensionUtil.INSTANCE.dpToPx(binding.avatar.getContext(), R.dimen.avatar_size)))) .placeholder(R.drawable.ic_baseline_account_circle_24) .error(R.drawable.ic_baseline_account_circle_24) .apply(RequestOptions.circleCropTransform()) diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java index 6f5a9a7e8..6440ba971 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java @@ -1,7 +1,10 @@ package it.niedermann.nextcloud.deck.ui.settings; +import android.content.Context; +import android.content.Intent; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import it.niedermann.nextcloud.deck.R; @@ -11,14 +14,12 @@ import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; public class SettingsActivity extends BrandedActivity { - private ActivitySettingsBinding binding; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler(this)); - binding = ActivitySettingsBinding.inflate(getLayoutInflater()); + final ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); @@ -40,4 +41,9 @@ public class SettingsActivity extends BrandedActivity { public void applyBrand(int mainColor) { // Nothing to do... } + + @NonNull + public static Intent createIntent(@NonNull Context context) { + return new Intent(context, SettingsActivity.class); + } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/MarkDownUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/MarkDownUtil.java deleted file mode 100644 index 9e1e5b147..000000000 --- a/app/src/main/java/it/niedermann/nextcloud/deck/util/MarkDownUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -package it.niedermann.nextcloud.deck.util; - -import android.content.Context; - -import androidx.core.content.ContextCompat; -import androidx.core.content.res.ResourcesCompat; - -import com.yydcdut.rxmarkdown.RxMDConfiguration.Builder; - -import it.niedermann.nextcloud.deck.R; - -/** - * Created by stefan on 07.12.16. - */ - -public class MarkDownUtil { - - private MarkDownUtil() {} - - /** - * Ensures every instance of RxMD uses the same configuration - * - * @param context Context - * @return RxMDConfiguration - */ - public static Builder getMarkDownConfiguration(Context context) { - return new Builder(context) - .setHeader2RelativeSize(1.35f) - .setHeader3RelativeSize(1.25f) - .setHeader4RelativeSize(1.15f) - .setHeader5RelativeSize(1.1f) - .setHeader6RelativeSize(1.05f) - .setHorizontalRulesHeight(2) - .setLinkFontColor(ContextCompat.getColor(context, R.color.primary)); - } - - public static Builder getMarkDownConfiguration(Context context, Boolean darkTheme) { - return new Builder(context) - .setHeader2RelativeSize(1.35f) - .setHeader3RelativeSize(1.25f) - .setHeader4RelativeSize(1.15f) - .setHeader5RelativeSize(1.1f) - .setHeader6RelativeSize(1.05f) - .setHorizontalRulesHeight(2) - .setLinkFontColor(ResourcesCompat.getColor(context.getResources(), R.color.primary, null)); - } -} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java index fbc7fc3fc..013a3d334 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java @@ -2,12 +2,8 @@ package it.niedermann.nextcloud.deck.util; import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.style.ImageSpan; import android.widget.ImageView; import android.widget.TextView; @@ -15,7 +11,6 @@ import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; @@ -23,16 +18,11 @@ import androidx.core.widget.TextViewCompat; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; -import com.bumptech.glide.request.target.CustomTarget; -import com.bumptech.glide.request.transition.Transition; import java.time.LocalDate; -import java.util.List; import it.niedermann.android.util.DimensionUtil; import it.niedermann.nextcloud.deck.R; -import it.niedermann.nextcloud.deck.model.Account; -import it.niedermann.nextcloud.deck.model.ocs.comment.Mention; import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION_CODES.LOLLIPOP; @@ -88,58 +78,6 @@ public final class ViewUtil { return drawable; } - /** - * Replaces all mentions in the textView with an avatar and the display name - * - * @param account {@link Account} where the users of those mentions belong to - * @param mentions {@link List} of all mentions that should be substituted - * @param textView target {@link TextView} - */ - public static void setupMentions(@NonNull Account account, @NonNull List<Mention> mentions, TextView textView) { - Context context = textView.getContext(); - SpannableStringBuilder messageBuilder = new SpannableStringBuilder(textView.getText()); - - // Step 1 - // Add avatar icons and display names - for (Mention m : mentions) { - final String mentionId = "@" + m.getMentionId(); - final String mentionDisplayName = " " + m.getMentionDisplayName(); - int index = messageBuilder.toString().lastIndexOf(mentionId); - while (index >= 0) { - messageBuilder.setSpan(new ImageSpan(context, R.drawable.ic_person_grey600_24dp), index, index + mentionId.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - messageBuilder.insert(index + mentionId.length(), mentionDisplayName); - index = messageBuilder.toString().substring(0, index).lastIndexOf(mentionId); - } - } - textView.setText(messageBuilder); - - // Step 2 - // Replace avatar icons with real avatars - final ImageSpan[] list = messageBuilder.getSpans(0, messageBuilder.length(), ImageSpan.class); - for (ImageSpan span : list) { - final int spanStart = messageBuilder.getSpanStart(span); - final int spanEnd = messageBuilder.getSpanEnd(span); - Glide.with(context) - .asBitmap() - .placeholder(R.drawable.ic_person_grey600_24dp) - .load(account.getUrl() + "/index.php/avatar/" + messageBuilder.subSequence(spanStart + 1, spanEnd).toString() + "/" + DimensionUtil.INSTANCE.dpToPx(context, R.dimen.icon_size_details)) - .apply(RequestOptions.circleCropTransform()) - .into(new CustomTarget<Bitmap>() { - @Override - public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { - messageBuilder.removeSpan(span); - messageBuilder.setSpan(new ImageSpan(context, resource), spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - @Override - public void onLoadCleared(@Nullable Drawable placeholder) { - // silence is gold - } - }); - } - textView.setText(messageBuilder); - } - public static void setImageColor(@NonNull Context context, @NonNull ImageView imageView, @ColorRes int colorRes) { if (SDK_INT >= LOLLIPOP) { imageView.setImageTintList(ColorStateList.valueOf(ContextCompat.getColor(context, colorRes))); diff --git a/app/src/main/res/drawable/ic_baseline_eye_24.xml b/app/src/main/res/drawable/ic_baseline_eye_24.xml new file mode 100644 index 000000000..c8acf29a8 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_eye_24.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#757575" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/> +</vector> diff --git a/app/src/main/res/layout/fragment_card_edit_tab_comments.xml b/app/src/main/res/layout/fragment_card_edit_tab_comments.xml index cc5fa77b7..4e340c3a2 100644 --- a/app/src/main/res/layout/fragment_card_edit_tab_comments.xml +++ b/app/src/main/res/layout/fragment_card_edit_tab_comments.xml @@ -49,7 +49,7 @@ android:padding="@dimen/spacer_1x" app:srcCompat="@drawable/ic_reply_grey600_24dp" /> - <TextView + <it.niedermann.android.markdown.MarkdownViewerImpl android:id="@+id/replyCommentText" android:layout_width="0dp" android:layout_height="wrap_content" diff --git a/app/src/main/res/layout/fragment_card_edit_tab_details.xml b/app/src/main/res/layout/fragment_card_edit_tab_details.xml index 2dfb79889..a2f5e5b21 100644 --- a/app/src/main/res/layout/fragment_card_edit_tab_details.xml +++ b/app/src/main/res/layout/fragment_card_edit_tab_details.xml @@ -131,29 +131,56 @@ tools:listitem="@tools:sample/avatars" /> <LinearLayout + android:id="@+id/descriptionBar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacer_2x" android:orientation="horizontal"> <ImageView android:layout_width="@dimen/icon_size_details" android:layout_height="wrap_content" - android:layout_marginTop="10dp" android:layout_marginEnd="@dimen/spacer_2x" android:contentDescription="@null" app:srcCompat="@drawable/ic_baseline_subject_24" /> - <com.yydcdut.markdown.MarkdownEditText - android:id="@+id/description" - android:layout_width="match_parent" + <LinearLayout + android:layout_width="0dp" android:layout_height="wrap_content" - android:gravity="top" - android:hint="@string/label_description" - android:importantForAutofill="no" - android:inputType="textMultiLine|textCapSentences" - android:scrollbars="vertical" /> + android:layout_weight="1" + android:gravity="end" + android:orientation="horizontal"> + + <ImageView + android:id="@+id/descriptionToggle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackgroundBorderless" + android:contentDescription="@string/edit_description" + android:paddingStart="@dimen/spacer_1x" + android:paddingEnd="@dimen/spacer_1x" + android:visibility="gone" + app:srcCompat="@drawable/ic_baseline_eye_24" + tools:visibility="gone" /> + </LinearLayout> </LinearLayout> + + <it.niedermann.android.markdown.MarkdownEditorImpl + android:id="@+id/descriptionEditor" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacer_1x" + android:textColor="?attr/colorAccent" + android:textSize="@dimen/font_size_description" /> + + <it.niedermann.android.markdown.MarkdownViewerImpl + android:id="@+id/descriptionViewer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacer_2x" + android:textColor="?attr/colorAccent" + android:textIsSelectable="true" + android:textSize="@dimen/font_size_description" + android:visibility="gone" /> </LinearLayout> <TextView diff --git a/app/src/main/res/layout/item_comment.xml b/app/src/main/res/layout/item_comment.xml index 754e989fe..2863699a5 100644 --- a/app/src/main/res/layout/item_comment.xml +++ b/app/src/main/res/layout/item_comment.xml @@ -94,7 +94,7 @@ tools:text="@tools:sample/date/day_of_week" /> </LinearLayout> - <com.yydcdut.markdown.MarkdownTextView + <it.niedermann.android.markdown.MarkdownViewerImpl android:id="@+id/message" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index edd334cf3..e44e774b3 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -109,6 +109,7 @@ <string name="no_lists_yet">Još nema popisa</string> <string name="do_you_want_to_save_your_changes">Želite li spremiti promjene?</string> <string name="do_you_want_to_archive_all_cards_of_the_list">Želite li arhivirati sve kartice iz %1$s?</string> + <string name="do_you_want_to_archive_all_cards_of_the_filtered_list">Želite li arhivirati sve filtrirane kartice od %1$s?</string> <plurals name="do_you_want_to_delete_the_current_list"> <item quantity="one">Trajno ćete izbrisati %1$d karticu s ovog popisa.</item> <item quantity="few">Trajno ćete izbrisati %1$d kartice s ovog popisa.</item> @@ -278,4 +279,8 @@ <string name="project_type_room">Soba za razgovor</string> <string name="simple_move">Premjesti</string> <string name="cannot_upload_files_without_permission">Otpremanje datoteka bez dopuštenja nije moguće</string> + <string name="clone_cards">Kloniraj kartice</string> + <string name="simple_clone">Kloniraj</string> + <string name="user_avatar">Avatar korisnika</string> + <string name="simple_unassign">Poništi dodjelu</string> </resources> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index c19fe8de1..ac7a62c15 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -9,6 +9,8 @@ <dimen name="compact_label_height">6dp</dimen> <dimen name="attachments_bottom_navigation_height">64dp</dimen> + <dimen name="font_size_description">18sp</dimen> + <!-- Drawer header --> <dimen name="drawer_header_height">100dp</dimen> <dimen name="drawer_header_logo_size">42dp</dimen> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b152a2a6f..5c7aaf716 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -323,4 +323,5 @@ <string name="add_stack_widget">Add list widget</string> <string name="add_filter_widget">Add filter widget</string> <string name="simple_order">Order</string> + <string name="edit_description">Edit description</string> </resources> |