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

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2024-01-15 19:08:58 +0300
committerStefan Niedermann <info@niedermann.it>2024-01-15 19:08:58 +0300
commitc97057858e03f0cfc0318a0acbc5dad94fabe7e7 (patch)
tree3ed1a2d83606cb16a1ec526ab1c11acca4baaa91 /app/src/main
parent35f94be61a18013a42cd5b1d1c2955b28a26d405 (diff)
feat(done): Show done state in card detail view
Refs: #1556 Signed-off-by: Stefan Niedermann <info@niedermann.it>
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java166
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDueDateView.java292
-rw-r--r--app/src/main/res/layout/fragment_card_edit_tab_details.xml89
-rw-r--r--app/src/main/res/layout/view_card_due_date.xml136
-rw-r--r--app/src/main/res/values/strings.xml1
5 files changed, 466 insertions, 218 deletions
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 d96ffa21f..f5b7149e6 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
@@ -29,18 +29,8 @@ import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar;
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
-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 java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.format.FormatStyle;
import java.util.stream.Stream;
import it.niedermann.android.markdown.MarkdownEditor;
@@ -61,17 +51,13 @@ 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.ui.theme.ThemeUtils;
-import it.niedermann.nextcloud.deck.ui.theme.ThemedDatePickerDialog;
import it.niedermann.nextcloud.deck.ui.theme.ThemedSnackbar;
-import it.niedermann.nextcloud.deck.ui.theme.ThemedTimePickerDialog;
-public class CardDetailsFragment extends Fragment implements OnDateSetListener, OnTimeSetListener, CardAssigneeListener {
+public class CardDetailsFragment extends Fragment implements CardDueDateView.DueDateChangedListener, CardAssigneeListener {
private FragmentCardEditTabDetailsBinding binding;
private EditCardViewModel viewModel;
private AssigneeAdapter adapter;
- private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
- private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
private static final String KEY_ACCOUNT = "account";
public static Fragment newInstance(@NonNull Account account) {
@@ -123,16 +109,16 @@ public class CardDetailsFragment extends Fragment implements OnDateSetListener,
viewModel.getBoardColor().observe(getViewLifecycleOwner(), this::applyTheme);
}
- @Override
- public void onResume() {
- super.onResume();
-
- // https://github.com/wdullaer/MaterialDateTimePicker#why-are-my-callbacks-lost-when-the-device-changes-orientation
- final var dpd = (DatePickerDialog) getChildFragmentManager().findFragmentByTag(ThemedDatePickerDialog.class.getCanonicalName());
- final var tpd = (TimePickerDialog) getChildFragmentManager().findFragmentByTag(ThemedTimePickerDialog.class.getCanonicalName());
- if (tpd != null) tpd.setOnTimeSetListener(this);
- if (dpd != null) dpd.setOnDateSetListener(this);
- }
+// @Override
+// public void onResume() {
+// super.onResume();
+//
+// // https://github.com/wdullaer/MaterialDateTimePicker#why-are-my-callbacks-lost-when-the-device-changes-orientation
+// final var dpd = (DatePickerDialog) getChildFragmentManager().findFragmentByTag(ThemedDatePickerDialog.class.getCanonicalName());
+// final var tpd = (TimePickerDialog) getChildFragmentManager().findFragmentByTag(ThemedTimePickerDialog.class.getCanonicalName());
+// if (tpd != null) tpd.setOnTimeSetListener(this);
+// if (dpd != null) dpd.setOnDateSetListener(this);
+// }
@Override
public void onDestroy() {
@@ -145,22 +131,16 @@ public class CardDetailsFragment extends Fragment implements OnDateSetListener,
Stream.of(
binding.labelsWrapper,
- binding.dueDateDateWrapper,
- binding.dueDateTimeWrapper,
binding.peopleWrapper,
binding.descriptionEditorWrapper
).forEach(utils.material::colorTextInputLayout);
- Stream.of(
- binding.clearDueDate,
- binding.descriptionToggle
- ).forEach(v -> utils.platform.colorImageView(v, ColorRole.SECONDARY));
+ utils.platform.colorImageView(binding.descriptionToggle, ColorRole.SECONDARY);
+ binding.cardDueDateView.applyTheme(color);
binding.descriptionEditor.setSearchColor(color);
binding.descriptionViewer.setSearchColor(color);
- utils.material.colorMaterialButtonPrimaryTonal(binding.markAsDone);
-
// TODO apply correct branding on the BrandedDatePicker
}
@@ -203,65 +183,24 @@ public class CardDetailsFragment extends Fragment implements OnDateSetListener,
}
private void setupDueDate() {
+ final var card = this.viewModel.getFullCard().getCard();
+ binding.cardDueDateView.setDueDateListener(this);
+ binding.cardDueDateView.setEnabled(this.viewModel.canEdit());
+ binding.cardDueDateView.setDueDate(getChildFragmentManager(), card.getDueDate(), card.getDone());
+ }
- if (this.viewModel.getFullCard().getCard().getDueDate() != null) {
- final var dueDate = this.viewModel.getFullCard().getCard().getDueDate().atZone(ZoneId.systemDefault());
- binding.dueDateDate.setText(dueDate == null ? null : dueDate.format(dateFormatter));
- binding.dueDateTime.setText(dueDate == null ? null : dueDate.format(timeFormatter));
- binding.clearDueDate.setVisibility(VISIBLE);
- } else {
- binding.clearDueDate.setVisibility(GONE);
- binding.dueDateDate.setText(null);
- binding.dueDateTime.setText(null);
- }
-
- if (viewModel.canEdit()) {
- if (this.viewModel.getFullCard().getCard().getDone() == null) {
- binding.markAsDone.setVisibility(VISIBLE);
- } else {
- binding.markAsDone.setVisibility(GONE);
- }
-
- binding.markAsDone.setOnClickListener(v -> {
- viewModel.getFullCard().getCard().setDone(Instant.now());
- });
-
- binding.dueDateDate.setOnClickListener(v -> {
- final LocalDate date;
- if (viewModel.getFullCard() != null && viewModel.getFullCard().getCard() != null && viewModel.getFullCard().getCard().getDueDate() != null) {
- date = viewModel.getFullCard().getCard().getDueDate().atZone(ZoneId.systemDefault()).toLocalDate();
- } else {
- date = LocalDate.now();
- }
- viewModel.getCurrentBoardColor(viewModel.getAccount().getId(), viewModel.getBoardId())
- .thenAcceptAsync(color -> ThemedDatePickerDialog.newInstance(this, date.getYear(), date.getMonthValue(), date.getDayOfMonth(), color)
- .show(getChildFragmentManager(), ThemedDatePickerDialog.class.getCanonicalName()), ContextCompat.getMainExecutor(requireContext()));
- });
-
- binding.dueDateTime.setOnClickListener(v -> {
- final LocalTime time;
- if (viewModel.getFullCard() != null && viewModel.getFullCard().getCard() != null && viewModel.getFullCard().getCard().getDueDate() != null) {
- time = viewModel.getFullCard().getCard().getDueDate().atZone(ZoneId.systemDefault()).toLocalTime();
- } else {
- time = LocalTime.now();
- }
- viewModel.getCurrentBoardColor(viewModel.getAccount().getId(), viewModel.getBoardId())
- .thenAcceptAsync(color -> ThemedTimePickerDialog.newInstance(this, time.getHour(), time.getMinute(), true, color)
- .show(getChildFragmentManager(), ThemedTimePickerDialog.class.getCanonicalName()), ContextCompat.getMainExecutor(requireContext()));
- });
+ @Override
+ public void onDueDateChanged(@Nullable Instant dueDate) {
+ final var card = this.viewModel.getFullCard().getCard();
+ card.setDueDate(dueDate);
+ binding.cardDueDateView.setDueDate(getChildFragmentManager(), card.getDueDate(), card.getDone());
+ }
- binding.clearDueDate.setOnClickListener(v -> {
- binding.dueDateDate.setText(null);
- binding.dueDateTime.setText(null);
- viewModel.getFullCard().getCard().setDueDate(null);
- binding.clearDueDate.setVisibility(GONE);
- });
- } else {
- binding.dueDateDate.setEnabled(false);
- binding.dueDateTime.setEnabled(false);
- binding.clearDueDate.setVisibility(GONE);
- binding.markAsDone.setVisibility(GONE);
- }
+ @Override
+ public void onDoneChanged(@Nullable Instant done) {
+ final var card = this.viewModel.getFullCard().getCard();
+ card.setDone(done);
+ binding.cardDueDateView.setDueDate(getChildFragmentManager(), card.getDueDate(), card.getDone());
}
private void setupLabels(@NonNull Account account) {
@@ -385,53 +324,6 @@ public class CardDetailsFragment extends Fragment implements OnDateSetListener,
}
}
- @Override
- public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
- int hourOfDay;
- int minute;
-
- final var selectedTime = binding.dueDateTime.getText();
- if (TextUtils.isEmpty(selectedTime)) {
- hourOfDay = 0;
- minute = 0;
- } else {
- final LocalTime oldTime = LocalTime.from(this.viewModel.getFullCard().getCard().getDueDate().atZone(ZoneId.systemDefault()));
- hourOfDay = oldTime.getHour();
- minute = oldTime.getMinute();
- }
-
- final var newDateTime = ZonedDateTime.of(
- LocalDate.of(year, monthOfYear + 1, dayOfMonth),
- LocalTime.of(hourOfDay, minute),
- ZoneId.systemDefault()
- );
- this.viewModel.getFullCard().getCard().setDueDate(newDateTime.toInstant());
- binding.dueDateDate.setText(newDateTime.format(dateFormatter));
-
- if (this.viewModel.getFullCard().getCard().getDueDate() == null || this.viewModel.getFullCard().getCard().getDueDate().toEpochMilli() == 0) {
- binding.clearDueDate.setVisibility(GONE);
- } else {
- binding.clearDueDate.setVisibility(VISIBLE);
- }
- }
-
- @Override
- public void onTimeSet(TimePickerDialog view, int hourOfDay, int minute, int second) {
- final var oldInstant = this.viewModel.getFullCard().getCard().getDueDate();
- final var oldDateTime = oldInstant == null ? ZonedDateTime.now() : oldInstant.atZone(ZoneId.systemDefault());
- final var newDateTime = oldDateTime.with(
- LocalTime.of(hourOfDay, minute)
- );
-
- this.viewModel.getFullCard().getCard().setDueDate(newDateTime.toInstant());
- binding.dueDateTime.setText(newDateTime.format(timeFormatter));
- if (this.viewModel.getFullCard().getCard().getDueDate() == null || this.viewModel.getFullCard().getCard().getDueDate().toEpochMilli() == 0) {
- binding.clearDueDate.setVisibility(GONE);
- } else {
- binding.clearDueDate.setVisibility(VISIBLE);
- }
- }
-
private void setupProjects() {
if (viewModel.getFullCard().getProjects().size() > 0) {
binding.projectsTitle.setVisibility(VISIBLE);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDueDateView.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDueDateView.java
new file mode 100644
index 000000000..1d264d35f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDueDateView.java
@@ -0,0 +1,292 @@
+package it.niedermann.nextcloud.deck.ui.card.details;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentManager;
+
+import com.nextcloud.android.common.ui.theme.utils.ColorRole;
+import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
+import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
+import java.util.stream.Stream;
+
+import it.niedermann.nextcloud.deck.databinding.ViewCardDueDateBinding;
+import it.niedermann.nextcloud.deck.ui.theme.ThemeUtils;
+import it.niedermann.nextcloud.deck.ui.theme.Themed;
+import it.niedermann.nextcloud.deck.ui.theme.ThemedDatePickerDialog;
+import it.niedermann.nextcloud.deck.ui.theme.ThemedTimePickerDialog;
+
+public class CardDueDateView extends FrameLayout implements DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener, Themed {
+
+ private final ViewCardDueDateBinding binding;
+ @Nullable
+ private DueDateChangedListener dueDateChangedListener;
+ private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
+ private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
+ @Nullable
+ private Instant dueDate = null;
+ @Nullable
+ private Instant done = null;
+ @Nullable
+ @ColorInt
+ private Integer color = null;
+ private FragmentManager fragmentManager = null;
+
+ public CardDueDateView(Context context) {
+ super(context);
+ binding = ViewCardDueDateBinding.inflate(LayoutInflater.from(context), this, true);
+ }
+
+ public CardDueDateView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ binding = ViewCardDueDateBinding.inflate(LayoutInflater.from(context), this, true);
+ }
+
+ public CardDueDateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ binding = ViewCardDueDateBinding.inflate(LayoutInflater.from(context), this, true);
+ }
+
+ public CardDueDateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ binding = ViewCardDueDateBinding.inflate(LayoutInflater.from(context), this, true);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (enabled != isEnabled()) {
+ super.setEnabled(enabled);
+ render();
+ }
+ }
+
+ public void setDueDate(@NonNull FragmentManager fragmentManager, @Nullable Instant dueDate, @Nullable Instant done) {
+ this.fragmentManager = fragmentManager;
+ this.dueDate = dueDate;
+ this.done = done;
+ render();
+ }
+
+ private void render() {
+ setVisibilityState();
+ setTextState();
+ setInteraction();
+ }
+
+ private void setInteraction() {
+ final var enabled = isEnabled();
+
+ binding.dueDateDate.setEnabled(enabled);
+ binding.dueDateTime.setEnabled(enabled);
+
+ if (enabled) {
+ binding.clearDone.setOnClickListener(v -> {
+ if (this.dueDateChangedListener != null) {
+ this.dueDateChangedListener.onDoneChanged(null);
+ }
+ });
+
+ binding.markAsDone.setOnClickListener(v -> {
+ if (this.dueDateChangedListener != null) {
+ this.dueDateChangedListener.onDoneChanged(Instant.now());
+ }
+ });
+
+ binding.clearDueDate.setOnClickListener(v -> {
+ if (this.dueDateChangedListener != null) {
+ this.dueDateChangedListener.onDueDateChanged(null);
+ }
+ });
+
+ binding.dueDateDate.setOnClickListener(v -> {
+ if (this.fragmentManager == null || this.color == null) {
+ return;
+ }
+ final LocalDate date;
+ if (this.dueDate != null) {
+ date = this.dueDate.atZone(ZoneId.systemDefault()).toLocalDate();
+ } else {
+ date = LocalDate.now();
+ }
+
+ ThemedDatePickerDialog.newInstance(this, date.getYear(), date.getMonthValue(), date.getDayOfMonth(), this.color)
+ .show(this.fragmentManager, ThemedDatePickerDialog.class.getCanonicalName());
+ });
+
+ binding.dueDateTime.setOnClickListener(v -> {
+ if (this.fragmentManager == null || this.color == null) {
+ return;
+ }
+ final LocalTime time;
+ if (this.dueDate != null) {
+ time = this.dueDate.atZone(ZoneId.systemDefault()).toLocalTime();
+ } else {
+ time = LocalTime.now();
+ }
+ ThemedTimePickerDialog.newInstance(this, time.getHour(), time.getMinute(), true, this.color)
+ .show(this.fragmentManager, ThemedTimePickerDialog.class.getCanonicalName());
+ });
+ } else {
+ Stream.of(
+ binding.clearDone,
+ binding.markAsDone,
+ binding.clearDueDate,
+ binding.dueDateDate,
+ binding.dueDateTime
+ ).forEach(v -> v.setOnClickListener(null));
+ }
+ }
+
+ private void setTextState() {
+ if (done == null) {
+ binding.doneDate.setText(null);
+ binding.doneDueDate.setText(null);
+
+ if (this.dueDate == null) {
+ binding.dueDateDate.setText(null);
+ binding.dueDateTime.setText(null);
+
+ } else {
+ final var dueDate = this.dueDate.atZone(ZoneId.systemDefault());
+ binding.dueDateDate.setText(dueDate.format(dateFormatter));
+ binding.dueDateTime.setText(dueDate.format(timeFormatter));
+ }
+
+ } else {
+ binding.dueDateDate.setText(null);
+ binding.dueDateTime.setText(null);
+
+ binding.doneDate.setText(done.atZone(ZoneId.systemDefault()).format(dateFormatter));
+
+ if (this.dueDate == null) {
+ binding.doneDueDate.setText(null);
+
+ } else {
+ final var dueDate = this.dueDate.atZone(ZoneId.systemDefault());
+ binding.doneDueDate.setText(dueDate.format(dateFormatter));
+ }
+ }
+ }
+
+ private void setVisibilityState() {
+ if (done == null) {
+ Stream.of(
+ binding.markAsDone,
+ binding.dueDateDateWrapper,
+ binding.dueDateTimeWrapper
+ ).forEach(v -> v.setVisibility(View.VISIBLE));
+
+ Stream.of(
+ binding.doneCheck,
+ binding.doneDueDate,
+ binding.doneDate,
+ binding.clearDone
+ ).forEach(v -> v.setVisibility(View.GONE));
+
+ binding.clearDueDate.setVisibility(dueDate == null || !isEnabled() ? View.GONE : View.VISIBLE);
+ } else {
+
+ Stream.of(
+ binding.doneCheck,
+ binding.doneDate,
+ binding.clearDone
+ ).forEach(v -> v.setVisibility(View.VISIBLE));
+
+ Stream.of(
+ binding.markAsDone,
+ binding.dueDateDateWrapper,
+ binding.dueDateTimeWrapper,
+ binding.clearDueDate
+ ).forEach(v -> v.setVisibility(View.GONE));
+
+ binding.doneDueDate.setVisibility(dueDate == null || !isEnabled() ? View.GONE : View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
+ int hourOfDay;
+ int minute;
+
+ final var selectedTime = binding.dueDateTime.getText();
+ if (TextUtils.isEmpty(selectedTime)) {
+ hourOfDay = 0;
+ minute = 0;
+ } else {
+ final var oldTime = LocalTime.from(this.dueDate.atZone(ZoneId.systemDefault()));
+ hourOfDay = oldTime.getHour();
+ minute = oldTime.getMinute();
+ }
+
+ final var newDateTime = ZonedDateTime.of(
+ LocalDate.of(year, monthOfYear + 1, dayOfMonth),
+ LocalTime.of(hourOfDay, minute),
+ ZoneId.systemDefault()
+ );
+ this.dueDate = newDateTime.toInstant();
+
+ if (dueDateChangedListener != null) {
+ dueDateChangedListener.onDueDateChanged(newDateTime.toInstant());
+ }
+ }
+
+ @Override
+ public void onTimeSet(TimePickerDialog view, int hourOfDay, int minute, int second) {
+ final var oldDateTime = this.dueDate == null ? ZonedDateTime.now() : this.dueDate.atZone(ZoneId.systemDefault());
+ final var newDateTime = oldDateTime.with(
+ LocalTime.of(hourOfDay, minute)
+ );
+
+ if (dueDateChangedListener != null) {
+ dueDateChangedListener.onDueDateChanged(newDateTime.toInstant());
+ }
+ }
+
+ @Override
+ public void applyTheme(int color) {
+ this.color = color;
+ final var utils = ThemeUtils.of(color, getContext());
+
+ Stream.of(
+ binding.dueDateDateWrapper,
+ binding.dueDateTimeWrapper
+ ).forEach(utils.material::colorTextInputLayout);
+
+ Stream.of(
+ binding.doneDueDate,
+ binding.doneDate
+ ).forEach(utils.platform::colorTextView);
+
+ Stream.of(
+ binding.clearDone,
+ binding.clearDueDate
+ ).forEach(v -> utils.platform.colorImageView(v, ColorRole.SECONDARY));
+
+ utils.material.colorMaterialButtonPrimaryTonal(binding.markAsDone);
+ }
+
+ public void setDueDateListener(@Nullable DueDateChangedListener dueDateChangedListener) {
+ this.dueDateChangedListener = dueDateChangedListener;
+ }
+
+ public interface DueDateChangedListener {
+ void onDueDateChanged(@Nullable Instant dueDate);
+
+ void onDoneChanged(@Nullable Instant done);
+ }
+}
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 80b107119..c39a00fc5 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
@@ -69,95 +69,22 @@
android:layout_marginTop="@dimen/spacer_1x"
android:layout_marginBottom="@dimen/spacer_1hx"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
- app:layout_constraintBottom_toTopOf="@id/dueDateDateWrapper"
+ app:layout_constraintBottom_toTopOf="@id/cardDueDateView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/peopleWrapper"
tools:listitem="@tools:sample/avatars" />
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/dueDateDateWrapper"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/spacer_2x"
- android:layout_marginEnd="@dimen/spacer_2x"
- android:hint="@string/hint_due_date_date"
- android:labelFor="@id/dueDateDate"
- app:layout_constraintBottom_toTopOf="@id/markAsDone"
- app:layout_constraintEnd_toStartOf="@id/dueDateTimeWrapper"
- app:layout_constraintHorizontal_weight="2"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/assignees"
- app:startIconDrawable="@drawable/calendar_blank_grey600_24dp">
-
- <EditText
- android:id="@+id/dueDateDate"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:enabled="true"
- android:focusable="false"
- android:importantForAutofill="no"
- android:inputType="date"
- android:maxLines="1"
- tools:text="01/07/2020" />
- </com.google.android.material.textfield.TextInputLayout>
-
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/dueDateTimeWrapper"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/spacer_1hx"
- android:hint="@string/hint_due_date_time"
- android:labelFor="@id/dueDateTime"
- app:layout_constraintBottom_toBottomOf="@id/dueDateDateWrapper"
- app:layout_constraintEnd_toStartOf="@id/clearDueDate"
- app:layout_constraintHorizontal_weight="1"
- app:layout_constraintStart_toEndOf="@id/dueDateDateWrapper"
- app:layout_constraintTop_toTopOf="@id/dueDateDateWrapper">
-
- <EditText
- android:id="@+id/dueDateTime"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:enabled="true"
- android:focusable="false"
- android:importantForAutofill="no"
- android:inputType="datetime"
- android:maxLines="1"
- android:minLines="0"
- android:textAlignment="center"
- tools:text="11:45" />
- </com.google.android.material.textfield.TextInputLayout>
-
- <ImageView
- android:id="@+id/clearDueDate"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="@dimen/spacer_1hx"
- android:layout_marginStart="@dimen/spacer_1x"
- android:layout_marginEnd="0dp"
- android:contentDescription="@string/label_clear_due_date"
- android:padding="@dimen/spacer_11qx"
- android:translationY="@dimen/spacer_1hx"
- app:layout_constraintBottom_toBottomOf="@id/dueDateTimeWrapper"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@id/dueDateTimeWrapper"
- app:layout_constraintTop_toTopOf="@id/dueDateTimeWrapper"
- app:srcCompat="@drawable/ic_close_circle_grey600" />
-
- <com.google.android.material.button.MaterialButton
- android:id="@+id/markAsDone"
- style="@style/Widget.Material3.Button"
- android:layout_width="0dp"
+ <it.niedermann.nextcloud.deck.ui.card.details.CardDueDateView
+ android:id="@+id/cardDueDateView"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacer_2x"
- android:layout_marginBottom="@dimen/spacer_1hx"
- android:text="@string/simple_completed"
- app:backgroundTint="@color/defaultBrand"
- app:icon="@drawable/ic_check_white_24dp"
app:layout_constraintBottom_toTopOf="@id/descriptionWrapper"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/dueDateDateWrapper" />
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/assignees" />
+
<RelativeLayout
android:id="@+id/descriptionWrapper"
@@ -167,7 +94,7 @@
app:layout_constraintBottom_toTopOf="@id/projectsTitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/dueDateDateWrapper">
+ app:layout_constraintTop_toBottomOf="@id/cardDueDateView">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/descriptionEditorWrapper"
diff --git a/app/src/main/res/layout/view_card_due_date.xml b/app/src/main/res/layout/view_card_due_date.xml
new file mode 100644
index 000000000..dc183fea7
--- /dev/null
+++ b/app/src/main/res/layout/view_card_due_date.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/doneCheck"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="@dimen/spacer_1hx"
+ android:layout_marginStart="@dimen/spacer_1qx"
+ android:layout_marginEnd="0dp"
+ android:contentDescription="@null"
+ android:padding="@dimen/spacer_11qx"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:srcCompat="@drawable/ic_check_white_24dp"
+ app:tint="?attr/colorOnSurface" />
+
+ <TextView
+ android:id="@+id/doneDate"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="@id/doneCheck"
+ app:layout_constraintEnd_toStartOf="@id/clearDone"
+ app:layout_constraintStart_toEndOf="@id/doneCheck"
+ app:layout_constraintTop_toTopOf="@id/doneCheck"
+ tools:text="@tools:sample/date/ddmmyy" />
+
+ <ImageView
+ android:id="@+id/clearDone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="@dimen/spacer_1hx"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginEnd="0dp"
+ android:contentDescription="@string/label_clear_done"
+ android:padding="@dimen/spacer_11qx"
+ app:layout_constraintBottom_toBottomOf="@id/doneDate"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@id/doneDate"
+ app:srcCompat="@drawable/ic_close_circle_grey600" />
+
+ <TextView
+ android:id="@+id/done_due_date"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toStartOf="@id/clearDone"
+ app:layout_constraintStart_toEndOf="@id/doneCheck"
+ app:layout_constraintTop_toBottomOf="@id/doneDate"
+ tools:text="@tools:sample/date/ddmmyy" />
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/dueDateDateWrapper"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:hint="@string/hint_due_date_date"
+ android:labelFor="@id/dueDateDate"
+ app:layout_constraintBottom_toTopOf="@id/markAsDone"
+ app:layout_constraintEnd_toStartOf="@id/dueDateTimeWrapper"
+ app:layout_constraintHorizontal_weight="2"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/done_due_date"
+ app:startIconDrawable="@drawable/calendar_blank_grey600_24dp">
+
+ <EditText
+ android:id="@+id/dueDateDate"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:enabled="true"
+ android:focusable="false"
+ android:importantForAutofill="no"
+ android:inputType="date"
+ android:maxLines="1"
+ tools:text="01/07/2020" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/dueDateTimeWrapper"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_1hx"
+ android:hint="@string/hint_due_date_time"
+ android:labelFor="@id/dueDateTime"
+ app:layout_constraintBottom_toBottomOf="@id/dueDateDateWrapper"
+ app:layout_constraintEnd_toStartOf="@id/clearDueDate"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintStart_toEndOf="@id/dueDateDateWrapper"
+ app:layout_constraintTop_toTopOf="@id/dueDateDateWrapper">
+
+ <EditText
+ android:id="@+id/dueDateTime"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:enabled="true"
+ android:focusable="false"
+ android:importantForAutofill="no"
+ android:inputType="datetime"
+ android:maxLines="1"
+ android:minLines="0"
+ android:textAlignment="center"
+ tools:text="11:45" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <ImageView
+ android:id="@+id/clearDueDate"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="@dimen/spacer_1hx"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginEnd="0dp"
+ android:contentDescription="@string/label_clear_due_date"
+ android:padding="@dimen/spacer_11qx"
+ android:translationY="@dimen/spacer_1hx"
+ app:layout_constraintBottom_toBottomOf="@id/dueDateTimeWrapper"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/dueDateTimeWrapper"
+ app:layout_constraintTop_toTopOf="@id/dueDateTimeWrapper"
+ app:srcCompat="@drawable/ic_close_circle_grey600" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/markAsDone"
+ style="@style/Widget.Material3.Button"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/spacer_2x"
+ android:layout_marginBottom="@dimen/spacer_1hx"
+ android:text="@string/simple_completed"
+ app:backgroundTint="@color/defaultBrand"
+ app:icon="@drawable/ic_check_white_24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/dueDateDateWrapper" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 71b56aeab..0d7e4ae48 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -98,6 +98,7 @@
<string name="add_board">Add board</string>
<string name="label_clear_due_date">Clear due date</string>
+ <string name="label_clear_done">Not completed</string>
<string name="label_add">Add %1$s</string>
<string name="url_maintainer" translatable="false">https://www.niedermann.it/</string>