diff options
author | Stefan Niedermann <info@niedermann.it> | 2021-06-17 18:30:59 +0300 |
---|---|---|
committer | Stefan Niedermann <info@niedermann.it> | 2021-06-17 18:31:10 +0300 |
commit | b108515abae3a9523179f4e576545335978fcbfd (patch) | |
tree | 37936d02d4f59d5b5174d21c63b650f30203723d | |
parent | 5fa1024e4a63e2e85cd94f6d7e237d8d3a7b549b (diff) | |
parent | 34458e8c3bc02daae17872b2ab0671d20119a8ce (diff) |
Merge branch 'master' into create-card-before-editing
Signed-off-by: Stefan Niedermann <info@niedermann.it>
# Conflicts:
# app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java
15 files changed, 132 insertions, 78 deletions
diff --git a/app/build.gradle b/app/build.gradle index fa5e6f8d6..d2477e60a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -121,7 +121,7 @@ dependencies { // Tests testImplementation 'junit:junit:4.13.2' testImplementation 'org.robolectric:robolectric:4.5.1' - testImplementation 'org.mockito:mockito-core:3.11.0' + testImplementation 'org.mockito:mockito-core:3.11.1' testImplementation 'androidx.test:core:1.3.0' testImplementation 'androidx.arch.core:core-testing:2.1.0' } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/LiveDataHelper.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/LiveDataHelper.java index 10a18bb09..059ed5e6b 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/LiveDataHelper.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/LiveDataHelper.java @@ -6,38 +6,24 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.MediatorLiveData; import androidx.lifecycle.Observer; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import static androidx.lifecycle.Transformations.distinctUntilChanged; public class LiveDataHelper { - public interface DataChangeProcessor<T> { - void onDataChanged(T data); + private LiveDataHelper() { + throw new UnsupportedOperationException("This class must not be instantiated."); } - public interface DataTransformator<I, O> { - O transform(I data); - } - - public interface LiveDataWrapper<T> { - T getData(); - - default void postResult(WrappedLiveData<T> liveData) { - liveData.setError(null); - T data = null; - try { - data = getData(); - } catch (RuntimeException e) { - liveData.setError(e); - } - liveData.postValue(data); - } - } + private static final ExecutorService executor = Executors.newCachedThreadPool(); public static <T> LiveData<T> interceptLiveData(LiveData<T> data, DataChangeProcessor<T> onDataChange) { MediatorLiveData<T> ret = new MediatorLiveData<>(); ret.addSource(data, changedData -> - doAsync(() -> { + executor.submit(() -> { onDataChange.onDataChanged(changedData); ret.postValue(changedData); }) @@ -47,32 +33,29 @@ public class LiveDataHelper { public static <I, O> LiveData<O> postCustomValue(LiveData<I> data, DataTransformator<I, O> transformator) { - MediatorLiveData<O> ret = new MediatorLiveData<>(); - - ret.addSource(data, changedData -> doAsync(() -> ret.postValue(transformator.transform(changedData)))); + final MediatorLiveData<O> ret = new MediatorLiveData<>(); + ret.addSource(data, changedData -> executor.submit(() -> ret.postValue(transformator.transform(changedData)))); return distinctUntilChanged(ret); } public static <I> MediatorLiveData<I> of(I oneShot) { - MediatorLiveData<I> ret = new MediatorLiveData<I>() { + return new MediatorLiveData<I>() { @Override public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) { super.observe(owner, observer); - doAsync(() -> postValue(oneShot)); + executor.submit(() -> postValue(oneShot)); } }; - return ret; } public static <I, O> LiveData<O> postSingleValue(LiveData<I> data, DataTransformator<I, O> transformator) { - MediatorLiveData<O> ret = new MediatorLiveData<>(); - - ret.addSource(data, changedData -> doAsync(() -> ret.postValue(transformator.transform(changedData)))); + final MediatorLiveData<O> ret = new MediatorLiveData<>(); + ret.addSource(data, changedData -> executor.submit(() -> ret.postValue(transformator.transform(changedData)))); return distinctUntilChanged(ret); } public static <T> void observeOnce(LiveData<T> liveData, LifecycleOwner owner, Observer<T> observer) { - Observer<T> tempObserver = new Observer<T>() { + final Observer<T> tempObserver = new Observer<T>() { @Override public void onChanged(T result) { liveData.removeObserver(this); @@ -85,7 +68,7 @@ public class LiveDataHelper { public static <T> WrappedLiveData<T> wrapInLiveData(final LiveDataWrapper<T> liveDataWrapper) { final WrappedLiveData<T> liveData = new WrappedLiveData<>(); - doAsync(() -> { + executor.submit(() -> { try { liveDataWrapper.postResult(liveData); } catch (Throwable t) { @@ -96,7 +79,26 @@ public class LiveDataHelper { return liveData; } - private static void doAsync(Runnable r) { - new Thread(r).start(); + public interface DataChangeProcessor<T> { + void onDataChanged(T data); + } + + public interface DataTransformator<I, O> { + O transform(I data); + } + + public interface LiveDataWrapper<T> { + T getData(); + + default void postResult(WrappedLiveData<T> liveData) { + liveData.setError(null); + T data = null; + try { + data = getData(); + } catch (RuntimeException e) { + liveData.setError(e); + } + liveData.postValue(data); + } } }
\ No newline at end of file diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/extrawurst/UserSearchLiveData.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/extrawurst/UserSearchLiveData.java index 3d05247b3..4a90664c9 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/extrawurst/UserSearchLiveData.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/extrawurst/UserSearchLiveData.java @@ -18,12 +18,12 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter public class UserSearchLiveData extends MediatorLiveData<List<User>> implements Debouncer.Callback<Long> { private static final int DEBOUNCE_TIME = 300; // ms - private DataBaseAdapter db; - private ServerAdapter server; + private final DataBaseAdapter db; + private final ServerAdapter server; long accountId; String searchTerm; long notYetAssignedInACL; - private Debouncer<Long> debouncer = new Debouncer<>(this, DEBOUNCE_TIME); + private final Debouncer<Long> debouncer = new Debouncer<>(this, DEBOUNCE_TIME); public UserSearchLiveData(DataBaseAdapter db, ServerAdapter server) { this.db = db; diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java index d01ef3d42..79e29c08b 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java @@ -3,13 +3,20 @@ package it.niedermann.nextcloud.deck.ui.board; import android.app.Dialog; import android.content.Context; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProvider; +import java.util.Objects; + import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogTextColorInputBinding; import it.niedermann.nextcloud.deck.model.full.FullBoard; @@ -75,6 +82,14 @@ public class EditBoardDialogFragment extends DialogFragment { return builder.create(); } + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding.input.requestFocus(); + Objects.requireNonNull(requireDialog().getWindow()).setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + return super.onCreateView(inflater, container, savedInstanceState); + } + public static DialogFragment newInstance(long boardId) { final DialogFragment dialog = new EditBoardDialogFragment(); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/NewCardDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/NewCardDialog.java index 5d60951fe..d133ef029 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/NewCardDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/NewCardDialog.java @@ -72,8 +72,8 @@ public class NewCardDialog extends DialogFragment implements DialogInterface.OnC final AlertDialog dialog = new AlertDialog.Builder(requireActivity()) .setTitle(R.string.add_card) .setView(binding.getRoot()) - .setPositiveButton(R.string.edit, null) - .setNegativeButton(R.string.simple_save, null) + .setPositiveButton(R.string.save_and_edit, null) + .setNegativeButton(R.string.save_and_close, null) .create(); dialog.setOnShowListener(d -> { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java index f1f584df6..4648e34c3 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java @@ -19,6 +19,8 @@ import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import it.niedermann.android.crosstabdnd.DragAndDropAdapter; import it.niedermann.android.crosstabdnd.DraggedItemLocalState; @@ -45,6 +47,7 @@ import static it.niedermann.nextcloud.deck.util.MimeTypeUtil.TEXT_PLAIN; public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> implements DragAndDropAdapter<FullCard>, CardOptionsItemSelectedListener, Branded { + private final ExecutorService executor; private final boolean compactMode; @NonNull protected final MainViewModel mainViewModel; @@ -66,6 +69,10 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im protected final int maxCoverImages; public CardAdapter(@NonNull Activity activity, @NonNull FragmentManager fragmentManager, long stackId, @NonNull MainViewModel mainViewModel, @Nullable SelectCardListener selectCardListener) { + this(activity, fragmentManager, stackId, mainViewModel, selectCardListener, Executors.newSingleThreadExecutor()); + } + + private CardAdapter(@NonNull Activity activity, @NonNull FragmentManager fragmentManager, long stackId, @NonNull MainViewModel mainViewModel, @Nullable SelectCardListener selectCardListener, @NonNull ExecutorService executor) { this.activity = activity; this.counterMaxValue = this.activity.getString(R.string.counter_max_value); this.fragmentManager = fragmentManager; @@ -79,6 +86,7 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im ? activity.getResources().getInteger(R.integer.max_cover_images) : 0; setHasStableIds(true); + this.executor = executor; } @Override @@ -204,10 +212,10 @@ public class CardAdapter extends RecyclerView.Adapter<AbstractCardViewHolder> im .putExtra(Intent.EXTRA_TEXT, CardUtil.getCardContentAsString(activity, fullCard)); activity.startActivity(Intent.createChooser(shareIntent, fullCard.getCard().getTitle())); } else if (itemId == R.id.action_card_assign) { - new Thread(() -> mainViewModel.assignUserToCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); + executor.submit(() -> mainViewModel.assignUserToCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())); return true; } else if (itemId == R.id.action_card_unassign) { - new Thread(() -> mainViewModel.unassignUserFromCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())).start(); + executor.submit(() -> mainViewModel.unassignUserFromCard(mainViewModel.getUserByUidDirectly(fullCard.getCard().getAccountId(), account.getUserName()), fullCard.getCard())); return true; } else if (itemId == R.id.action_card_move) { DeckLog.verbose("[Move card] Launch move dialog for " + Card.class.getSimpleName() + " \"" + fullCard.getCard().getTitle() + "\" (#" + fullCard.getLocalId() + ") from " + Stack.class.getSimpleName() + " #" + +stackId); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java index 4594fcf79..4cf57ba6f 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java @@ -38,6 +38,8 @@ import java.io.IOException; import java.time.Instant; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import id.zelory.compressor.constraint.FormatConstraint; import id.zelory.compressor.constraint.QualityConstraint; @@ -95,6 +97,7 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentDelet private PreviewDialogViewModel previewViewModel; private BottomSheetBehavior<LinearLayout> mBottomSheetBehaviour; private boolean compressImagesOnUpload = true; + private final ExecutorService executor = Executors.newCachedThreadPool(); private RecyclerView.ItemDecoration galleryItemDecoration; @@ -404,7 +407,7 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentDelet DeckLog.verbose("--- found content URL", sourceUri.getPath()); // Separate Thread required because picked file might not yet be locally available // https://github.com/stefan-niedermann/nextcloud-deck/issues/814 - new Thread(() -> { + executor.submit(() -> { try { final File originalFile = copyContentUriToTempFile(requireContext(), sourceUri, editViewModel.getAccount().getId(), editViewModel.getFullCard().getLocalId()); requireActivity().runOnUiThread(() -> { @@ -430,7 +433,7 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentDelet } catch (IOException e) { requireActivity().runOnUiThread(() -> ExceptionDialogFragment.newInstance(e, editViewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName())); } - }).start(); + }); break; } default: { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/upcomingcards/UpcomingCardsViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/upcomingcards/UpcomingCardsViewModel.java index 23336c91f..8914a87ed 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/upcomingcards/UpcomingCardsViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/upcomingcards/UpcomingCardsViewModel.java @@ -7,6 +7,8 @@ import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.model.Account; @@ -19,10 +21,12 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiv public class UpcomingCardsViewModel extends AndroidViewModel { private final SyncManager syncManager; + private final ExecutorService executor; public UpcomingCardsViewModel(@NonNull Application application) { super(application); this.syncManager = new SyncManager(application); + this.executor = Executors.newCachedThreadPool(); } public LiveData<List<UpcomingCardsAdapterItem>> getUpcomingCards() { @@ -30,11 +34,11 @@ public class UpcomingCardsViewModel extends AndroidViewModel { } public void assignUser(@NonNull Account account, @NonNull Card card) { - new Thread(() -> syncManager.assignUserToCard(syncManager.getUserByUidDirectly(card.getAccountId(), account.getUserName()), card)).start(); + executor.submit(() -> syncManager.assignUserToCard(syncManager.getUserByUidDirectly(card.getAccountId(), account.getUserName()), card)); } public void unassignUser(@NonNull Account account, @NonNull Card card) { - new Thread(() -> syncManager.unassignUserFromCard(syncManager.getUserByUidDirectly(card.getAccountId(), account.getUserName()), card)).start(); + executor.submit(() -> syncManager.unassignUserFromCard(syncManager.getUserByUidDirectly(card.getAccountId(), account.getUserName()), card)); } public void archiveCard(@NonNull FullCard card, @NonNull IResponseCallback<FullCard> callback) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/filter/FilterWidget.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/filter/FilterWidget.java index 89d75eeee..56ea508c0 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/filter/FilterWidget.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/filter/FilterWidget.java @@ -7,7 +7,11 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import androidx.annotation.NonNull; + import java.util.NoSuchElementException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.model.Account; @@ -18,26 +22,26 @@ import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE; public class FilterWidget extends AppWidgetProvider { public static final String ACCOUNT_KEY = "filter_widget_account"; public static final String BUNDLE_KEY = "filter_widget_bundle"; + final ExecutorService executor = Executors.newCachedThreadPool(); - static void updateAppWidget(Context context, AppWidgetManager awm, int[] appWidgetIds, Account account) { + static void updateAppWidget(@NonNull ExecutorService executor, @NonNull Context context, AppWidgetManager awm, int[] appWidgetIds, Account account) { final SyncManager syncManager = new SyncManager(context); - for (int appWidgetId : appWidgetIds) { - new Thread(() -> { + executor.submit(() -> { try { // TODO implement throw new UnsupportedOperationException("Not yet implemented"); } catch (NoSuchElementException e) { // onUpdate has been triggered before the user finished configuring the widget } - }).start(); + }); } } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); - updateAppWidget(context, appWidgetManager, appWidgetIds, null); + updateAppWidget(executor, context, appWidgetManager, appWidgetIds, null); } @Override @@ -56,10 +60,10 @@ public class FilterWidget extends AppWidgetProvider { if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { if (intent.getExtras() != null) { - updateAppWidget(context, awm, new int[]{intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)}, account); + updateAppWidget(executor, context, awm, new int[]{intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)}, account); } } else { - updateAppWidget(context, awm, awm.getAppWidgetIds(new ComponentName(context, FilterWidget.class)), account); + updateAppWidget(executor, context, awm, awm.getAppWidgetIds(new ComponentName(context, FilterWidget.class)), account); } } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SingleCardWidget.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SingleCardWidget.java index 766948062..b3e4d622b 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SingleCardWidget.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SingleCardWidget.java @@ -15,6 +15,8 @@ import androidx.annotation.IdRes; import androidx.annotation.NonNull; import java.util.NoSuchElementException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.model.Card; @@ -25,11 +27,13 @@ import it.niedermann.nextcloud.deck.util.DateUtil; public class SingleCardWidget extends AppWidgetProvider { + private final ExecutorService executor = Executors.newCachedThreadPool(); + void updateAppWidget(Context context, AppWidgetManager awm, int[] appWidgetIds) { final SyncManager syncManager = new SyncManager(context); for (int appWidgetId : appWidgetIds) { - new Thread(() -> { + executor.submit(() -> { try { final FullSingleCardWidgetModel fullModel = syncManager.getSingleCardWidgetModelDirectly(appWidgetId); @@ -106,7 +110,7 @@ public class SingleCardWidget extends AppWidgetProvider { } catch (NoSuchElementException e) { // onUpdate has been triggered before the user finished configuring the widget } - }).start(); + }); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidget.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidget.java index 5b0907ef3..02d426bbb 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidget.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidget.java @@ -10,6 +10,10 @@ import android.net.Uri; import android.widget.RemoteViews; import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; @@ -23,11 +27,12 @@ import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE; public class StackWidget extends AppWidgetProvider { private static final int PENDING_INTENT_OPEN_APP_RQ = 0; private static final int PENDING_INTENT_EDIT_CARD_RQ = 1; + private final ExecutorService executor = Executors.newCachedThreadPool(); @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); - updateAppWidget(context, appWidgetManager, appWidgetIds); + updateAppWidget(executor, context, appWidgetManager, appWidgetIds); } @Override @@ -40,10 +45,10 @@ public class StackWidget extends AppWidgetProvider { if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { final int appWidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); DeckLog.verbose(ACTION_APPWIDGET_UPDATE, "for", StackWidget.class.getSimpleName(), "with id", appWidgetId, "→ perform update."); - updateAppWidget(context, awm, new int[]{appWidgetId}); + updateAppWidget(executor, context, awm, new int[]{appWidgetId}); } else { DeckLog.verbose(ACTION_APPWIDGET_UPDATE, "→ Triggering update for all widgets of type", StackWidget.class.getSimpleName()); - updateAppWidget(context, awm, awm.getAppWidgetIds(new ComponentName(context, StackWidget.class))); + updateAppWidget(executor, context, awm, awm.getAppWidgetIds(new ComponentName(context, StackWidget.class))); } } } @@ -59,10 +64,10 @@ public class StackWidget extends AppWidgetProvider { } } - private static void updateAppWidget(Context context, AppWidgetManager awm, int[] appWidgetIds) { + private static void updateAppWidget(@NonNull ExecutorService executor, @NonNull Context context, AppWidgetManager awm, int[] appWidgetIds) { final SyncManager syncManager = new SyncManager(context); for (int appWidgetId : appWidgetIds) { - new Thread(() -> { + executor.submit(() -> { if (syncManager.filterWidgetExists(appWidgetId)) { final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_stack); @@ -94,7 +99,7 @@ public class StackWidget extends AppWidgetProvider { } else { DeckLog.warn("Does not yet exist"); } - }).start(); + }); } } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/upcoming/UpcomingWidget.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/upcoming/UpcomingWidget.java index a28f1ef4f..42c7989dd 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/upcoming/UpcomingWidget.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/upcoming/UpcomingWidget.java @@ -12,6 +12,8 @@ import android.widget.RemoteViews; import androidx.annotation.NonNull; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.stream.Collectors; import it.niedermann.nextcloud.deck.BuildConfig; @@ -35,6 +37,7 @@ public class UpcomingWidget extends AppWidgetProvider { private static final String PENDING_INTENT_ACTION_OPEN = "open"; private static final String PENDING_INTENT_PARAM_LOCAL_CARD_ID = "localCardId"; private static final String PENDING_INTENT_PARAM_ACCOUNT_ID = "accountId"; + private final ExecutorService executor = Executors.newCachedThreadPool(); @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { @@ -42,10 +45,10 @@ public class UpcomingWidget extends AppWidgetProvider { final SyncManager syncManager = new SyncManager(context); for (int appWidgetId : appWidgetIds) { - new Thread(() -> { + executor.submit(() -> { if (syncManager.filterWidgetExists(appWidgetId)) { DeckLog.warn(UpcomingWidget.class.getSimpleName(), "with id", appWidgetId, "already exists, perform update instead."); - updateAppWidget(context, appWidgetManager, appWidgetIds); + updateAppWidget(executor, context, appWidgetManager, appWidgetIds); } else { final List<Account> accountsList = syncManager.readAccountsDirectly(); final FilterWidget config = new FilterWidget(appWidgetId, EWidgetType.UPCOMING_WIDGET); @@ -59,7 +62,7 @@ public class UpcomingWidget extends AppWidgetProvider { @Override public void onResponse(Integer response) { DeckLog.verbose("Successfully created", UpcomingWidget.class.getSimpleName(), "with id", appWidgetId); - updateAppWidget(context, appWidgetManager, appWidgetIds); + updateAppWidget(executor, context, appWidgetManager, appWidgetIds); } @Override @@ -70,7 +73,7 @@ public class UpcomingWidget extends AppWidgetProvider { } }); } - }).start(); + }); } } @@ -84,17 +87,17 @@ public class UpcomingWidget extends AppWidgetProvider { if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { final int appWidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); DeckLog.verbose(ACTION_APPWIDGET_UPDATE, "for", UpcomingWidget.class.getSimpleName(), "with id", appWidgetId, "→ perform update."); - updateAppWidget(context, awm, new int[]{appWidgetId}); + updateAppWidget(executor, context, awm, new int[]{appWidgetId}); } else { DeckLog.verbose(ACTION_APPWIDGET_UPDATE, "→ Triggering update for all widgets of type", UpcomingWidget.class.getSimpleName()); - updateAppWidget(context, awm, awm.getAppWidgetIds(new ComponentName(context, UpcomingWidget.class))); + updateAppWidget(executor, context, awm, awm.getAppWidgetIds(new ComponentName(context, UpcomingWidget.class))); } } else if (PENDING_INTENT_ACTION_EDIT.equals(intent.getAction())) { if (intent.hasExtra(PENDING_INTENT_PARAM_ACCOUNT_ID) && intent.hasExtra(PENDING_INTENT_PARAM_LOCAL_CARD_ID)) { - new Thread(() -> { + executor.submit(() -> { final SyncManager syncManager = new SyncManager(context); context.startActivity(EditActivity.createEditCardIntent(context, syncManager.readAccountDirectly(intent.getLongExtra(PENDING_INTENT_PARAM_ACCOUNT_ID, -1)), syncManager.getBoardLocalIdByLocalCardIdDirectly(intent.getLongExtra(PENDING_INTENT_PARAM_LOCAL_CARD_ID, -1)), intent.getLongExtra(PENDING_INTENT_PARAM_LOCAL_CARD_ID, -1))); - }).start(); + }); } else { DeckLog.error(PENDING_INTENT_PARAM_ACCOUNT_ID, "and", PENDING_INTENT_PARAM_LOCAL_CARD_ID, "must be provided for action", PENDING_INTENT_ACTION_EDIT); } @@ -114,9 +117,9 @@ public class UpcomingWidget extends AppWidgetProvider { } } - private static void updateAppWidget(@NonNull Context context, @NonNull AppWidgetManager awm, int[] appWidgetIds) { + private static void updateAppWidget(@NonNull ExecutorService executor, @NonNull Context context, @NonNull AppWidgetManager awm, int[] appWidgetIds) { for (int appWidgetId : appWidgetIds) { - new Thread(() -> { + executor.submit(() -> { final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_upcoming); final Intent serviceIntent = new Intent(context, UpcomingWidgetService.class); @@ -131,7 +134,7 @@ public class UpcomingWidget extends AppWidgetProvider { awm.notifyAppWidgetViewDataChanged(appWidgetId, R.id.upcoming_widget_lv); awm.updateAppWidget(appWidgetId, views); - }).start(); + }); } } diff --git a/app/src/main/res/layout/activity_exception.xml b/app/src/main/res/layout/activity_exception.xml index 932fa7bf2..9d7420d1f 100644 --- a/app/src/main/res/layout/activity_exception.xml +++ b/app/src/main/res/layout/activity_exception.xml @@ -28,7 +28,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:hint="An error appeared." + android:hint="@string/hint_error_appeared" app:drawableEndCompat="@drawable/ic_bug_report_black_24dp" tools:ignore="HardcodedText" /> @@ -111,4 +111,4 @@ app:backgroundTint="@color/defaultBrand" /> </LinearLayout> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f9acf8b6b..8cacf2776 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,6 +3,7 @@ <string name="app_name_short" translatable="false">Deck</string> <string name="navigation_drawer_open">Open navigation drawer</string> <string name="navigation_drawer_close">Close navigation drawer</string> + <string name="hint_search_deck">Search deck</string> <string name="simple_boards">Boards</string> <string name="simple_add">Add</string> @@ -34,6 +35,7 @@ <string name="simple_copied">Copied</string> <string name="simple_archive">Archive</string> <string name="simple_unassigned">Unassigned</string> + <string name="hint_error_appeared">An error appeared</string> <string name="edit_board">Edit board</string> <string name="archive_board">Archive board</string> @@ -71,6 +73,10 @@ <string name="about_license_tab_title">License</string> <string name="seconds_ago">seconds ago</string> <string name="edit">Edit</string> + <!-- After specifying the title of a new card, save it and then directly start it in edit mode --> + <string name="save_and_edit">@string/edit</string> + <!-- After specifying the title of a new card, save it and return to the list of cards --> + <string name="save_and_close">@string/simple_save</string> <string name="label_labels">Select Tags</string> <string name="label_description">Description</string> <string name="hint_assign_people">Assign users</string> @@ -174,7 +180,7 @@ <string name="hours_6">6 hours</string> <string name="action_card_move">Move card</string> <string name="action_card_move_title">Move %1$s</string> - <string name="title_is_mandatory">Title is mandatory</string> + <string name="title_is_mandatory">Title is required</string> <string name="provide_at_least_a_title_or_description">Provide at least a title or description</string> <string name="welcome_text">Welcome to %1$s</string> <string name="maintenance_mode_explanation">The server %1$s is currently in maintenance mode. Please contact your administrator or try later again.</string> @@ -341,6 +347,6 @@ <string name="account_imported">Account imported</string> <string name="simple_search">Search</string> <!-- Label for a title input field that is required to be filled out --> - <string name="title_mandatory">Title (mandatory)</string> + <string name="title_mandatory">Title (required)</string> <string name="saving_new_card">Saving new card…</string> </resources> diff --git a/app/src/main/res/xml/searchable.xml b/app/src/main/res/xml/searchable.xml index 47128864a..cbef62706 100644 --- a/app/src/main/res/xml/searchable.xml +++ b/app/src/main/res/xml/searchable.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android" - android:hint="Search deck" - android:label="@string/app_name"></searchable>
\ No newline at end of file + android:hint="@string/hint_search_deck" + android:label="@string/app_name"></searchable> |