diff options
39 files changed, 30 insertions, 1067 deletions
diff --git a/app/build.gradle b/app/build.gradle index 87e44d2b0..cb58fa9d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -72,12 +72,11 @@ dependencies { def lifecycleVersion = "2.6.2" def roomVersion = "2.6.1" def glideVersion = "4.16.0" - def nextcloudCommonsVersion = "1.9.0" - def androidCommonsVersion = "0.4.0" + def nextcloudCommonsVersion = "2.0.0" + def androidCommonsVersion = "1.0.0" implementation project(path: ':cross-tab-drag-and-drop') implementation project(path: ':tab-layout-helper') - implementation project(path: ':reactive-livedata') coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' @@ -114,6 +113,7 @@ dependencies { } implementation "com.github.stefan-niedermann.android-commons:util:$androidCommonsVersion" implementation "com.github.stefan-niedermann.android-commons:shared-preferences:$androidCommonsVersion" + implementation "com.github.stefan-niedermann.android-commons:reactive-livedata:$androidCommonsVersion" // Custom Date / Time Picker for branding support implementation 'com.wdullaer:materialdatetimepicker:4.2.3' @@ -143,3 +143,8 @@ dependencies { testImplementation 'androidx.test:core:1.5.0' testImplementation 'androidx.arch.core:core-testing:2.2.0' } +configurations.all { + resolutionStrategy { + force "com.github.stefan-niedermann.android-commons:util:new-util-api-4-SNAPSHOT" + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/database/migration/Migration_20_21.java b/app/src/main/java/it/niedermann/nextcloud/deck/database/migration/Migration_20_21.java index 4ac1b8f93..b54d3b5d6 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/database/migration/Migration_20_21.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/database/migration/Migration_20_21.java @@ -33,8 +33,8 @@ public class Migration_20_21 extends Migration { @ColorInt int color1; @ColorInt int color2; try { - color1 = Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(colorAsString1)); - color2 = Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(colorAsString2)); + color1 = Color.parseColor(ColorUtil.formatColorToParsableHexString(colorAsString1)); + color2 = Color.parseColor(ColorUtil.formatColorToParsableHexString(colorAsString2)); } catch (Exception e) { color1 = Color.GRAY; color2 = Color.GRAY; @@ -64,7 +64,7 @@ public class Migration_20_21 extends Migration { @ColorInt int color1; try { - color1 = Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(colorAsString1)); + color1 = Color.parseColor(ColorUtil.formatColorToParsableHexString(colorAsString1)); } catch (Exception e) { color1 = Color.GRAY; } @@ -98,7 +98,7 @@ public class Migration_20_21 extends Migration { @ColorInt int color1; try { - color1 = Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(colorAsString1)); + color1 = Color.parseColor(ColorUtil.formatColorToParsableHexString(colorAsString1)); } catch (Exception e) { color1 = Color.GRAY; } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java index 317557a61..b2fba2063 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java @@ -97,7 +97,7 @@ public class Board extends AbstractRemoteEntity implements Serializable { public void setColor(String color) { try { - setColor(Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(color))); + setColor(Color.parseColor(ColorUtil.formatColorToParsableHexString(color))); } catch (Exception e) { DeckLog.logError(e); setColor(Color.GRAY); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Label.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Label.java index b065f411c..4555faccc 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Label.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Label.java @@ -73,7 +73,7 @@ public class Label extends AbstractRemoteEntity implements Serializable { public void setColor(String color) { try { - setColor(Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(color))); + setColor(Color.parseColor(ColorUtil.formatColorToParsableHexString(color))); } catch (Exception e) { DeckLog.logError(e); setColor(Color.GRAY); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/JsonToEntityParser.java b/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/JsonToEntityParser.java index 5c2a83dff..26327890c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/JsonToEntityParser.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/JsonToEntityParser.java @@ -585,7 +585,7 @@ public class JsonToEntityParser { String rawString = getNullAsEmptyString(element.get(field)); try { if (!rawString.trim().isEmpty()) { - String colorAsString = ColorUtil.INSTANCE.formatColorToParsableHexString(rawString); + String colorAsString = ColorUtil.formatColorToParsableHexString(rawString); return Color.parseColor(colorAsString); } } catch (Exception e) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/json/JsonColorSerializer.java b/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/json/JsonColorSerializer.java index 635344d0b..0855ef71e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/json/JsonColorSerializer.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/remote/api/json/JsonColorSerializer.java @@ -14,7 +14,7 @@ public class JsonColorSerializer extends TypeAdapter<Integer> { if (value == null) { out.nullValue(); } else { - out.value(ColorUtil.INSTANCE.intColorToHexString(value)); + out.value(ColorUtil.intColorToHexString(value)); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsViewHolder.java index 381a290e6..7a4d1a193 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsViewHolder.java @@ -23,7 +23,7 @@ public class ManageLabelsViewHolder extends RecyclerView.ViewHolder { binding.label.setText(label.getTitle()); final int labelColor = label.getColor(); binding.label.setChipBackgroundColor(ColorStateList.valueOf(labelColor)); - final int color = ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(labelColor); + final int color = ColorUtil.getForegroundColorForBackgroundColor(labelColor); binding.label.setTextColor(color); binding.delete.setOnClickListener((v) -> listener.requestDelete(label)); binding.editText.setOnClickListener((v) -> listener.requestEdit(label)); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/LabelAutoCompleteAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/LabelAutoCompleteAdapter.java index 0af489781..0f0b91b6c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/LabelAutoCompleteAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/LabelAutoCompleteAdapter.java @@ -98,7 +98,7 @@ public class LabelAutoCompleteAdapter extends AutoCompleteAdapter<Label> { final var label = getItem(position); final int labelColor = label.getColor(); - final int color = ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(labelColor); + final int color = ColorUtil.getForegroundColorForBackgroundColor(labelColor); if (label.getLocalId() == null) { binding.label.setText(String.format(context.getString(R.string.label_add, label.getTitle()))); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityViewHolder.java index f78edd3f7..fd1cf6115 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/activities/CardActivityViewHolder.java @@ -32,7 +32,7 @@ public class CardActivityViewHolder extends RecyclerView.ViewHolder { itemView.setOnClickListener(View::showContextMenu); itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> { inflater.inflate(R.menu.activity_menu, menu); - menu.findItem(android.R.id.copy).setOnMenuItemClickListener(item -> ClipboardUtil.INSTANCE.copyToClipboard(context, activity.getSubject())); + menu.findItem(android.R.id.copy).setOnMenuItemClickListener(item -> ClipboardUtil.copyToClipboard(context, activity.getSubject())); }); final var type = ActivityType.findById(activity.getType()); setImageResource(binding.type, type); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentViewHolder.java index 7b00f2a84..977035940 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/AttachmentViewHolder.java @@ -47,7 +47,7 @@ public abstract class AttachmentViewHolder extends RecyclerView.ViewHolder { menu.findItem(android.R.id.copyUrl).setVisible(false); } else { menu.findItem(android.R.id.copyUrl).setVisible(true); - menu.findItem(android.R.id.copyUrl).setOnMenuItemClickListener(item -> ClipboardUtil.INSTANCE.copyToClipboard(itemView.getContext(), attachment.getFilename(), attachmentUri)); + menu.findItem(android.R.id.copyUrl).setOnMenuItemClickListener(item -> ClipboardUtil.copyToClipboard(itemView.getContext(), attachment.getFilename(), attachmentUri)); } }); } 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 7a4df435f..37e9497e4 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 @@ -61,7 +61,7 @@ public class ItemCommentViewHolder extends RecyclerView.ViewHolder { 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())); + menu.findItem(android.R.id.copy).setOnMenuItemClickListener(item -> ClipboardUtil.copyToClipboard(itemView.getContext(), comment.getComment().getMessage())); final var replyMenuItem = menu.findItem(R.id.reply); if (comment.getStatusEnum() != DBStatus.LOCAL_EDITED && account.getServerDeckVersionAsObject().supportsCommentsReplies()) { replyMenuItem.setOnMenuItemClickListener(item -> { 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 d86f9361a..1c1f737a9 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 @@ -278,7 +278,7 @@ public class CardDetailsFragment extends Fragment implements CardDueDateView.Due try { final int labelColor = label.getColor(); chip.setChipBackgroundColor(ColorStateList.valueOf(labelColor)); - final int color = ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(labelColor); + final int color = ColorUtil.getForegroundColorForBackgroundColor(labelColor); chip.setTextColor(color); if (chip.getCloseIcon() != null) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java index 0e558fb85..b6fd5a484 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java @@ -37,14 +37,14 @@ public class ExceptionActivity extends AppCompatActivity { } final var adapter = new TipsAdapter(this::startActivity); - final String debugInfo = "Full Crash:\n\n" + ExceptionUtil.INSTANCE.getDebugInfos(this, throwable, BuildConfig.FLAVOR); + final String debugInfo = "Full Crash:\n\n" + ExceptionUtil.getDebugInfos(this, throwable, BuildConfig.FLAVOR); binding.tips.setAdapter(adapter); binding.tips.setNestedScrollingEnabled(false); binding.toolbar.setTitle(R.string.error); binding.message.setText(throwable.getMessage()); binding.stacktrace.setText(debugInfo); - binding.copy.setOnClickListener((v) -> ClipboardUtil.INSTANCE.copyToClipboard(this, getString(R.string.simple_exception), "```\n" + debugInfo + "\n```")); + binding.copy.setOnClickListener((v) -> ClipboardUtil.copyToClipboard(this, getString(R.string.simple_exception), "```\n" + debugInfo + "\n```")); binding.close.setOnClickListener((v) -> finish()); final var utils = ThemeUtils.defaultBrand(this); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java index a69ddf80e..54fa0912d 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java @@ -53,7 +53,7 @@ public class ExceptionDialogFragment extends AppCompatDialogFragment { final var adapter = new TipsAdapter((actionIntent) -> requireActivity().startActivity(actionIntent)); - final String debugInfos = ExceptionUtil.INSTANCE.getDebugInfos(requireContext(), throwable, BuildConfig.FLAVOR, account == null ? null : account.getServerDeckVersion()); + final String debugInfos = ExceptionUtil.getDebugInfos(requireContext(), throwable, BuildConfig.FLAVOR, account == null ? null : account.getServerDeckVersion()); binding.tips.setAdapter(adapter); binding.stacktrace.setText(debugInfos); @@ -66,7 +66,7 @@ public class ExceptionDialogFragment extends AppCompatDialogFragment { .setView(binding.getRoot()) .setTitle(R.string.error_dialog_title) .setPositiveButton(android.R.string.copy, (a, b) -> { - ClipboardUtil.INSTANCE.copyToClipboard(requireContext(), getString(R.string.simple_exception), "```\n" + debugInfos + "\n```"); + ClipboardUtil.copyToClipboard(requireContext(), getString(R.string.simple_exception), "```\n" + debugInfos + "\n```"); a.dismiss(); }) .setNegativeButton(R.string.simple_close, null) diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsAdapter.java index 0a8dadfa2..ef8ce7c4d 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterLabelsAdapter.java @@ -86,7 +86,7 @@ public class FilterLabelsAdapter extends RecyclerView.Adapter<FilterLabelsAdapte binding.label.setText(label.getTitle()); final int labelColor = label.getColor(); binding.label.setChipBackgroundColor(ColorStateList.valueOf(labelColor)); - final int textColor = ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(labelColor); + final int textColor = ColorUtil.getForegroundColorForBackgroundColor(labelColor); binding.label.setTextColor(textColor); itemView.setSelected(selectedLabels.contains(label)); applyTheme(color); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/main/MainActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/main/MainActivity.java index e6d4693e0..4388d0ae3 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/main/MainActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/main/MainActivity.java @@ -520,7 +520,7 @@ public class MainActivity extends AppCompatActivity implements DeleteStackListen utils.deck.themeEmptyContentView(binding.emptyContentViewBoards); utils.platform.colorNavigationView(binding.navigationView, false); - @ColorInt final int headerTextColor = ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(accountColor); + @ColorInt final int headerTextColor = ColorUtil.getForegroundColorForBackgroundColor(accountColor); headerBinding.headerView.setBackgroundColor(accountColor); headerBinding.appName.setTextColor(headerTextColor); DrawableCompat.setTint(headerBinding.logo.getDrawable(), headerTextColor); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java index c0ab59e75..95fffe567 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java @@ -70,7 +70,7 @@ public class ShareProgressDialogFragment extends ThemedDialogFragment { binding.errorReportButton.setOnClickListener((v) -> { final StringBuilder debugInfos = new StringBuilder(exceptionsCount + " attachments failed to upload:"); for (Throwable t : exceptions) { - debugInfos.append(ExceptionUtil.INSTANCE.getDebugInfos(requireContext(), t, BuildConfig.FLAVOR)); + debugInfos.append(ExceptionUtil.getDebugInfos(requireContext(), t, BuildConfig.FLAVOR)); } ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException(debugInfos.toString()), null) .show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName()); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/labelchip/LabelChip.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/labelchip/LabelChip.java index d69ff2898..cd6a63a3d 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/labelchip/LabelChip.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/labelchip/LabelChip.java @@ -45,7 +45,7 @@ public class LabelChip extends Chip { int labelColor = label.getColor(); final var colorStateList = ColorStateList.valueOf(labelColor); setChipBackgroundColor(colorStateList); - setTextColor(ColorUtil.INSTANCE.getForegroundColorForBackgroundColor(labelColor)); + setTextColor(ColorUtil.getForegroundColorForBackgroundColor(labelColor)); } catch (IllegalArgumentException e) { DeckLog.logError(e); } diff --git a/reactive-livedata/build.gradle b/reactive-livedata/build.gradle deleted file mode 100644 index c18feca69..000000000 --- a/reactive-livedata/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdk 34 - namespace 'it.niedermann.android.reactivelivedata' - - defaultConfig { - minSdk 22 - targetSdk 34 - } - - compileOptions { - coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } -} - -dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' - - implementation "androidx.lifecycle:lifecycle-livedata:2.7.0" - implementation 'androidx.core:core:1.12.0' - - testImplementation 'junit:junit:4.13.2' - testImplementation 'org.robolectric:robolectric:4.11.1' - testImplementation 'androidx.test:core:1.5.0' - testImplementation 'androidx.arch.core:core-testing:2.2.0' -} diff --git a/reactive-livedata/src/main/AndroidManifest.xml b/reactive-livedata/src/main/AndroidManifest.xml deleted file mode 100644 index cc947c567..000000000 --- a/reactive-livedata/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ -<manifest /> diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/ReactiveLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/ReactiveLiveData.java deleted file mode 100644 index 664004bba..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/ReactiveLiveData.java +++ /dev/null @@ -1,217 +0,0 @@ -package it.niedermann.android.reactivelivedata; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.arch.core.util.Function; -import androidx.core.util.Consumer; -import androidx.core.util.Pair; -import androidx.core.util.Predicate; -import androidx.core.util.Supplier; -import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MediatorLiveData; -import androidx.lifecycle.Observer; -import androidx.lifecycle.Transformations; - -import java.time.temporal.ChronoUnit; -import java.util.concurrent.ExecutorService; - -import it.niedermann.android.reactivelivedata.combinator.DoubleCombinatorLiveData; -import it.niedermann.android.reactivelivedata.combinator.TripleCombinatorLiveData; -import it.niedermann.android.reactivelivedata.debounce.DebounceLiveData; -import it.niedermann.android.reactivelivedata.distinct.DistinctUntilChangedLiveData; -import it.niedermann.android.reactivelivedata.filter.FilterLiveData; -import it.niedermann.android.reactivelivedata.flatmap.FlatMapLiveData; -import it.niedermann.android.reactivelivedata.map.MapLiveData; -import it.niedermann.android.reactivelivedata.merge.MergeLiveData; -import it.niedermann.android.reactivelivedata.take.TakeLiveData; -import it.niedermann.android.reactivelivedata.tap.TapLiveData; -import kotlin.Triple; -import kotlin.jvm.functions.Function1; - -/** - * @see ReactiveLiveDataBuilder - */ -public class ReactiveLiveData<T> extends MediatorLiveData<T> implements ReactiveLiveDataBuilder<T> { - - public ReactiveLiveData(@Nullable LiveData<T> source) { - if (source == null) { - setValue(null); - } else { - addSource(source, this::setValue); - } - } - - public ReactiveLiveData(@NonNull T value) { - setValue(value); - } - - public ReactiveLiveData() { - super(); - } - - /** - * Observe without getting notified about the emitted values. - */ - public void observe(@NonNull LifecycleOwner owner) { - super.observe(owner, val -> { - // Nothing to do… - }); - } - - /** - * Observe without getting getting the emitted value. - */ - public void observe(@NonNull LifecycleOwner owner, @NonNull Runnable runnable) { - super.observe(owner, val -> runnable.run()); - } - - /** - * Cancel observation directly after one value has been emitted. - */ - public void observeOnce(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { - final var internalObserver = new Observer<T>() { - @Override - public void onChanged(T result) { - removeObserver(this); - observer.onChanged(result); - } - }; - - observe(owner, internalObserver); - } - - /** - * @see Transformations#map(LiveData, Function1) - */ - @NonNull - @Override - public <Y> ReactiveLiveData<Y> map(@NonNull Function1<T, Y> mapFunction) { - return new MapLiveData<>(this, mapFunction); - } - - /** - * @see #map(Function1) but the mapFunction will be executed on the given executor - */ - public <Y> ReactiveLiveData<Y> map(@NonNull Function1<T, Y> mapFunction, @NonNull ExecutorService executor) { - return new MapLiveData<>(this, mapFunction, executor); - } - - /** - * @see Transformations#switchMap(LiveData, Function1) - */ - @NonNull - @Override - public <Y> ReactiveLiveData<Y> flatMap(@NonNull Function1<T, LiveData<Y>> flatMapFunction) { - return new FlatMapLiveData<>(this, flatMapFunction); - } - - @NonNull - @Override - public <Y> ReactiveLiveData<Y> flatMap(@NonNull Supplier<LiveData<Y>> switchMapSupplier) { - return new FlatMapLiveData<>(this, switchMapSupplier); - } - - /** - * @see Transformations#distinctUntilChanged(LiveData) - */ - @NonNull - @Override - public ReactiveLiveData<T> distinctUntilChanged() { - return new DistinctUntilChangedLiveData<>(this); - } - - @NonNull - public ReactiveLiveData<T> filter(@NonNull Predicate<T> predicate) { - return new FilterLiveData<>(this, predicate); - } - - @NonNull - @Override - public ReactiveLiveData<T> filter(@NonNull Supplier<Boolean> supplier) { - return new FilterLiveData<>(this, supplier); - } - - @NonNull - @Override - public ReactiveLiveData<T> tap(@NonNull Consumer<T> consumer) { - return new TapLiveData<>(this, consumer); - } - - @NonNull - @Override - public ReactiveLiveData<T> tap(@NonNull Runnable runnable) { - return new TapLiveData<>(this, runnable); - } - - /** - * @see #tap(Consumer) but the tap consumer will be executed on the given executor - */ - public ReactiveLiveData<T> tap(@NonNull Consumer<T> consumer, @NonNull ExecutorService executor) { - return new TapLiveData<>(this, consumer, executor); - } - - public ReactiveLiveData<T> tap(@NonNull Runnable runnable, @NonNull ExecutorService executor) { - return new TapLiveData<>(this, runnable, executor); - } - - @NonNull - @Override - public ReactiveLiveData<T> merge(@NonNull Supplier<LiveData<T>> secondSource) { - return new MergeLiveData<>(this, secondSource); - } - - @NonNull - @Override - public ReactiveLiveData<T> take(int limit) { - return new TakeLiveData<>(this, limit); - } - - @NonNull - @Override - public <Y> ReactiveLiveData<Pair<T, Y>> combineWith(@NonNull Function<T, LiveData<Y>> secondSourceFunction) { - return new DoubleCombinatorLiveData<>(this, secondSourceFunction); - } - - @NonNull - @Override - public <Y> ReactiveLiveData<Pair<T, Y>> combineWith(@NonNull Supplier<LiveData<Y>> secondSourceSupplier) { - return new DoubleCombinatorLiveData<>(this, secondSourceSupplier); - } - - @NonNull - @Override - public <Y, Z> ReactiveLiveData<Triple<T, Y, Z>> combineWith(@NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Function<T, LiveData<Z>> thirdSourceFunction) { - return new TripleCombinatorLiveData<>(this, secondSourceFunction, thirdSourceFunction); - } - - @NonNull - @Override - public <Y, Z> ReactiveLiveData<Triple<T, Y, Z>> combineWith(@NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Supplier<LiveData<Z>> thirdSourceSupplier) { - return new TripleCombinatorLiveData<>(this, secondSourceFunction, thirdSourceSupplier); - } - - @NonNull - @Override - public <Y, Z> ReactiveLiveData<Triple<T, Y, Z>> combineWith(@NonNull Supplier<LiveData<Y>> secondSourceSupplier, @NonNull Function<T, LiveData<Z>> thirdSourceFunction) { - return new TripleCombinatorLiveData<>(this, secondSourceSupplier, thirdSourceFunction); - } - - @NonNull - @Override - public <Y, Z> ReactiveLiveData<Triple<T, Y, Z>> combineWith(@NonNull Supplier<LiveData<Y>> secondSourceSupplier, @NonNull Supplier<LiveData<Z>> thirdSourceSupplier) { - return new TripleCombinatorLiveData<>(this, secondSourceSupplier, thirdSourceSupplier); - } - - @NonNull - @Override - public ReactiveLiveData<T> debounce(long timeout, @NonNull ChronoUnit timeUnit) { - return new DebounceLiveData<>(this, timeout, timeUnit); - } - - @NonNull - @Override - public ReactiveLiveData<T> debounce(long timeout) { - return new DebounceLiveData<>(this, timeout); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/ReactiveLiveDataBuilder.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/ReactiveLiveDataBuilder.java deleted file mode 100644 index dc498a928..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/ReactiveLiveDataBuilder.java +++ /dev/null @@ -1,131 +0,0 @@ -package it.niedermann.android.reactivelivedata; - -import androidx.annotation.NonNull; -import androidx.arch.core.util.Function; -import androidx.core.util.Consumer; -import androidx.core.util.Pair; -import androidx.core.util.Predicate; -import androidx.core.util.Supplier; -import androidx.lifecycle.LiveData; - -import java.time.temporal.ChronoUnit; -import java.util.concurrent.TimeUnit; - -import kotlin.Triple; -import kotlin.jvm.functions.Function1; - -/** - * Partial implementation of <a href="https://reactivex.io/documentation/operators.html">ReactiveX</a> features - */ -public interface ReactiveLiveDataBuilder<T> { - - /** - * @see <a href="https://reactivex.io/documentation/operators/map.html">ReactiveX#map</a> - */ - @NonNull - <Y> ReactiveLiveDataBuilder<Y> map(@NonNull Function1<T, Y> mapFunction); - - /** - * @see <a href="https://reactivex.io/documentation/operators/flatmap.html">ReactiveX#flatmap</a> - */ - @NonNull - <Y> ReactiveLiveDataBuilder<Y> flatMap(@NonNull Function1<T, LiveData<Y>> flatMapFunction); - - /** - * @see #flatMap(Function1) - */ - @NonNull - <Y> ReactiveLiveDataBuilder<Y> flatMap(@NonNull Supplier<LiveData<Y>> flatMapSupplier); - - /** - * @see <a href="https://reactivex.io/documentation/operators/distinct.html">ReactiveX#distinct</a> - */ - @NonNull - ReactiveLiveDataBuilder<T> distinctUntilChanged(); - - /** - * @see <a href="https://reactivex.io/documentation/operators/filter.html">ReactiveX#filter</a> - */ - @NonNull - ReactiveLiveDataBuilder<T> filter(@NonNull Predicate<T> predicate); - - /** - * @see #filter(Predicate) - */ - @NonNull - ReactiveLiveDataBuilder<T> filter(@NonNull Supplier<Boolean> supplier); - - /** - * @see <a href="https://reactivex.io/documentation/operators/do.html">ReactiveX#do</a> - */ - @NonNull - ReactiveLiveDataBuilder<T> tap(@NonNull Consumer<T> consumer); - - /** - * @see #tap(Consumer) - */ - @NonNull - ReactiveLiveDataBuilder<T> tap(@NonNull Runnable runnable); - - /** - * @see <a href="https://reactivex.io/documentation/operators/merge.html">ReactiveX#merge</a> - */ - @NonNull - ReactiveLiveData<T> merge(@NonNull Supplier<LiveData<T>> liveData); - - /** - * @see <a href="https://reactivex.io/documentation/operators/take.html">ReactiveX#take</a> - */ - @NonNull - ReactiveLiveDataBuilder<T> take(int limit); - - /** - * @see <a href="https://reactivex.io/documentation/operators/combinelatest.html">ReactiveX#combinelatest</a> - */ - @NonNull - <Y> ReactiveLiveDataBuilder<Pair<T, Y>> combineWith(@NonNull Function<T, LiveData<Y>> secondSourceFunction); - - /** - * @see #combineWith(Function) - */ - @NonNull - <Y> ReactiveLiveDataBuilder<Pair<T, Y>> combineWith(@NonNull Supplier<LiveData<Y>> secondSourceSupplier); - - /** - * @see <a href="https://reactivex.io/documentation/operators/combinelatest.html">ReactiveX#combinelatest</a> - */ - @NonNull - <Y, Z> ReactiveLiveDataBuilder<Triple<T, Y, Z>> combineWith(@NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Function<T, LiveData<Z>> thirdSourceFunction); - - /** - * @see #combineWith(Function) - */ - @NonNull - <Y, Z> ReactiveLiveDataBuilder<Triple<T, Y, Z>> combineWith(@NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Supplier<LiveData<Z>> thirdSourceSupplier); - - /** - * @see #combineWith(Function) - */ - @NonNull - <Y, Z> ReactiveLiveDataBuilder<Triple<T, Y, Z>> combineWith(@NonNull Supplier<LiveData<Y>> secondSourceSupplier, @NonNull Function<T, LiveData<Z>> thirdSourceFunction); - - /** - * @see #combineWith(Function) - */ - @NonNull - <Y, Z> ReactiveLiveDataBuilder<Triple<T, Y, Z>> combineWith(@NonNull Supplier<LiveData<Y>> secondSourceSupplier, @NonNull Supplier<LiveData<Z>> thirdSourceSupplier); - - /** - * @see <a href="https://reactivex.io/documentation/operators/debounce.html">ReactiveX#debounce</a>> - */ - @NonNull - ReactiveLiveDataBuilder<T> debounce(long timeout, @NonNull ChronoUnit timeUnit); - - /** - * @param timeout defaults to {@link TimeUnit#MILLISECONDS} - * - * @see #debounce(long, ChronoUnit) - */ - @NonNull - ReactiveLiveDataBuilder<T> debounce(long timeout); -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/DoubleCombinatorLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/DoubleCombinatorLiveData.java deleted file mode 100644 index 63c704546..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/DoubleCombinatorLiveData.java +++ /dev/null @@ -1,20 +0,0 @@ -package it.niedermann.android.reactivelivedata.combinator; - -import androidx.annotation.NonNull; -import androidx.arch.core.util.Function; -import androidx.core.util.Pair; -import androidx.core.util.Supplier; -import androidx.lifecycle.LiveData; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; - -public class DoubleCombinatorLiveData<T, Y> extends ReactiveLiveData<Pair<T, Y>> { - - public DoubleCombinatorLiveData(@NonNull LiveData<T> source, @NonNull Supplier<LiveData<Y>> secondSourceSupplier) { - this(source, val -> secondSourceSupplier.get()); - } - - public DoubleCombinatorLiveData(@NonNull LiveData<T> source, @NonNull Function<T, LiveData<Y>> secondSourceFunction) { - addSource(source, new DoubleCombinatorObserver<>(this, secondSourceFunction)); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/DoubleCombinatorObserver.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/DoubleCombinatorObserver.java deleted file mode 100644 index 18c2affbb..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/DoubleCombinatorObserver.java +++ /dev/null @@ -1,45 +0,0 @@ -package it.niedermann.android.reactivelivedata.combinator; - -import androidx.annotation.NonNull; -import androidx.arch.core.util.Function; -import androidx.core.util.Pair; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MediatorLiveData; -import androidx.lifecycle.Observer; - -class DoubleCombinatorObserver<T, Y> implements Observer<T> { - private final MediatorLiveData<Pair<T, Y>> mediator; - private final Function<T, LiveData<Y>> secondSourceFunction; - private T value1; - private Y value2; - - private LiveData<Y> secondSource; - - private boolean value1emitted = false; - private boolean value2emitted = false; - - public DoubleCombinatorObserver(@NonNull MediatorLiveData<Pair<T, Y>> mediator, @NonNull Function<T, LiveData<Y>> secondSourceFunction) { - this.mediator = mediator; - this.secondSourceFunction = secondSourceFunction; - } - - @Override - public void onChanged(T emittedValue1) { - value1 = emittedValue1; - value1emitted = true; - if (value2emitted) { - mediator.setValue(new Pair<>(value1, value2)); - } - - if (secondSource == null) { - secondSource = secondSourceFunction.apply(emittedValue1); - mediator.addSource(secondSource, val2 -> { - value2 = val2; - value2emitted = true; - if (value1emitted) { - mediator.setValue(new Pair<>(value1, value2)); - } - }); - } - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/TripleCombinatorLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/TripleCombinatorLiveData.java deleted file mode 100644 index de0353c42..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/TripleCombinatorLiveData.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.niedermann.android.reactivelivedata.combinator; - -import androidx.annotation.NonNull; -import androidx.arch.core.util.Function; -import androidx.core.util.Supplier; -import androidx.lifecycle.LiveData; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; -import kotlin.Triple; - -public class TripleCombinatorLiveData<T, Y, Z> extends ReactiveLiveData<Triple<T, Y, Z>> { - - public TripleCombinatorLiveData(@NonNull LiveData<T> source, @NonNull Supplier<LiveData<Y>> secondSourceSupplier, @NonNull Supplier<LiveData<Z>> thirdSourceSupplier) { - this(source, val -> secondSourceSupplier.get(), val -> thirdSourceSupplier.get()); - } - - public TripleCombinatorLiveData(@NonNull LiveData<T> source, @NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Supplier<LiveData<Z>> thirdSourceSupplier) { - this(source, secondSourceFunction, val -> thirdSourceSupplier.get()); - } - - public TripleCombinatorLiveData(@NonNull LiveData<T> source, @NonNull Supplier<LiveData<Y>> secondSourceSupplier, @NonNull Function<T, LiveData<Z>> thirdSourceFunction) { - this(source, val -> secondSourceSupplier.get(), thirdSourceFunction); - } - - public TripleCombinatorLiveData(@NonNull LiveData<T> source, @NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Function<T, LiveData<Z>> thirdSourceFunction) { - addSource(source, new TripleCombinatorObserver<>(this, secondSourceFunction, thirdSourceFunction)); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/TripleCombinatorObserver.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/TripleCombinatorObserver.java deleted file mode 100644 index f146fa9cc..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/combinator/TripleCombinatorObserver.java +++ /dev/null @@ -1,62 +0,0 @@ -package it.niedermann.android.reactivelivedata.combinator; - -import androidx.annotation.NonNull; -import androidx.arch.core.util.Function; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MediatorLiveData; -import androidx.lifecycle.Observer; - -import kotlin.Triple; - -class TripleCombinatorObserver<T, Y, Z> implements Observer<T> { - private final MediatorLiveData<Triple<T, Y, Z>> mediator; - private final Function<T, LiveData<Y>> secondSourceFunction; - private final Function<T, LiveData<Z>> thirdSourceFunction; - private T value1; - private Y value2; - private Z value3; - - private LiveData<Y> secondSource; - private LiveData<Z> thirdSource; - - private boolean value1emitted = false; - private boolean value2emitted = false; - private boolean value3emitted = false; - - public TripleCombinatorObserver(@NonNull MediatorLiveData<Triple<T, Y, Z>> mediator, @NonNull Function<T, LiveData<Y>> secondSourceFunction, @NonNull Function<T, LiveData<Z>> thirdSourceFunction) { - this.mediator = mediator; - this.secondSourceFunction = secondSourceFunction; - this.thirdSourceFunction = thirdSourceFunction; - } - - @Override - public void onChanged(T emittedValue1) { - value1 = emittedValue1; - value1emitted = true; - if (value2emitted && value3emitted) { - mediator.setValue(new Triple<>(value1, value2, value3)); - } - - if (secondSource == null) { - secondSource = secondSourceFunction.apply(emittedValue1); - mediator.addSource(secondSource, val2 -> { - value2 = val2; - value2emitted = true; - if (value1emitted && value3emitted) { - mediator.setValue(new Triple<>(value1, value2, value3)); - } - }); - } - - if (thirdSource == null) { - thirdSource = thirdSourceFunction.apply(emittedValue1); - mediator.addSource(thirdSource, val3 -> { - value3 = val3; - value3emitted = true; - if (value1emitted && value2emitted) { - mediator.setValue(new Triple<>(value1, value2, value3)); - } - }); - } - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/debounce/DebounceLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/debounce/DebounceLiveData.java deleted file mode 100644 index 22a67d59a..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/debounce/DebounceLiveData.java +++ /dev/null @@ -1,19 +0,0 @@ -package it.niedermann.android.reactivelivedata.debounce; - -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; - -import java.time.temporal.ChronoUnit; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; - -public class DebounceLiveData<T> extends ReactiveLiveData<T> { - - public DebounceLiveData(@NonNull LiveData<T> source, long timeout) { - this(source, timeout, ChronoUnit.MILLIS); - } - - public DebounceLiveData(@NonNull LiveData<T> source, long timeout, @NonNull ChronoUnit timeUnit) { - addSource(source, new DebounceObserver<>(this, timeout, timeUnit)); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/debounce/DebounceObserver.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/debounce/DebounceObserver.java deleted file mode 100644 index 4d18cfa0e..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/debounce/DebounceObserver.java +++ /dev/null @@ -1,79 +0,0 @@ -package it.niedermann.android.reactivelivedata.debounce; - -import androidx.annotation.NonNull; -import androidx.lifecycle.MediatorLiveData; -import androidx.lifecycle.Observer; - -import java.time.Duration; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -class DebounceObserver<T> implements Observer<T> { - private final MediatorLiveData<T> mediator; - private final ExecutorService executor = Executors.newSingleThreadExecutor(); - private final long timeout; - private final ChronoUnit timeUnit; - private T lastEmittedValue = null; - private Instant lastEmit = Instant.now(); - private boolean firstEmit = true; - private Future<?> scheduledRecheck; - - public DebounceObserver(@NonNull MediatorLiveData<T> mediator, long timeout, @NonNull ChronoUnit timeUnit) { - this.mediator = mediator; - this.timeout = timeout; - this.timeUnit = timeUnit; - } - - @Override - public void onChanged(T value) { - final var now = Instant.now(); - - if (firstEmit) { - firstEmit = false; - emitValue(value, now); - } else { - if (lastEmit.isBefore(now.minus(timeout, timeUnit))) { - emitValue(value, now); - } else { - scheduleRecheck(value, getRemainingTimeToNextTimeout(now, lastEmit)); - } - } - } - - private void emitValue(T value, @NonNull Instant lastEmit) { - cancelScheduledRecheck(); - mediator.postValue(value); - this.lastEmit = lastEmit; - } - - private Duration getRemainingTimeToNextTimeout(@NonNull Instant now, @NonNull Instant lastEmit) { - final var millisSinceLastEmit = now.toEpochMilli() - lastEmit.toEpochMilli(); - final var millisToNextEmit = Duration.of(timeout, timeUnit).toMillis() - millisSinceLastEmit; - return Duration.ofMillis(millisToNextEmit); - } - - private void cancelScheduledRecheck() { - if (scheduledRecheck != null) { - scheduledRecheck.cancel(true); - } - } - - private synchronized void scheduleRecheck(T newValue, @NonNull Duration sleep) { - cancelScheduledRecheck(); - scheduledRecheck = executor.submit(() -> { - try { - Thread.sleep(sleep.toMillis()); - if (!Objects.equals(lastEmittedValue, newValue)) { - mediator.postValue(newValue); - lastEmittedValue = newValue; - } - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); - } -}
\ No newline at end of file diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/distinct/DistinctUntilChangedLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/distinct/DistinctUntilChangedLiveData.java deleted file mode 100644 index 6ec85ed85..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/distinct/DistinctUntilChangedLiveData.java +++ /dev/null @@ -1,14 +0,0 @@ -package it.niedermann.android.reactivelivedata.distinct; - -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.Transformations; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; - -public class DistinctUntilChangedLiveData<T> extends ReactiveLiveData<T> { - - public DistinctUntilChangedLiveData(@NonNull LiveData<T> source) { - super(Transformations.distinctUntilChanged(source)); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/filter/FilterLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/filter/FilterLiveData.java deleted file mode 100644 index fac27030f..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/filter/FilterLiveData.java +++ /dev/null @@ -1,23 +0,0 @@ -package it.niedermann.android.reactivelivedata.filter; - -import androidx.annotation.NonNull; -import androidx.core.util.Predicate; -import androidx.core.util.Supplier; -import androidx.lifecycle.LiveData; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; - -public class FilterLiveData<T> extends ReactiveLiveData<T> { - - public FilterLiveData(@NonNull LiveData<T> source, @NonNull Supplier<Boolean> supplier) { - this(source, val -> supplier.get()); - } - - public FilterLiveData(@NonNull LiveData<T> source, @NonNull Predicate<T> predicate) { - addSource(source, val -> { - if (predicate.test(val)) { - setValue(val); - } - }); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/flatmap/FlatMapLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/flatmap/FlatMapLiveData.java deleted file mode 100644 index 13593cb79..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/flatmap/FlatMapLiveData.java +++ /dev/null @@ -1,20 +0,0 @@ -package it.niedermann.android.reactivelivedata.flatmap; - -import androidx.annotation.NonNull; -import androidx.core.util.Supplier; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.Transformations; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; -import kotlin.jvm.functions.Function1; - -public class FlatMapLiveData<T, Y> extends ReactiveLiveData<Y> { - - public FlatMapLiveData(@NonNull LiveData<T> source, @NonNull Supplier<LiveData<Y>> switchMapSupplier) { - this(source, val -> switchMapSupplier.get()); - } - - public FlatMapLiveData(@NonNull LiveData<T> source, @NonNull Function1<T, LiveData<Y>> flatMapFunction) { - super(Transformations.switchMap(source, flatMapFunction)); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/map/MapLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/map/MapLiveData.java deleted file mode 100644 index a705b427b..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/map/MapLiveData.java +++ /dev/null @@ -1,21 +0,0 @@ -package it.niedermann.android.reactivelivedata.map; - -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.Transformations; - -import java.util.concurrent.ExecutorService; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; -import kotlin.jvm.functions.Function1; - -public class MapLiveData<T, Y> extends ReactiveLiveData<Y> { - - public MapLiveData(@NonNull LiveData<T> source, @NonNull Function1<T, Y> mapFunction) { - super(Transformations.map(source, mapFunction)); - } - - public MapLiveData(@NonNull LiveData<T> source, @NonNull Function1<T, Y> mapFunction, @NonNull ExecutorService executor) { - addSource(source, val -> executor.submit(() -> postValue(mapFunction.invoke(val)))); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/merge/MergeLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/merge/MergeLiveData.java deleted file mode 100644 index cc3c1ddd6..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/merge/MergeLiveData.java +++ /dev/null @@ -1,15 +0,0 @@ -package it.niedermann.android.reactivelivedata.merge; - -import androidx.annotation.NonNull; -import androidx.core.util.Supplier; -import androidx.lifecycle.LiveData; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; - -public class MergeLiveData<T> extends ReactiveLiveData<T> { - - public MergeLiveData(@NonNull LiveData<T> source, @NonNull Supplier<LiveData<T>> secondSource) { - addSource(source, this::setValue); - addSource(secondSource.get(), this::setValue); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/take/TakeLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/take/TakeLiveData.java deleted file mode 100644 index 0ca536db2..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/take/TakeLiveData.java +++ /dev/null @@ -1,13 +0,0 @@ -package it.niedermann.android.reactivelivedata.take; - -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; - -import it.niedermann.android.reactivelivedata.ReactiveLiveData; - -public class TakeLiveData<T> extends ReactiveLiveData<T> { - - public TakeLiveData(@NonNull LiveData<T> source, int limit) { - addSource(source, new TakeObserver<>(this, limit)); - } -} diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/take/TakeObserver.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/take/TakeObserver.java deleted file mode 100644 index 0f1f4e576..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/take/TakeObserver.java +++ /dev/null @@ -1,37 +0,0 @@ -package it.niedermann.android.reactivelivedata.take; - -import androidx.annotation.NonNull; -import androidx.lifecycle.MediatorLiveData; -import androidx.lifecycle.Observer; - -class TakeObserver<T> implements Observer<T> { - private final MediatorLiveData<T> mediator; - private final int limit; - private int counter = 0; - - public TakeObserver(@NonNull MediatorLiveData<T> mediator, int limit) { - if (limit == Integer.MAX_VALUE) { - throw new RuntimeException("limit must be lower than Integer.MAX_VALUE"); - } - - if (limit < 1) { - throw new RuntimeException("limit must be 1 or higher"); - } - - this.mediator = mediator; - this.limit = limit; - } - - @Override - public void onChanged(T value) { - if (counter < limit) { - mediator.setValue(value); - } - counter++; - - // Prevent integer overflow - if (counter == limit + 1) { - counter = limit; - } - } -}
\ No newline at end of file diff --git a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/tap/TapLiveData.java b/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/tap/TapLiveData.java deleted file mode 100644 index c9d08a98d..000000000 --- a/reactive-livedata/src/main/java/it/niedermann/android/reactivelivedata/tap/TapLiveData.java +++ /dev/null @@ -1,34 +0,0 @@ -package it.niedermann.android.reactivelivedata.tap; - -import androidx.annotation.NonNull; -import androidx.core.util.Consumer; -import androidx.lifecycle.LiveData; - -import java.util.concurrent.ExecutorService; - -import it.niedermann.android.reactivelivedata.map.MapLiveData; - -public class TapLiveData<T> extends MapLiveData<T, T> { - - public TapLiveData(@NonNull LiveData<T> source, @NonNull Runnable runnable) { - this(source, val -> runnable.run()); - } - - public TapLiveData(@NonNull LiveData<T> source, @NonNull Consumer<T> consumer) { - super(source, val -> { - consumer.accept(val); - return val; - }); - } - - public TapLiveData(@NonNull LiveData<T> source, @NonNull Runnable runnable, @NonNull ExecutorService executor) { - this(source, val -> runnable.run(), executor); - } - - public TapLiveData(@NonNull LiveData<T> source, @NonNull Consumer<T> consumer, @NonNull ExecutorService executor) { - super(source, val -> { - consumer.accept(val); - return val; - }, executor); - } -} diff --git a/reactive-livedata/src/test/java/it/niedermann/android/reactivelivedata/ReactiveLiveDataTest.java b/reactive-livedata/src/test/java/it/niedermann/android/reactivelivedata/ReactiveLiveDataTest.java deleted file mode 100644 index a644a8ccf..000000000 --- a/reactive-livedata/src/test/java/it/niedermann/android/reactivelivedata/ReactiveLiveDataTest.java +++ /dev/null @@ -1,188 +0,0 @@ -package it.niedermann.android.reactivelivedata; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; -import static it.niedermann.android.reactivelivedata.TestUtil.getOrAwaitValue; - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule; -import androidx.core.util.Pair; -import androidx.lifecycle.MutableLiveData; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import java.util.concurrent.TimeUnit; - -@RunWith(RobolectricTestRunner.class) -public class ReactiveLiveDataTest { - - @Rule - public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule(); - - @Test - public void filter() throws InterruptedException { - final var s1$ = new MutableLiveData<Integer>(); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .filter(val -> val < 2); - - s1$.postValue(1); - assertEquals(Integer.valueOf(1), getOrAwaitValue(reactive1$)); - - s1$.postValue(2); - assertEquals(Integer.valueOf(1), getOrAwaitValue(reactive1$)); - } - - @Test - public void map() throws InterruptedException { - final var s1$ = new MutableLiveData<Integer>(); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .map(val -> val * 2); - - s1$.postValue(1); - assertEquals(Integer.valueOf(2), getOrAwaitValue(reactive1$)); - - s1$.postValue(2); - assertEquals(Integer.valueOf(4), getOrAwaitValue(reactive1$)); - - s1$.postValue(3); - assertEquals(Integer.valueOf(6), getOrAwaitValue(reactive1$)); - } - - @Test - public void flatMap() throws InterruptedException { - final var s0$ = new MutableLiveData<Void>(null); - final var s1$ = new MutableLiveData<>("Foo"); - final var s2$ = new MutableLiveData<>("Bar"); - - final var reactive1$ = new ReactiveLiveData<>(s0$) - .flatMap(() -> s1$); - - final var reactive2$ = new ReactiveLiveData<>(s0$) - .flatMap(() -> s2$); - - assertEquals("Foo", getOrAwaitValue(reactive1$)); - assertEquals("Bar", getOrAwaitValue(reactive2$)); - } - - @Test - public void flatMap_chained() throws InterruptedException { - final var s0$ = new MutableLiveData<Void>(null); - final var s1$ = new MutableLiveData<>("Foo"); - final var s2$ = new MutableLiveData<>("Bar"); - final var s3$ = new MutableLiveData<>("Baz"); - - final var reactive1$ = new ReactiveLiveData<>(s0$) - .flatMap(() -> s1$) - .flatMap(val -> "Foo".equals(val) ? s2$ : s3$); - - assertEquals("Bar", getOrAwaitValue(reactive1$)); - - s1$.postValue("Qux"); - - assertEquals("Baz", getOrAwaitValue(reactive1$)); - } - - @Test - public void combineWith() throws InterruptedException { - final var s1$ = new MutableLiveData<>(5); - final var s2$ = new MutableLiveData<>("Foo"); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .combineWith(val -> s2$); - - assertEquals(new Pair<>(5, "Foo"), getOrAwaitValue(reactive1$)); - } - - @Test - public void merge() throws InterruptedException { - final var s1$ = new MutableLiveData<>(5); - final var s2$ = new MutableLiveData<>(9); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .merge(() -> s2$); - - assertEquals(Integer.valueOf(5), getOrAwaitValue(reactive1$)); - assertEquals(Integer.valueOf(9), getOrAwaitValue(reactive1$)); - } - - @Test - public void take() throws InterruptedException { - assertThrows(RuntimeException.class, () -> new ReactiveLiveData<>().take(Integer.MAX_VALUE)); - assertThrows(RuntimeException.class, () -> new ReactiveLiveData<>().take(0)); - - final var s1$ = new MutableLiveData<>(0); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .take(3); - - assertEquals(Integer.valueOf(0), getOrAwaitValue(reactive1$)); - - s1$.setValue(1); - assertEquals(Integer.valueOf(1), getOrAwaitValue(reactive1$)); - - s1$.setValue(2); - assertEquals(Integer.valueOf(2), getOrAwaitValue(reactive1$)); - - s1$.setValue(3); - assertEquals(Integer.valueOf(2), getOrAwaitValue(reactive1$)); - - s1$.setValue(4); - assertEquals(Integer.valueOf(2), getOrAwaitValue(reactive1$)); - } - - @Test - public void debounce() throws InterruptedException { - final var s1$ = new MutableLiveData<>(0); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .debounce(120); - - assertEquals(Integer.valueOf(0), getOrAwaitValue(reactive1$, 10, TimeUnit.MILLISECONDS)); - - for (int i = 1; i <= 6; i++) { - Thread.sleep(50); - s1$.setValue(i); - switch (i) { - case 1: - case 2: - assertEquals(Integer.valueOf(0), getOrAwaitValue(reactive1$, 10, TimeUnit.MILLISECONDS)); - break; - case 3: - case 4: - case 5: - assertEquals(Integer.valueOf(3), getOrAwaitValue(reactive1$, 10, TimeUnit.MILLISECONDS)); - break; - case 6: - assertEquals(Integer.valueOf(6), getOrAwaitValue(reactive1$, 10, TimeUnit.MILLISECONDS)); - break; - default: - throw new IllegalStateException(); - } - } - } - - @Test - public void debounce_shouldPickUpChangesAfterTheTimeoutDirectly() throws InterruptedException { - final var s1$ = new MutableLiveData<>(0); - - final var reactive1$ = new ReactiveLiveData<>(s1$) - .debounce(120); - - assertEquals(Integer.valueOf(0), getOrAwaitValue(reactive1$, 0, TimeUnit.MILLISECONDS)); - - Thread.sleep(50); - s1$.setValue(1); - assertEquals(Integer.valueOf(0), getOrAwaitValue(reactive1$, 0, TimeUnit.MILLISECONDS)); - - Thread.sleep(50); - s1$.setValue(2); - assertEquals(Integer.valueOf(0), getOrAwaitValue(reactive1$, 0, TimeUnit.MILLISECONDS)); - - Thread.sleep(50); - assertEquals(Integer.valueOf(2), getOrAwaitValue(reactive1$, 0, TimeUnit.MILLISECONDS)); - } -} diff --git a/reactive-livedata/src/test/java/it/niedermann/android/reactivelivedata/TestUtil.java b/reactive-livedata/src/test/java/it/niedermann/android/reactivelivedata/TestUtil.java deleted file mode 100644 index 8f47e15f7..000000000 --- a/reactive-livedata/src/test/java/it/niedermann/android/reactivelivedata/TestUtil.java +++ /dev/null @@ -1,45 +0,0 @@ -package it.niedermann.android.reactivelivedata; - -import androidx.annotation.Nullable; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.Observer; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class TestUtil { - - private TestUtil() { - // Util class - } - - /** - * @see #getOrAwaitValue(LiveData, long, TimeUnit) - */ - public static <T> T getOrAwaitValue(final LiveData<T> liveData) throws InterruptedException { - return getOrAwaitValue(liveData, 2, TimeUnit.SECONDS); - } - - /** - * @see <a href="https://gist.github.com/JoseAlcerreca/1e9ee05dcdd6a6a6fa1cbfc125559bba">Source</a> - */ - public static <T> T getOrAwaitValue(final LiveData<T> liveData, long timeout, TimeUnit unit) throws InterruptedException { - final var data = new Object[1]; - final var latch = new CountDownLatch(1); - final var observer = new Observer<T>() { - @Override - public void onChanged(@Nullable T o) { - data[0] = o; - latch.countDown(); - liveData.removeObserver(this); - } - }; - liveData.observeForever(observer); - // Don't wait indefinitely if the LiveData is not set. - if (!latch.await(timeout, unit)) { - throw new RuntimeException("LiveData value was never set."); - } - //noinspection unchecked - return (T) data[0]; - } -} diff --git a/settings.gradle b/settings.gradle index 6b84d234f..edf1d2bdb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,3 @@ include ':app' include ':cross-tab-drag-and-drop' include ':tab-layout-helper' -include ':reactive-livedata'
\ No newline at end of file |