diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/AvatarSelectionActivity.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/AvatarSelectionActivity.java index 0c0bcd6a5e..d2b965503a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/AvatarSelectionActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/AvatarSelectionActivity.java @@ -13,7 +13,6 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; -import androidx.lifecycle.LiveData; import org.signal.imageeditor.core.model.EditorModel; import org.thoughtcrime.securesms.R; @@ -22,13 +21,14 @@ import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.scribbles.ImageEditorFragment; -import org.thoughtcrime.securesms.util.DefaultValueLiveData; import org.thoughtcrime.securesms.util.MediaUtil; import java.io.FileDescriptor; import java.util.Collections; import java.util.Optional; +import io.reactivex.rxjava3.core.Flowable; + public class AvatarSelectionActivity extends AppCompatActivity implements CameraFragment.Controller, ImageEditorFragment.Controller, MediaGalleryFragment.Callbacks { private static final Point AVATAR_DIMENSIONS = new Point(AvatarHelper.AVATAR_DIMENSIONS, AvatarHelper.AVATAR_DIMENSIONS); @@ -131,8 +131,8 @@ public class AvatarSelectionActivity extends AppCompatActivity implements Camera } @Override - public @NonNull LiveData> getMostRecentMediaItem() { - return new DefaultValueLiveData<>(Optional.empty()); + public @NonNull Flowable> getMostRecentMediaItem() { + return Flowable.just(Optional.empty()); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/Camera1Fragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/Camera1Fragment.java index a17ab102a3..5b93b9d65c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/Camera1Fragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/Camera1Fragment.java @@ -27,7 +27,6 @@ import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.lifecycle.Observer; import com.bumptech.glide.Glide; import com.bumptech.glide.load.MultiTransformation; @@ -51,8 +50,8 @@ import org.thoughtcrime.securesms.util.Stopwatch; import org.thoughtcrime.securesms.util.TextSecurePreferences; import java.io.ByteArrayOutputStream; -import java.util.Optional; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.disposables.Disposable; /** @@ -75,8 +74,8 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment, private Camera1Controller.Properties properties; private RotationListener rotationListener; private Disposable rotationListenerDisposable; + private Disposable mostRecentItemDisposable = Disposable.disposed(); - private final Observer> thumbObserver = this::presentRecentItemThumbnail; private boolean isThumbAvailable; private boolean isMediaSelected; @@ -192,7 +191,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment, @Override public void onDestroyView() { super.onDestroyView(); - controller.getMostRecentMediaItem().removeObserver(thumbObserver); + mostRecentItemDisposable.dispose(); } @Override @@ -271,19 +270,13 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment, controller.onCameraError(); } - private void presentRecentItemThumbnail(Optional media) { - if (media == null) { - isThumbAvailable = false; - updateGalleryVisibility(); - return; - } - + private void presentRecentItemThumbnail(@Nullable Media media) { ImageView thumbnail = controlsContainer.findViewById(R.id.camera_gallery_button); - if (media.isPresent()) { + if (media != null) { thumbnail.setVisibility(View.VISIBLE); Glide.with(this) - .load(new DecryptableUri(media.get().getUri())) + .load(new DecryptableUri(media.getUri())) .centerCrop() .into(thumbnail); } else { @@ -291,7 +284,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment, thumbnail.setImageResource(0); } - isThumbAvailable = media.isPresent(); + isThumbAvailable = media != null; updateGalleryVisibility(); } @@ -331,8 +324,10 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment, View countButton = requireView().findViewById(R.id.camera_review_button); View toggleSpacer = requireView().findViewById(R.id.toggle_spacer); - controller.getMostRecentMediaItem().removeObserver(thumbObserver); - controller.getMostRecentMediaItem().observeForever(thumbObserver); + mostRecentItemDisposable.dispose(); + mostRecentItemDisposable = controller.getMostRecentMediaItem() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(item -> presentRecentItemThumbnail(item.orElse(null))); if (toggleSpacer != null) { if (Stories.isFeatureEnabled()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraFragment.java index 798764889f..e988a19373 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraFragment.java @@ -5,7 +5,6 @@ import android.content.res.Configuration; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.lifecycle.LiveData; import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil; import org.thoughtcrime.securesms.mms.MediaConstraints; @@ -13,6 +12,8 @@ import org.thoughtcrime.securesms.mms.MediaConstraints; import java.io.FileDescriptor; import java.util.Optional; +import io.reactivex.rxjava3.core.Flowable; + public interface CameraFragment { float PORTRAIT_ASPECT_RATIO = 9 / 16f; @@ -54,7 +55,7 @@ public interface CameraFragment { void onVideoCaptureError(); void onGalleryClicked(); void onCameraCountButtonClicked(); - @NonNull LiveData> getMostRecentMediaItem(); + @NonNull Flowable> getMostRecentMediaItem(); @NonNull MediaConstraints getMediaConstraints(); int getMaxVideoDuration(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java index ff10d59fe2..f6d61bc91c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java @@ -31,7 +31,6 @@ import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.view.PreviewView; import androidx.camera.view.SignalCameraView; import androidx.core.content.ContextCompat; -import androidx.lifecycle.Observer; import com.bumptech.glide.Glide; import com.bumptech.glide.util.Executors; @@ -57,7 +56,9 @@ import org.thoughtcrime.securesms.video.VideoUtil; import java.io.FileDescriptor; import java.io.IOException; -import java.util.Optional; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.disposables.Disposable; /** * Camera captured implemented using the CameraX SDK, which uses Camera2 under the hood. Should be @@ -74,8 +75,8 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { private Controller controller; private View selfieFlash; private MemoryFileDescriptor videoFileDescriptor; + private Disposable mostRecentItemDisposable = Disposable.disposed(); - private final Observer> thumbObserver = this::presentRecentItemThumbnail; private boolean isThumbAvailable; private boolean isMediaSelected; @@ -161,7 +162,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { @Override public void onDestroyView() { super.onDestroyView(); - controller.getMostRecentMediaItem().removeObserver(thumbObserver); + mostRecentItemDisposable.dispose(); closeVideoFileDescriptor(); requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } @@ -221,19 +222,13 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { initControls(); } - private void presentRecentItemThumbnail(Optional media) { - if (media == null) { - isThumbAvailable = false; - updateGalleryVisibility(); - return; - } - + private void presentRecentItemThumbnail(@Nullable Media media) { ImageView thumbnail = controlsContainer.findViewById(R.id.camera_gallery_button); - if (media.isPresent()) { + if (media != null) { thumbnail.setVisibility(View.VISIBLE); Glide.with(this) - .load(new DecryptableUri(media.get().getUri())) + .load(new DecryptableUri(media.getUri())) .centerCrop() .into(thumbnail); } else { @@ -241,7 +236,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { thumbnail.setImageResource(0); } - isThumbAvailable = media.isPresent(); + isThumbAvailable = media != null; updateGalleryVisibility(); } @@ -292,8 +287,10 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { } } - controller.getMostRecentMediaItem().removeObserver(thumbObserver); - controller.getMostRecentMediaItem().observeForever(thumbObserver); + mostRecentItemDisposable.dispose(); + mostRecentItemDisposable = controller.getMostRecentMediaItem() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(item -> presentRecentItemThumbnail(item.orElse(null))); selfieFlash = requireView().findViewById(R.id.camera_selfie_flash); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt index 5d255ed71f..276542097a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt @@ -6,9 +6,9 @@ import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.LiveData import androidx.navigation.fragment.findNavController import app.cash.exhaustive.Exhaustive +import io.reactivex.rxjava3.core.Flowable import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.mediasend.CameraFragment @@ -149,7 +149,7 @@ class MediaCaptureFragment : Fragment(R.layout.fragment_container), CameraFragme } } - override fun getMostRecentMediaItem(): LiveData> { + override fun getMostRecentMediaItem(): Flowable> { return viewModel.getMostRecentMedia() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureViewModel.kt index bb946b7866..40f201d544 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureViewModel.kt @@ -1,18 +1,18 @@ package org.thoughtcrime.securesms.mediasend.v2.capture import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import io.reactivex.rxjava3.core.Flowable import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.util.SingleLiveEvent -import org.thoughtcrime.securesms.util.livedata.Store +import org.thoughtcrime.securesms.util.rx.RxStore import java.io.FileDescriptor import java.util.Optional class MediaCaptureViewModel(private val repository: MediaCaptureRepository) : ViewModel() { - private val store: Store = Store(MediaCaptureState()) + private val store: RxStore = RxStore(MediaCaptureState()) private val internalEvents: SingleLiveEvent = SingleLiveEvent() @@ -34,8 +34,8 @@ class MediaCaptureViewModel(private val repository: MediaCaptureRepository) : Vi repository.renderVideoToMedia(fd, this::onMediaRendered, this::onMediaRenderFailed) } - fun getMostRecentMedia(): LiveData> { - return Transformations.map(store.stateLiveData) { Optional.ofNullable(it.mostRecentMedia) } + fun getMostRecentMedia(): Flowable> { + return store.stateFlowable.map { Optional.ofNullable(it.mostRecentMedia) } } private fun onMediaRendered(media: Media) {