mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Persist camera lens selection across sessions.
This commit is contained in:
@@ -46,6 +46,7 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
|
|||||||
private const val LAST_KEY_TRANSPARENCY_TIME = "misc.last_key_transparency_time"
|
private const val LAST_KEY_TRANSPARENCY_TIME = "misc.last_key_transparency_time"
|
||||||
private const val HAS_KEY_TRANSPARENCY_FAILURE = "misc.has_key_transparency_failure"
|
private const val HAS_KEY_TRANSPARENCY_FAILURE = "misc.has_key_transparency_failure"
|
||||||
private const val HAS_SEEN_KEY_TRANSPARENCY_FAILURE = "misc.has_seen_key_transparency_failure"
|
private const val HAS_SEEN_KEY_TRANSPARENCY_FAILURE = "misc.has_seen_key_transparency_failure"
|
||||||
|
private const val CAMERA_FACING_FRONT = "misc.camera_facing_front"
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onFirstEverAppLaunch() {
|
public override fun onFirstEverAppLaunch() {
|
||||||
@@ -309,4 +310,9 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
|
|||||||
* Whether you have seen the dialog on key transparency failure
|
* Whether you have seen the dialog on key transparency failure
|
||||||
*/
|
*/
|
||||||
var hasSeenKeyTransparencyFailure: Boolean by booleanValue(HAS_SEEN_KEY_TRANSPARENCY_FAILURE, false)
|
var hasSeenKeyTransparencyFailure: Boolean by booleanValue(HAS_SEEN_KEY_TRANSPARENCY_FAILURE, false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the preferred camera direction is front-facing.
|
||||||
|
*/
|
||||||
|
var isCameraFacingFront: Boolean by booleanValue(CAMERA_FACING_FRONT, true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import org.thoughtcrime.securesms.mediasend.v2.MediaAnimations;
|
|||||||
import org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton;
|
import org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton;
|
||||||
import org.signal.glide.decryptableuri.DecryptableUri;
|
import org.signal.glide.decryptableuri.DecryptableUri;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -107,7 +107,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
|
|||||||
|
|
||||||
display.getSize(displaySize);
|
display.getSize(displaySize);
|
||||||
|
|
||||||
camera = new Camera1Controller(TextSecurePreferences.getDirectCaptureCameraId(getContext()), displaySize.x, displaySize.y, this);
|
camera = new Camera1Controller(SignalStore.misc().isCameraFacingFront() ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK, displaySize.x, displaySize.y, this);
|
||||||
orderEnforcer = new OrderEnforcer<>(Stage.SURFACE_AVAILABLE, Stage.CAMERA_PROPERTIES_AVAILABLE);
|
orderEnforcer = new OrderEnforcer<>(Stage.SURFACE_AVAILABLE, Stage.CAMERA_PROPERTIES_AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +347,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
|
|||||||
flipButton.setVisibility(properties.getCameraCount() > 1 ? View.VISIBLE : View.GONE);
|
flipButton.setVisibility(properties.getCameraCount() > 1 ? View.VISIBLE : View.GONE);
|
||||||
flipButton.setOnClickListener(v -> {
|
flipButton.setOnClickListener(v -> {
|
||||||
int newCameraId = camera.flip();
|
int newCameraId = camera.flip();
|
||||||
TextSecurePreferences.setDirectCaptureCameraId(getContext(), newCameraId);
|
SignalStore.misc().setCameraFacingFront(newCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT);
|
||||||
|
|
||||||
Animation animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
|
Animation animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
|
||||||
animation.setDuration(200);
|
animation.setDuration(200);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.camera.core.CameraSelector
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
@@ -29,6 +30,7 @@ import androidx.compose.runtime.mutableIntStateOf
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -50,6 +52,7 @@ import org.signal.core.ui.BottomSheetUtil
|
|||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.mediasend.camerax.CameraXModePolicy
|
import org.thoughtcrime.securesms.mediasend.camerax.CameraXModePolicy
|
||||||
import org.thoughtcrime.securesms.permissions.PermissionDeniedBottomSheet.Companion.showPermissionFragment
|
import org.thoughtcrime.securesms.permissions.PermissionDeniedBottomSheet.Companion.showPermissionFragment
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
@@ -101,7 +104,6 @@ class CameraXFragment : ComposeFragment(), CameraFragment {
|
|||||||
private val isQrScanEnabled: Boolean
|
private val isQrScanEnabled: Boolean
|
||||||
get() = requireArguments().getBoolean(IS_QR_SCAN_ENABLED, false)
|
get() = requireArguments().getBoolean(IS_QR_SCAN_ENABLED, false)
|
||||||
|
|
||||||
// Compose state holders for HUD visibility
|
|
||||||
private var controlsVisible = mutableStateOf(true)
|
private var controlsVisible = mutableStateOf(true)
|
||||||
private var selectedMediaCount = mutableIntStateOf(0)
|
private var selectedMediaCount = mutableIntStateOf(0)
|
||||||
|
|
||||||
@@ -295,6 +297,22 @@ private fun CameraXScreen(
|
|||||||
val cameraState by cameraViewModel.state
|
val cameraState by cameraViewModel.state
|
||||||
var hasPermission by remember { mutableStateOf(hasCameraPermission()) }
|
var hasPermission by remember { mutableStateOf(hasCameraPermission()) }
|
||||||
|
|
||||||
|
LaunchedEffect(cameraViewModel) {
|
||||||
|
val lensFacing = if (SignalStore.misc.isCameraFacingFront) {
|
||||||
|
CameraSelector.LENS_FACING_FRONT
|
||||||
|
} else {
|
||||||
|
CameraSelector.LENS_FACING_BACK
|
||||||
|
}
|
||||||
|
cameraViewModel.setLensFacing(lensFacing)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(cameraViewModel) {
|
||||||
|
snapshotFlow { cameraState.lensFacing }
|
||||||
|
.collect { lensFacing ->
|
||||||
|
SignalStore.misc.isCameraFacingFront = lensFacing == CameraSelector.LENS_FACING_FRONT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
if (!hasPermission) {
|
if (!hasPermission) {
|
||||||
onCheckPermissions()
|
onCheckPermissions()
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.hardware.Camera.CameraInfo;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
@@ -88,7 +87,6 @@ public class TextSecurePreferences {
|
|||||||
|
|
||||||
public static final String SYSTEM_EMOJI_PREF = "pref_system_emoji";
|
public static final String SYSTEM_EMOJI_PREF = "pref_system_emoji";
|
||||||
private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device";
|
private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device";
|
||||||
public static final String DIRECT_CAPTURE_CAMERA_ID = "pref_direct_capture_camera_id";
|
|
||||||
public static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
|
public static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
|
||||||
public static final String READ_RECEIPTS_PREF = "pref_read_receipts";
|
public static final String READ_RECEIPTS_PREF = "pref_read_receipts";
|
||||||
public static final String INCOGNITO_KEYBOARD_PREF = "pref_incognito_keyboard";
|
public static final String INCOGNITO_KEYBOARD_PREF = "pref_incognito_keyboard";
|
||||||
@@ -445,15 +443,6 @@ public class TextSecurePreferences {
|
|||||||
return getBooleanPreference(context, ALWAYS_RELAY_CALLS_PREF, false);
|
return getBooleanPreference(context, ALWAYS_RELAY_CALLS_PREF, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDirectCaptureCameraId(Context context, int value) {
|
|
||||||
setIntegerPrefrence(context, DIRECT_CAPTURE_CAMERA_ID, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static int getDirectCaptureCameraId(Context context) {
|
|
||||||
return getIntegerPreference(context, DIRECT_CAPTURE_CAMERA_ID, CameraInfo.CAMERA_FACING_FRONT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
|
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
|
||||||
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
|
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
// Camera feature module
|
// Camera feature module
|
||||||
implementation(project(":feature:camera"))
|
implementation(project(":feature:camera"))
|
||||||
|
|
||||||
// Core modules
|
// Core modules
|
||||||
implementation(project(":core:ui"))
|
implementation(project(":core:ui"))
|
||||||
|
|
||||||
|
|||||||
@@ -398,6 +398,10 @@ class CameraScreenViewModel : ViewModel() {
|
|||||||
_state.value = state.copy(zoomRatio = newZoom)
|
_state.value = state.copy(zoomRatio = newZoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setLensFacing(lensFacing: Int) {
|
||||||
|
_state.value = _state.value.copy(lensFacing = lensFacing)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleSwitchCameraEvent(state: CameraScreenState) {
|
private fun handleSwitchCameraEvent(state: CameraScreenState) {
|
||||||
if (state.isRecording) {
|
if (state.isRecording) {
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user