From 0c6683b46349560a8377273039743da1a3a0f397 Mon Sep 17 00:00:00 2001 From: Stefan Niedermann Date: Mon, 31 May 2021 20:54:38 +0200 Subject: Create card in PrepareCreateActivity before starting the EditActivity Signed-off-by: Stefan Niedermann --- .../nextcloud/deck/ui/PickStackActivity.java | 86 +++++++++++++---- .../nextcloud/deck/ui/card/EditActivity.java | 13 +-- .../deck/ui/pickstack/PickStackViewModel.java | 53 +++++++++++ .../ui/preparecreate/PrepareCreateActivity.java | 62 +++++++++--- .../ui/preparecreate/PrepareCreateViewModel.java | 104 +++++++++++++++++++++ .../stack/StackWidgetConfigurationActivity.java | 16 ++-- 6 files changed, 285 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateViewModel.java (limited to 'app/src/main/java/it/niedermann/nextcloud/deck') 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 d60ce4002..34df713c7 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 @@ -3,6 +3,9 @@ package it.niedermann.nextcloud.deck.ui; import android.content.res.ColorStateList; import android.graphics.Color; import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; @@ -17,11 +20,14 @@ import java.util.List; import it.niedermann.android.util.ColorUtil; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; +import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.databinding.ActivityPickStackBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.Stack; import it.niedermann.nextcloud.deck.ui.branding.Branded; +import it.niedermann.nextcloud.deck.ui.branding.BrandingUtil; +import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import it.niedermann.nextcloud.deck.ui.pickstack.PickStackFragment; import it.niedermann.nextcloud.deck.ui.pickstack.PickStackListener; @@ -34,13 +40,8 @@ import static it.niedermann.nextcloud.deck.util.DeckColorUtil.contrastRatioIsSuf public abstract class PickStackActivity extends AppCompatActivity implements Branded, PickStackListener { - protected ActivityPickStackBinding binding; - protected PickStackViewModel viewModel; - - private Account selectedAccount; - private Board selectedBoard; - private Stack selectedStack; - + private ActivityPickStackBinding binding; + private PickStackViewModel viewModel; @Override protected void onCreate(Bundle savedInstanceState) { @@ -71,20 +72,58 @@ public abstract class PickStackActivity extends AppCompatActivity implements Bra .commit(); }); binding.cancel.setOnClickListener((v) -> finish()); - binding.submit.setOnClickListener((v) -> onSubmit(selectedAccount, selectedBoard.getLocalId(), selectedStack.getLocalId())); + binding.submit.setOnClickListener((v) -> { + viewModel.setSubmitInProgress(true); + onSubmit(viewModel.getAccount(), viewModel.getBoardLocalId(), viewModel.getStackLocalId(), new IResponseCallback() { + @Override + public void onResponse(Void response) { + runOnUiThread(() -> viewModel.setSubmitInProgress(false)); + } + + @Override + public void onError(Throwable throwable) { + IResponseCallback.super.onError(throwable); + runOnUiThread(() -> { + viewModel.setSubmitInProgress(false); + ExceptionDialogFragment + .newInstance(throwable, viewModel.getAccount()) + .show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); + }); + } + }); + }); + viewModel.submitButtonEnabled().observe(this, (enabled) -> binding.submit.setEnabled(enabled)); + if (requireContent()) { + viewModel.setContentIsSatisfied(false); + binding.inputWrapper.setVisibility(View.VISIBLE); + binding.input.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Nothing to do here... + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + viewModel.setContentIsSatisfied(s != null && !s.toString().trim().isEmpty()); + } + + @Override + public void afterTextChanged(Editable s) { + // Nothing to do here... + } + }); + } else { + viewModel.setContentIsSatisfied(true); + } } @Override public void onStackPicked(@NonNull Account account, @Nullable Board board, @Nullable Stack stack) { - this.selectedAccount = account; - this.selectedBoard = board; - this.selectedStack = stack; - if (board == null) { - binding.submit.setEnabled(false); - } else { - applyBrand(board.getColor()); - binding.submit.setEnabled(stack != null); - } + viewModel.setSelected(account, board, stack); + applyBrand(board == null + ? ContextCompat.getColor(this, R.color.accent) + : board.getColor() + ); } @Override @@ -96,12 +135,23 @@ public abstract class PickStackActivity extends AppCompatActivity implements Bra DrawableCompat.setTintList(binding.submit.getBackground(), ColorStateList.valueOf(finalMainColor)); binding.submit.setTextColor(ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(finalMainColor)); binding.cancel.setTextColor(getSecondaryForegroundColorDependingOnTheme(this, mainColor)); + BrandingUtil.applyBrandToEditTextInputLayout(mainColor, binding.inputWrapper); } catch (Throwable t) { DeckLog.logError(t); } } - abstract protected void onSubmit(Account account, long boardLocalId, long stackId); + abstract protected void onSubmit(Account account, long boardLocalId, long stackId, @NonNull IResponseCallback callback); abstract protected boolean showBoardsWithoutEditPermission(); + + protected boolean requireContent() { + return false; + } + + @NonNull + protected String getContent() { + final Editable text = binding.input.getText(); + return text == null ? "" : text.toString(); + } } \ No newline at end of file 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 989fbcafe..71725c88a 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 @@ -325,18 +325,7 @@ public class EditActivity extends AppCompatActivity { applyBrandToPrimaryTabLayout(mainColor, binding.tabLayout); } - @NonNull - public static Intent createNewCardIntent(@NonNull Context context, @NonNull Account account, Long boardLocalId, Long stackId, @Nullable String title, @Nullable String description) { - return createNewCardIntent(context, account, boardLocalId, stackId, title) - .putExtra(BUNDLE_KEY_DESCRIPTION, description); - } - - @NonNull - public static Intent createNewCardIntent(@NonNull Context context, @NonNull Account account, Long boardLocalId, Long stackId, @Nullable String title) { - return createNewCardIntent(context, account, boardLocalId, stackId) - .putExtra(BUNDLE_KEY_TITLE, title); - } - + @Deprecated @NonNull public static Intent createNewCardIntent(@NonNull Context context, @NonNull Account account, Long boardLocalId, Long stackId) { return createBasicIntent(context, account, boardLocalId) diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java index cc9fc2259..f9fbcae89 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/pickstack/PickStackViewModel.java @@ -3,8 +3,10 @@ package it.niedermann.nextcloud.deck.ui.pickstack; import android.app.Application; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import java.util.List; @@ -13,16 +15,67 @@ import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.Stack; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; +import static androidx.lifecycle.Transformations.distinctUntilChanged; + @SuppressWarnings("WeakerAccess") public class PickStackViewModel extends AndroidViewModel { private final SyncManager syncManager; + private Account selectedAccount; + @Nullable + private Board selectedBoard; + @Nullable + private Stack selectedStack; + private boolean contentIsSatisfied = false; + private boolean saveInProgress = false; + + private final MutableLiveData submitButtonEnabled$ = new MutableLiveData<>(false); + public PickStackViewModel(@NonNull Application application) { super(application); this.syncManager = new SyncManager(application); } + public LiveData submitButtonEnabled() { + return distinctUntilChanged(submitButtonEnabled$); + } + + public void setContentIsSatisfied(boolean isSatisfied) { + this.contentIsSatisfied = isSatisfied; + this.submitButtonEnabled$.setValue(!saveInProgress && contentIsSatisfied && selectedBoard != null && selectedStack != null); + } + + public void setSelected(@NonNull Account account, @Nullable Board board, @Nullable Stack stack) { + this.selectedAccount = account; + this.selectedBoard = board; + this.selectedStack = stack; + this.submitButtonEnabled$.setValue(!saveInProgress && contentIsSatisfied && selectedBoard != null && selectedStack != null); + } + + public void setSubmitInProgress(boolean saveInProgress) { + this.saveInProgress = saveInProgress; + this.submitButtonEnabled$.setValue(!saveInProgress && contentIsSatisfied && selectedBoard != null && selectedStack != null); + } + + public Account getAccount() { + return this.selectedAccount; + } + + public long getBoardLocalId() { + if (this.selectedBoard == null) { + throw new IllegalStateException("Check submitButtonEnabled() before calling this method."); + } + return this.selectedBoard.getLocalId(); + } + + public long getStackLocalId() { + if (this.selectedStack == null) { + throw new IllegalStateException("Check submitButtonEnabled() before calling this method."); + } + return this.selectedStack.getLocalId(); + } + public LiveData hasAccounts() { return syncManager.hasAccounts(); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java index 53e25a0d9..ccb7c8a38 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java @@ -1,13 +1,20 @@ package it.niedermann.nextcloud.deck.ui.preparecreate; +import android.annotation.SuppressLint; import android.content.Intent; import android.os.Bundle; +import android.text.TextUtils; +import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; +import androidx.lifecycle.ViewModelProvider; import it.niedermann.nextcloud.deck.R; +import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.model.Account; +import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.ui.PickStackActivity; import it.niedermann.nextcloud.deck.ui.card.EditActivity; @@ -17,6 +24,8 @@ import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentStackId; public class PrepareCreateActivity extends PickStackActivity { + private PrepareCreateViewModel viewModel; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -24,29 +33,60 @@ public class PrepareCreateActivity extends PickStackActivity { if (actionBar != null) { actionBar.setTitle(R.string.add_card); } + + viewModel = new ViewModelProvider(this).get(PrepareCreateViewModel.class); } @Override - protected void onSubmit(Account account, long boardId, long stackId) { - final Intent intent = getIntent(); - if (intent == null) { - startActivity(EditActivity.createNewCardIntent(this, account, boardId, stackId)); + protected void onSubmit(Account account, long boardId, long stackId, @NonNull IResponseCallback callback) { + Toast.makeText(this, R.string.saving_new_card, Toast.LENGTH_SHORT).show(); + final FullCard fullCard; + if (requireContent()) { + fullCard = viewModel.createFullCard(account.getServerDeckVersionAsObject(), getContent()); } else { - startActivity(EditActivity.createNewCardIntent(this, account, boardId, stackId, + final Intent intent = getIntent(); + if (intent == null) { + throw new IllegalStateException("Intent should not be null because title is required."); + } + fullCard = viewModel.createFullCard( + account.getServerDeckVersionAsObject(), + intent.getStringExtra(Intent.EXTRA_SUBJECT), intent.getStringExtra(Intent.EXTRA_TITLE), - intent.getStringExtra(Intent.EXTRA_TEXT))); + intent.getStringExtra(Intent.EXTRA_TEXT) + ); } - saveCurrentAccount(this, account); - saveCurrentBoardId(this, account.getId(), boardId); - saveCurrentStackId(this, account.getId(), boardId, stackId); - applyBrand(account.getColor()); + viewModel.saveCard(account.getId(), boardId, stackId, fullCard, new IResponseCallback() { + @Override + public void onResponse(FullCard response) { + saveCurrentAccount(PrepareCreateActivity.this, account); + saveCurrentBoardId(PrepareCreateActivity.this, account.getId(), boardId); + saveCurrentStackId(PrepareCreateActivity.this, account.getId(), boardId, stackId); - finish(); + callback.onResponse(null); + startActivity(EditActivity.createEditCardIntent(PrepareCreateActivity.this, account, boardId, response.getLocalId())); + finish(); + } + + @Override + @SuppressLint("MissingSuperCall") + public void onError(Throwable throwable) { + callback.onError(throwable); + } + }); } @Override protected boolean showBoardsWithoutEditPermission() { return false; } + + @Override + protected boolean requireContent() { + final Intent intent = getIntent(); + return intent == null || (TextUtils.isEmpty(intent.getStringExtra(Intent.EXTRA_SUBJECT)) && + TextUtils.isEmpty(intent.getStringExtra(Intent.EXTRA_TITLE)) && + TextUtils.isEmpty(intent.getStringExtra(Intent.EXTRA_TEXT))); + } + } \ No newline at end of file diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateViewModel.java new file mode 100644 index 000000000..1ce61f380 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateViewModel.java @@ -0,0 +1,104 @@ +package it.niedermann.nextcloud.deck.ui.preparecreate; + +import android.app.Application; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.AndroidViewModel; + +import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.model.Card; +import it.niedermann.nextcloud.deck.model.full.FullCard; +import it.niedermann.nextcloud.deck.model.ocs.Version; +import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; + +@SuppressWarnings("WeakerAccess") +public class PrepareCreateViewModel extends AndroidViewModel { + + private final SyncManager syncManager; + + public PrepareCreateViewModel(@NonNull Application application) { + super(application); + this.syncManager = new SyncManager(application); + } + + public void saveCard(long accountId, long boardLocalId, long stackLocalId, @NonNull FullCard fullCard, @NonNull IResponseCallback callback) { + syncManager.createFullCard(accountId, boardLocalId, stackLocalId, fullCard, callback); + } + + @SuppressWarnings("ConstantConditions") + public FullCard createFullCard(@NonNull Version version, @Nullable String subject, @Nullable String title, @Nullable String description) { + if (TextUtils.isEmpty(subject) && TextUtils.isEmpty(title) && TextUtils.isEmpty(description)) { + throw new IllegalArgumentException("Subject, title or description must not be empty."); + } + if (TextUtils.isEmpty(subject)) { + if (TextUtils.isEmpty(title)) { + return createFullCard(version, description); + } else if (TextUtils.isEmpty(description)) { + return createFullCard(version, title); + } else { + return createFullCard(version, title, description); + } + } else if (TextUtils.isEmpty(title)) { + if (TextUtils.isEmpty(subject)) { + return createFullCard(version, description); + } else if (TextUtils.isEmpty(description)) { + return createFullCard(version, subject); + } else { + return createFullCard(version, subject, description); + } + } else if (TextUtils.isEmpty(description)) { + if (TextUtils.isEmpty(subject)) { + return createFullCard(version, title); + } else if (TextUtils.isEmpty(title)) { + return createFullCard(version, description); + } else { + return createFullCard(version, subject, title); + } + } else { + return createFullCard(version, subject, title.trim() + "\n\n" + description.trim()); + } + } + + public FullCard createFullCard(@NonNull Version version, @NonNull String title, @NonNull String description) { + if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(description)) { + final FullCard fullCard = new FullCard(); + final Card card = new Card(); + final int maxLength = version.getCardTitleMaxLength(); + if (title.length() > maxLength) { + card.setTitle(title.substring(0, maxLength)); + card.setDescription(title.substring(maxLength).trim() + "\n\n" + description); + } else { + card.setTitle(title); + card.setDescription(description); + } + fullCard.setCard(card); + return fullCard; + } else if (!TextUtils.isEmpty(title)) { + return createFullCard(version, title); + } else if (!TextUtils.isEmpty(description)) { + return createFullCard(version, description); + } else { + throw new IllegalArgumentException("Title or description must not be empty."); + } + } + + public FullCard createFullCard(@NonNull Version version, @NonNull String content) { + if (TextUtils.isEmpty(content)) { + throw new IllegalArgumentException("Content must not be empty."); + } + final FullCard fullCard = new FullCard(); + final Card card = new Card(); + final int maxLength = version.getCardTitleMaxLength(); + if (content.length() > maxLength) { + card.setTitle(content.substring(0, maxLength).trim()); + card.setDescription(content.substring(maxLength).trim()); + } else { + card.setTitle(content); + card.setDescription(null); + } + fullCard.setCard(card); + return fullCard; + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java index 07747b275..85c987740 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java @@ -1,9 +1,11 @@ package it.niedermann.nextcloud.deck.ui.widget.stack; +import android.annotation.SuppressLint; import android.appwidget.AppWidgetManager; import android.content.Intent; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.lifecycle.ViewModelProvider; @@ -11,6 +13,7 @@ import java.util.Collections; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; +import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.api.ResponseCallback; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.widget.filter.EWidgetType; @@ -19,7 +22,6 @@ import it.niedermann.nextcloud.deck.model.widget.filter.FilterWidgetAccount; import it.niedermann.nextcloud.deck.model.widget.filter.FilterWidgetBoard; import it.niedermann.nextcloud.deck.model.widget.filter.FilterWidgetStack; import it.niedermann.nextcloud.deck.ui.PickStackActivity; -import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; public class StackWidgetConfigurationActivity extends PickStackActivity { private int appWidgetId; @@ -51,7 +53,7 @@ public class StackWidgetConfigurationActivity extends PickStackActivity { } @Override - protected void onSubmit(Account account, long boardId, long stackId) { + protected void onSubmit(Account account, long boardId, long stackId, @NonNull IResponseCallback callback) { final FilterWidget config = new FilterWidget(appWidgetId, EWidgetType.STACK_WIDGET); final FilterWidgetAccount filterWidgetAccount = new FilterWidgetAccount(account.getId(), false); filterWidgetAccount.setIncludeNoProject(false); @@ -60,8 +62,8 @@ public class StackWidgetConfigurationActivity extends PickStackActivity { filterWidgetAccount.setBoards( Collections.singletonList(filterWidgetBoard)); config.setAccounts(Collections.singletonList(filterWidgetAccount)); - stackWidgetConfigurationViewModel.addStackWidget(config, new ResponseCallback(account) { + stackWidgetConfigurationViewModel.addStackWidget(config, new ResponseCallback(account) { @Override public void onResponse(Integer response) { final Intent updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, @@ -69,16 +71,14 @@ public class StackWidgetConfigurationActivity extends PickStackActivity { .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); setResult(RESULT_OK, updateIntent); getApplicationContext().sendBroadcast(updateIntent); - + callback.onResponse(null); finish(); } @Override + @SuppressLint("MissingSuperCall") public void onError(Throwable throwable) { - super.onError(throwable); - ExceptionDialogFragment - .newInstance(throwable, account) - .show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); + callback.onError(throwable); } }); } -- cgit v1.2.3