Fix gradle format task.

This commit is contained in:
Greyson Parrelli
2026-02-16 14:22:44 -05:00
committed by Alex Hart
parent 9cefe0bc04
commit b48b1f031e
57 changed files with 164 additions and 186 deletions

View File

@@ -127,7 +127,7 @@ tasks.register("format") {
dependsOn(
gradle.includedBuild("build-logic").task(":plugins:ktlintFormat"),
gradle.includedBuild("build-logic").task(":tools:ktlintFormat"),
*subprojects.mapNotNull { tasks.findByPath(":${it.name}:ktlintFormat") }.toTypedArray()
*subprojects.mapNotNull { tasks.findByPath(":${it.path}:ktlintFormat") }.toTypedArray()
)
}

View File

@@ -26,4 +26,4 @@ class UriSerializer : KSerializer<Uri> {
override fun deserialize(decoder: Decoder): Uri {
return Uri.parse(decoder.decodeString())
}
}
}

View File

@@ -58,4 +58,4 @@ class TransformPropertiesTest {
Assert.assertEquals(false, parsed.videoTrim)
Assert.assertEquals(false, parsed.videoEdited)
}
}
}

View File

@@ -42,4 +42,4 @@ object CoreUiDependencies {
fun provideIsScreenSecurityEnabled(): Boolean
fun provideForceSplitPane(): Boolean
}
}
}

View File

@@ -34,8 +34,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import org.signal.core.ui.R

View File

@@ -70,4 +70,4 @@ fun Modifier.ensureWidthIsAtLeastHeight(): Modifier {
placeable.placeRelative((size - placeable.width) / 2, (size - placeable.height) / 2)
}
}
}
}

View File

@@ -38,7 +38,7 @@ object TransitionSpecs {
targetOffsetX = { -it },
animationSpec = tween(200)
) + fadeOut(animationSpec = tween(200))
)
)
}
val popTransitionSpec: AnimatedContentTransitionScope<Scene<NavKey>>.() -> ContentTransform = {
@@ -53,10 +53,10 @@ object TransitionSpecs {
targetOffsetX = { it },
animationSpec = tween(200)
) + fadeOut(animationSpec = tween(200))
)
)
}
val predictivePopTransitonSpec: AnimatedContentTransitionScope<Scene<NavKey>>.(@NavigationEvent.SwipeEdge Int) -> ContentTransform = {
val predictivePopTransitonSpec: AnimatedContentTransitionScope<Scene<NavKey>>.(@NavigationEvent.SwipeEdge Int) -> ContentTransform = {
(
slideInHorizontally(
initialOffsetX = { -it },
@@ -68,7 +68,7 @@ object TransitionSpecs {
targetOffsetX = { it },
animationSpec = tween(200)
) + fadeOut(animationSpec = tween(200))
)
)
}
}
}
}

View File

@@ -22,7 +22,7 @@ class CoreUiDependenciesRule(
private class Provider(
val isIncognitoKeyboardEnabled: Boolean
): CoreUiDependencies.Provider {
) : CoreUiDependencies.Provider {
override fun providePackageId(): String = "org.thoughtcrime.securesms"
override fun provideIsIncognitoKeyboardEnabled(): Boolean = isIncognitoKeyboardEnabled
override fun provideIsScreenSecurityEnabled(): Boolean = false

View File

@@ -150,7 +150,7 @@ private fun Message<*, *>.appendSizeTree(name: String, depth: Int, sb: StringBui
if (isMessageList) {
for (i in value.indices) {
sb.append("\n")
(value[i] as Message<*, *>).appendSizeTree("${fieldName}[$i]", depth + 2, sb)
(value[i] as Message<*, *>).appendSizeTree("$fieldName[$i]", depth + 2, sb)
}
}
}

View File

@@ -10,7 +10,6 @@ import org.signal.core.util.Hex
import org.signal.core.util.isNotNullOrBlank
import java.util.regex.Matcher
import java.util.regex.Pattern
import kotlin.io.path.Path
/** Given a [Matcher], update the [StringBuilder] with the scrubbed output you want for a given match. */
private typealias MatchProcessor = (Matcher, StringBuilder) -> Unit

View File

@@ -33,4 +33,4 @@ fun Bitmap.scaleWithAspectRatio(maxWidth: Int, maxHeight: Int): Bitmap {
}
return scale(newWidth, newHeight)
}
}

View File

@@ -1,13 +1,11 @@
package org.signal.camera.demo
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
@@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("org.signal.camera.demo", appContext.packageName)
}
}
}

View File

@@ -24,4 +24,4 @@ class MainActivity : ComponentActivity() {
}
}
}
}
}

View File

@@ -1,22 +1,15 @@
package org.signal.camera.demo
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.runtime.Composable
import androidx.navigation3.runtime.NavKey
import androidx.compose.ui.Modifier
import androidx.navigation3.runtime.NavBackStack
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.scene.Scene
import androidx.navigation3.ui.NavDisplay
import org.signal.camera.demo.screens.gallery.GalleryScreen
import org.signal.camera.demo.screens.imageviewer.ImageViewerScreen
@@ -42,24 +35,24 @@ fun NavGraph(
modifier: Modifier = Modifier
) {
val backStack = rememberNavBackStack(Screen.Main)
@Suppress("UNCHECKED_CAST")
val typedBackStack = backStack as NavBackStack<Screen>
NavDisplay(
backStack = backStack,
modifier = modifier,
transitionSpec = {
// Gallery slides up from bottom
slideInHorizontally(
initialOffsetX = { fullWidth -> fullWidth },
initialOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
) togetherWith
// Camera stays in place and fades out
slideOutHorizontally (
targetOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(500)
)
// Camera stays in place and fades out
slideOutHorizontally(
targetOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(500)
)
},
popTransitionSpec = {
// Camera slides back in from left
@@ -67,11 +60,11 @@ fun NavGraph(
initialOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(500)
) togetherWith
// Gallery slides out to right
slideOutHorizontally(
targetOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
)
// Gallery slides out to right
slideOutHorizontally(
targetOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
)
},
predictivePopTransitionSpec = { progress ->
// Camera slides back in from left (predictive with progress)
@@ -79,21 +72,21 @@ fun NavGraph(
initialOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(500)
) togetherWith
// Gallery slides out to right (predictive with progress)
slideOutHorizontally(
targetOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
)
// Gallery slides out to right (predictive with progress)
slideOutHorizontally(
targetOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
)
},
entryProvider = entryProvider {
addEntryProvider(
key = Screen.Main,
contentKey = Screen.Main,
key = Screen.Main,
contentKey = Screen.Main,
metadata = emptyMap()
) { screen: Screen ->
MainScreen(backStack = typedBackStack)
}
addEntryProvider(
key = Screen.Gallery,
contentKey = Screen.Gallery,
@@ -101,7 +94,7 @@ fun NavGraph(
) { screen: Screen ->
GalleryScreen(backStack = typedBackStack)
}
addEntryProvider(
key = Screen.ImageViewer,
contentKey = Screen.ImageViewer,
@@ -109,7 +102,7 @@ fun NavGraph(
) { screen: Screen ->
ImageViewerScreen(backStack = typedBackStack)
}
addEntryProvider(
key = Screen.VideoViewer,
contentKey = Screen.VideoViewer,

View File

@@ -5,8 +5,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
@@ -17,10 +15,10 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.PlayArrow
@@ -59,11 +57,11 @@ fun GalleryScreen(
val context = LocalContext.current
val state = viewModel.state.value
var showDeleteDialog by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
viewModel.loadMedia(context)
}
// Delete confirmation dialog
if (showDeleteDialog) {
AlertDialog(
@@ -92,7 +90,7 @@ fun GalleryScreen(
}
)
}
Box(
modifier = Modifier
.fillMaxSize()
@@ -154,7 +152,7 @@ fun GalleryScreen(
}
}
}
// Delete all button at bottom (only show when there are items)
if (state.mediaItems.isNotEmpty()) {
Button(
@@ -196,7 +194,7 @@ private fun MediaThumbnail(
scaleType = GlideImageScaleType.CENTER_CROP,
modifier = Modifier.fillMaxSize()
)
if (mediaItem.isVideo) {
Box(
modifier = Modifier

View File

@@ -19,10 +19,10 @@ class GalleryScreenViewModel : ViewModel() {
private val _state: MutableState<GalleryScreenState> = mutableStateOf(GalleryScreenState())
val state: State<GalleryScreenState>
get() = _state
fun loadMedia(context: Context) {
_state.value = _state.value.copy(isLoading = true, error = null)
viewModelScope.launch {
try {
val mediaItems = loadMediaFromInternalStorage(context)
@@ -40,7 +40,7 @@ class GalleryScreenViewModel : ViewModel() {
}
}
}
fun deleteAllMedia(context: Context) {
viewModelScope.launch {
try {
@@ -56,14 +56,14 @@ class GalleryScreenViewModel : ViewModel() {
}
}
}
private suspend fun loadMediaFromInternalStorage(context: Context): List<MediaItem> = withContext(Dispatchers.IO) {
val galleryDir = File(context.filesDir, GALLERY_FOLDER)
if (!galleryDir.exists()) {
return@withContext emptyList()
}
galleryDir.listFiles()
?.filter { it.isFile }
?.mapNotNull { file ->
@@ -80,23 +80,23 @@ class GalleryScreenViewModel : ViewModel() {
?.sortedByDescending { it.lastModified }
?: emptyList()
}
private suspend fun deleteAllMediaFromInternalStorage(context: Context): Int = withContext(Dispatchers.IO) {
val galleryDir = File(context.filesDir, GALLERY_FOLDER)
if (!galleryDir.exists()) {
return@withContext 0
}
val files = galleryDir.listFiles() ?: return@withContext 0
var deletedCount = 0
files.forEach { file ->
if (file.isFile && file.delete()) {
deletedCount++
}
}
deletedCount
}
}

View File

@@ -6,19 +6,19 @@ sealed class MediaItem {
abstract val file: File
abstract val name: String
abstract val lastModified: Long
data class Image(
override val file: File,
override val name: String = file.name,
override val lastModified: Long = file.lastModified()
) : MediaItem()
data class Video(
override val file: File,
override val name: String = file.name,
override val lastModified: Long = file.lastModified()
) : MediaItem()
val isImage: Boolean get() = this is Image
val isVideo: Boolean get() = this is Video
}

View File

@@ -36,18 +36,18 @@ fun ImageViewerScreen(
backStack: NavBackStack<Screen>
) {
val selectedMedia = org.signal.camera.demo.MediaSelectionHolder.selectedMedia
if (selectedMedia == null || selectedMedia !is MediaItem.Image) {
// No image selected, go back
backStack.removeLastOrNull()
return
}
val imageFile = selectedMedia.file
var scale by remember { mutableFloatStateOf(1f) }
var offset by remember { mutableStateOf(Offset.Zero) }
Box(
modifier = Modifier
.fillMaxSize()
@@ -83,7 +83,7 @@ fun ImageViewerScreen(
)
)
}
// Back button
IconButton(
onClick = { backStack.removeLastOrNull() },

View File

@@ -5,6 +5,7 @@ package org.signal.camera.demo.screens.main
import android.Manifest
import android.os.Build
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -25,35 +26,34 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation3.runtime.NavBackStack
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.MultiplePermissionsState
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import androidx.compose.foundation.background
import androidx.compose.ui.graphics.Color
import androidx.navigation3.runtime.NavBackStack
import org.signal.camera.demo.Screen
import org.signal.camera.hud.StandardCameraHudEvents
import org.signal.camera.CameraScreen
import org.signal.camera.CameraScreenEvents
import org.signal.camera.CameraScreenViewModel
import org.signal.camera.demo.Screen
import org.signal.camera.hud.StandardCameraHud
import org.signal.camera.hud.StandardCameraHudEvents
@Composable
fun MainScreen(
backStack: NavBackStack<Screen>,
viewModel: MainScreenViewModel = viewModel(),
viewModel: MainScreenViewModel = viewModel()
) {
val cameraViewModel: CameraScreenViewModel = viewModel()
val permissions = buildList {
add(Manifest.permission.CAMERA)
add(Manifest.permission.RECORD_AUDIO)
if (Build.VERSION.SDK_INT >= 33) {
add(Manifest.permission.READ_MEDIA_IMAGES)
add(Manifest.permission.READ_MEDIA_VIDEO)
@@ -61,7 +61,7 @@ fun MainScreen(
add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
val permissionsState = rememberMultiplePermissionsState(permissions = permissions)
val context = LocalContext.current
@@ -126,7 +126,7 @@ fun MainScreen(
}
)
}
is StandardCameraHudEvents.VideoCaptureStopped-> {
is StandardCameraHudEvents.VideoCaptureStopped -> {
cameraViewModel.stopRecording()
}
is StandardCameraHudEvents.GalleryClick -> {
@@ -155,7 +155,7 @@ fun MainScreen(
)
}
}
// QR Code Dialog
if (qrCodeContent != null) {
AlertDialog(

View File

@@ -5,8 +5,8 @@ import android.graphics.Bitmap
sealed interface MainScreenEvents {
data class SavePhoto(val context: Context, val bitmap: Bitmap) : MainScreenEvents
data class VideoSaved(val result: org.signal.camera.VideoCaptureResult) : MainScreenEvents
data object ClearSaveStatus : MainScreenEvents
}

View File

@@ -9,11 +9,11 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import org.signal.camera.VideoCaptureResult
import org.signal.camera.VideoOutput
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.signal.camera.VideoCaptureResult
import org.signal.camera.VideoOutput
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
@@ -40,25 +40,25 @@ class MainScreenViewModel : ViewModel() {
}
}
}
fun createVideoOutput(context: Context): VideoOutput {
// Create gallery directory in internal storage
val galleryDir = File(context.filesDir, GALLERY_FOLDER)
if (!galleryDir.exists()) {
galleryDir.mkdirs()
}
// Generate filename with timestamp
val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
.format(System.currentTimeMillis())
val file = File(galleryDir, "$name.mp4")
// Open the file as a ParcelFileDescriptor
val fileDescriptor = ParcelFileDescriptor.open(
file,
ParcelFileDescriptor.MODE_READ_WRITE or ParcelFileDescriptor.MODE_CREATE
)
return VideoOutput.FileDescriptorOutput(fileDescriptor)
}
@@ -87,7 +87,7 @@ class MainScreenViewModel : ViewModel() {
is VideoCaptureResult.Success -> {
// Close the file descriptor now that recording is complete
result.fileDescriptor?.close()
Log.d(TAG, "Video saved successfully")
_state.value = state.copy(saveStatus = SaveStatus.Success)
}
@@ -97,7 +97,7 @@ class MainScreenViewModel : ViewModel() {
}
}
}
private fun handleClearSaveStatusEvent(
state: MainScreenState,
event: MainScreenEvents.ClearSaveStatus
@@ -111,12 +111,12 @@ class MainScreenViewModel : ViewModel() {
if (!galleryDir.exists()) {
galleryDir.mkdirs()
}
// Generate filename with timestamp
val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
.format(System.currentTimeMillis())
val file = File(galleryDir, "$name.jpg")
// Save bitmap to file
file.outputStream().use { outputStream ->
event.bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outputStream)

View File

@@ -27,7 +27,6 @@ import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import androidx.navigation3.runtime.NavBackStack
import org.signal.camera.demo.Screen
import java.io.File
@OptIn(UnstableApi::class)
@Composable
@@ -35,16 +34,16 @@ fun VideoViewerScreen(
backStack: NavBackStack<Screen>
) {
val selectedMedia = org.signal.camera.demo.MediaSelectionHolder.selectedMedia
if (selectedMedia == null || selectedMedia !is org.signal.camera.demo.screens.gallery.MediaItem.Video) {
// No video selected, go back
backStack.removeAt(backStack.lastIndex)
return
}
val context = LocalContext.current
val videoFile = selectedMedia.file
val exoPlayer = remember {
ExoPlayer.Builder(context).build().apply {
val mediaItem = MediaItem.fromUri(videoFile.toURI().toString())
@@ -54,13 +53,13 @@ fun VideoViewerScreen(
repeatMode = Player.REPEAT_MODE_OFF
}
}
DisposableEffect(Unit) {
onDispose {
exoPlayer.release()
}
}
Box(
modifier = Modifier
.fillMaxSize()
@@ -81,7 +80,7 @@ fun VideoViewerScreen(
},
modifier = Modifier.fillMaxSize()
)
// Back button
IconButton(
onClick = { backStack.removeAt(backStack.lastIndex) },

View File

@@ -8,4 +8,4 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
val Pink40 = Color(0xFF7D5260)

View File

@@ -1,6 +1,5 @@
package org.signal.camera.demo.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
@@ -30,7 +29,7 @@ private val LightColorScheme = lightColorScheme(
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
*/
)
@Composable
@@ -55,4 +54,4 @@ fun CameraXTestTheme(
typography = Typography,
content = content
)
}
}

View File

@@ -30,5 +30,5 @@ val Typography = Typography(
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)
*/
)

View File

@@ -1,9 +1,8 @@
package org.signal.camera.demo
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
@@ -14,4 +13,4 @@ class ExampleUnitTest {
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
}

View File

@@ -59,12 +59,15 @@ class RegistrationApplication : Application() {
)
)
CoreUiDependencies.init(this, object : CoreUiDependencies.Provider {
override fun providePackageId(): String = BuildConfig.APPLICATION_ID
override fun provideIsIncognitoKeyboardEnabled(): Boolean = false
override fun provideIsScreenSecurityEnabled(): Boolean = false
override fun provideForceSplitPane(): Boolean = false
})
CoreUiDependencies.init(
this,
object : CoreUiDependencies.Provider {
override fun providePackageId(): String = BuildConfig.APPLICATION_ID
override fun provideIsIncognitoKeyboardEnabled(): Boolean = false
override fun provideIsScreenSecurityEnabled(): Boolean = false
override fun provideForceSplitPane(): Boolean = false
}
)
}
private fun createPushServiceSocket(configuration: SignalServiceConfiguration): PushServiceSocket {

View File

@@ -8,7 +8,6 @@ package org.signal.registration.sample.absbackup
import android.app.backup.BackupAgent
import android.app.backup.BackupDataInput
import android.app.backup.BackupDataOutput
import android.app.backup.FullBackupDataOutput
import android.os.ParcelFileDescriptor
import org.signal.core.util.logging.Log
import org.signal.registration.NetworkController
@@ -17,7 +16,6 @@ import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
@@ -108,4 +106,4 @@ class RegistrationBackupAgent : BackupAgent() {
private val TAG = Log.tag(RegistrationBackupAgent::class)
private const val BACKUP_KEY = "Svr2Credentials"
}
}
}

View File

@@ -10,6 +10,8 @@ import org.signal.core.util.logging.Log
import org.signal.registration.NetworkController
import org.signal.registration.NetworkController.AccountAttributes
import org.signal.registration.NetworkController.BackupMasterKeyError
import org.signal.registration.NetworkController.CheckSvrCredentialsError
import org.signal.registration.NetworkController.CheckSvrCredentialsResponse
import org.signal.registration.NetworkController.CreateSessionError
import org.signal.registration.NetworkController.GetSessionStatusError
import org.signal.registration.NetworkController.GetSvrCredentialsError
@@ -27,8 +29,6 @@ import org.signal.registration.NetworkController.SubmitVerificationCodeError
import org.signal.registration.NetworkController.SvrCredentials
import org.signal.registration.NetworkController.UpdateSessionError
import org.signal.registration.NetworkController.VerificationCodeTransport
import org.signal.registration.NetworkController.CheckSvrCredentialsError
import org.signal.registration.NetworkController.CheckSvrCredentialsResponse
import java.util.Locale
/**

View File

@@ -17,6 +17,8 @@ import org.signal.libsignal.net.Network
import org.signal.libsignal.protocol.util.Hex
import org.signal.registration.NetworkController
import org.signal.registration.NetworkController.AccountAttributes
import org.signal.registration.NetworkController.CheckSvrCredentialsRequest
import org.signal.registration.NetworkController.CheckSvrCredentialsResponse
import org.signal.registration.NetworkController.CreateSessionError
import org.signal.registration.NetworkController.GetSessionStatusError
import org.signal.registration.NetworkController.PreKeyCollection
@@ -25,8 +27,6 @@ import org.signal.registration.NetworkController.RegisterAccountResponse
import org.signal.registration.NetworkController.RegistrationLockResponse
import org.signal.registration.NetworkController.RegistrationNetworkResult
import org.signal.registration.NetworkController.RequestVerificationCodeError
import org.signal.registration.NetworkController.CheckSvrCredentialsRequest
import org.signal.registration.NetworkController.CheckSvrCredentialsResponse
import org.signal.registration.NetworkController.SessionMetadata
import org.signal.registration.NetworkController.SubmitVerificationCodeError
import org.signal.registration.NetworkController.ThirdPartyServiceErrorResponse

View File

@@ -5,7 +5,6 @@ import androidx.camera.compose.CameraXViewfinder
import androidx.camera.core.SurfaceRequest
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.viewfinder.compose.MutableCoordinateTransformer
import androidx.camera.core.Preview as CameraPreview
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring
@@ -45,6 +44,7 @@ import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.signal.core.ui.compose.Previews
import androidx.camera.core.Preview as CameraPreview
/**
* A camera screen that handles core camera functionality, such as:

View File

@@ -43,4 +43,4 @@ sealed interface CameraScreenEvents {
/** Indicates the capture error has been handled and can be cleared. */
data object ClearCaptureError : CameraScreenEvents
}
}

View File

@@ -45,4 +45,3 @@ enum class FlashMode(val cameraxMode: Int) {
}
}
}

View File

@@ -3,8 +3,8 @@ package org.signal.camera
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Matrix
import android.os.Build
@@ -81,7 +81,7 @@ class CameraScreenViewModel : ViewModel() {
private var orientationListener: OrientationEventListener? = null
private val _qrCodeDetected = MutableSharedFlow<String>(extraBufferCapacity = 1)
/**
* Flow of detected QR codes. Observers can collect from this flow to receive QR code detections.
* The flow filters consecutive duplicates and is throttled to avoid rapid-fire detections.
@@ -133,7 +133,7 @@ class CameraScreenViewModel : ViewModel() {
@androidx.annotation.OptIn(markerClass = [androidx.camera.core.ExperimentalGetImage::class])
fun capturePhoto(
context: Context,
onPhotoCaptured: (Bitmap) -> Unit,
onPhotoCaptured: (Bitmap) -> Unit
) {
val state = _state.value
val capture = imageCapture ?: run {

View File

@@ -13,7 +13,7 @@ sealed class VideoOutput {
* The consumer is responsible for creating the file and managing its lifecycle.
*/
data class FileOutput(val file: File) : VideoOutput()
/**
* Save video to a file descriptor.
* The consumer provides the file descriptor and is responsible for closing it.
@@ -35,7 +35,7 @@ sealed class VideoCaptureResult {
val outputFile: File? = null,
val fileDescriptor: ParcelFileDescriptor? = null
) : VideoCaptureResult()
/**
* Video capture failed.
* @param fileDescriptor The file descriptor that was being used (for cleanup)

View File

@@ -22,12 +22,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview

View File

@@ -32,14 +32,14 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.signal.glide.compose.GlideImage
import org.signal.glide.compose.GlideImageScaleType
import kotlinx.coroutines.withContext
/**
* A button that displays a thumbnail of the most recent image or video from the gallery.
* Shows a circular thumbnail with a white border that opens the gallery when clicked.
*
*
* @param modifier Modifier to apply to the button
* @param onClick Callback when the button is clicked
*/
@@ -50,12 +50,12 @@ fun GalleryThumbnailButton(
) {
val context = LocalContext.current
var thumbnailUri by remember { mutableStateOf<Uri?>(null) }
// Load the most recent media item
LaunchedEffect(Unit) {
thumbnailUri = getLatestMediaUri(context)
}
Box(
modifier = modifier
.size(52.dp)
@@ -93,7 +93,7 @@ private suspend fun getLatestMediaUri(context: Context): Uri? = withContext(Disp
try {
val imageUri = getLatestImageUri(context)
val videoUri = getLatestVideoUri(context)
// Compare timestamps if both exist, otherwise return whichever is available
when {
imageUri != null && videoUri != null -> {
@@ -122,9 +122,9 @@ private fun getLatestImageUri(context: Context): Uri? {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATE_ADDED
)
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
@@ -141,7 +141,7 @@ private fun getLatestImageUri(context: Context): Uri? {
)
}
}
return null
}
@@ -153,9 +153,9 @@ private fun getLatestVideoUri(context: Context): Uri? {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DATE_ADDED
)
val sortOrder = "${MediaStore.Video.Media.DATE_ADDED} DESC"
context.contentResolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
@@ -172,7 +172,7 @@ private fun getLatestVideoUri(context: Context): Uri? {
)
}
}
return null
}
@@ -181,7 +181,7 @@ private fun getLatestVideoUri(context: Context): Uri? {
*/
private fun getMediaTimestamp(context: Context, uri: Uri): Long? {
val projection = arrayOf(MediaStore.MediaColumns.DATE_ADDED)
context.contentResolver.query(
uri,
projection,
@@ -194,7 +194,7 @@ private fun getMediaTimestamp(context: Context, uri: Uri): Long? {
return cursor.getLong(dateColumn)
}
}
return null
}
@@ -208,7 +208,7 @@ fun hasMediaPermissions(context: Context): Boolean {
// Android 13+
context.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) ==
PackageManager.PERMISSION_GRANTED ||
context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) ==
context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) ==
PackageManager.PERMISSION_GRANTED
} else {
// Older Android versions

View File

@@ -413,7 +413,7 @@ private fun MediaCountIndicator(
.padding(horizontal = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
val size = with (LocalDensity.current) {
val size = with(LocalDensity.current) {
22.sp.toDp()
}
Box(

View File

@@ -8,7 +8,6 @@ import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.fragment.app.FragmentActivity
@@ -49,10 +48,10 @@ abstract class MediaSendActivity : FragmentActivity() {
backStack = backStack,
callback = viewModel,
modifier = Modifier.fillMaxSize(),
cameraSlot = { },
textStoryEditorSlot = { },
videoEditorSlot = { },
sendSlot = { }
cameraSlot = { },
textStoryEditorSlot = { },
videoEditorSlot = { },
sendSlot = { }
)
}
}

View File

@@ -38,4 +38,4 @@ object MediaSendDependencies {
fun provideMediaSendRepository(): MediaSendRepository
fun providePreUploadRepository(): PreUploadRepository
}
}
}

View File

@@ -18,7 +18,7 @@ import org.signal.mediasend.MediaRecipientId
* Threading: all callback methods are invoked on this manager's serialized background executor
* thread (i.e., not the main thread).
*/
interface PreUploadRepository {
interface PreUploadRepository {
/**
* Performs pre-upload side-effects (e.g., create attachment state + enqueue jobs).
*
@@ -75,4 +75,4 @@ interface PreUploadRepository {
*/
@WorkerThread
fun deleteAbandonedPreuploadedAttachments(context: Context): Int
}
}

View File

@@ -6,7 +6,6 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier

View File

@@ -38,4 +38,3 @@ data class RegistrationFlowState(
/** If true, do not attempt any flows where we generate RRP's. Create a session instead. */
val doNotAttemptRecoveryPassword: Boolean = false
) : Parcelable

View File

@@ -26,10 +26,7 @@ import org.signal.registration.RegistrationFlowState
import org.signal.registration.RegistrationRepository
import org.signal.registration.RegistrationRoute
import org.signal.registration.screens.phonenumber.PhoneNumberEntryState.OneTimeEvent
import org.signal.registration.screens.phonenumber.PhoneNumberEntryState.OneTimeEvent.*
import org.signal.registration.screens.util.navigateTo
import org.signal.registration.screens.verificationcode.VerificationCodeState
import org.signal.registration.screens.verificationcode.VerificationCodeViewModel
class PhoneNumberEntryViewModel(
val repository: RegistrationRepository,
@@ -101,7 +98,7 @@ class PhoneNumberEntryViewModel(
@VisibleForTesting
fun applyParentState(state: PhoneNumberEntryState, parentState: RegistrationFlowState): PhoneNumberEntryState {
return state.copy(
sessionE164 = parentState.sessionE164,
sessionE164 = parentState.sessionE164,
sessionMetadata = parentState.sessionMetadata,
preExistingRegistrationData = parentState.preExistingRegistrationData,
restoredSvrCredentials = state.restoredSvrCredentials.takeUnless { parentState.doNotAttemptRecoveryPassword } ?: emptyList()
@@ -238,7 +235,7 @@ class PhoneNumberEntryViewModel(
if (state.restoredSvrCredentials.isNotEmpty()) {
when (val result = repository.checkSvrCredentials(e164, state.restoredSvrCredentials)) {
is NetworkController.RegistrationNetworkResult.Success -> {
Log.i(TAG, "[CheckSVRCredentials] Successfully validated credentials for ${e164}.")
Log.i(TAG, "[CheckSVRCredentials] Successfully validated credentials for $e164.")
val credential = result.data.validCredential
if (credential != null) {
parentEventEmitter(RegistrationFlowEvent.E164Chosen(e164))

View File

@@ -217,7 +217,7 @@ class PinEntryForSmsBypassViewModel(
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return PinEntryForSmsBypassViewModel(
repository = repository,
parentState = parentState,
parentState = parentState,
parentEventEmitter = parentEventEmitter,
svrCredentials = svrCredentials
) as T

View File

@@ -17,4 +17,4 @@ class ACIParceler : Parceler<ServiceId.ACI> {
override fun create(parcel: Parcel): ServiceId.ACI {
return ServiceId.ACI.parseOrThrow(parcel.createByteArray())
}
}
}

View File

@@ -17,4 +17,4 @@ class KyberPreKeyRecordParceler : Parceler<KyberPreKeyRecord> {
override fun create(parcel: Parcel): KyberPreKeyRecord {
return KyberPreKeyRecord(parcel.createByteArray())
}
}
}

View File

@@ -19,4 +19,3 @@ object MasterKeyParceler : Parceler<MasterKey?> {
parcel.writeByteArray(this?.serialize())
}
}

View File

@@ -17,4 +17,4 @@ class PNIParceler : Parceler<ServiceId.PNI> {
override fun create(parcel: Parcel): ServiceId.PNI {
return ServiceId.PNI.parseOrThrow(parcel.createByteArray())
}
}
}

View File

@@ -42,4 +42,4 @@ object SensitiveLog : Log.Logger() {
override fun flush() {
this.logger.flush()
}
}
}

View File

@@ -17,4 +17,4 @@ class SignedPreKeyRecordParceler : Parceler<SignedPreKeyRecord> {
override fun create(parcel: Parcel): SignedPreKeyRecord {
return SignedPreKeyRecord(parcel.createByteArray())
}
}
}

View File

@@ -7,11 +7,11 @@ package org.signal.registration
import android.app.Application
import androidx.compose.ui.test.assertIsDisplayed
import androidx.test.core.app.ApplicationProvider
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.lifecycle.SavedStateHandle
import androidx.test.core.app.ApplicationProvider
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import io.mockk.mockk
import org.junit.Before

View File

@@ -7,11 +7,11 @@ package org.signal.registration.screens.phonenumber
import android.app.Application
import androidx.compose.ui.test.assertIsEnabled
import androidx.test.core.app.ApplicationProvider
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

View File

@@ -7,12 +7,12 @@ package org.signal.registration.screens.verificationcode
import android.app.Application
import androidx.compose.ui.test.assertIsDisplayed
import androidx.test.core.app.ApplicationProvider
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.test.core.app.ApplicationProvider
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

View File

@@ -7,10 +7,10 @@ package org.signal.registration.screens.welcome
import android.app.Application
import androidx.compose.ui.test.assertIsDisplayed
import androidx.test.core.app.ApplicationProvider
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

View File

@@ -15,26 +15,26 @@ import org.signal.glide.common.io.InputStreamFactory
object SignalGlideDependencies {
private lateinit var _application: Application
private lateinit var _provider: Provider
@Synchronized
fun init(application: Application, provider: Provider) {
if (this::_application.isInitialized || this::_provider.isInitialized) {
return
}
_application = application
_provider = provider
}
val application: Application
get() = _application
fun getUriInputStreamFactory(uri: Uri): InputStreamFactory = _provider.getUriInputStreamFactory(uri)
interface Provider {
/**
* A factory which can create an [java.io.InputStream] from a given [Uri]
*/
fun getUriInputStreamFactory(uri: Uri): InputStreamFactory
}
}
}

View File

@@ -48,7 +48,7 @@ internal class GroupChangeActionsBuilderChangeSetModifier(private val result: Gr
}
override fun clearModifyDisappearingMessagesTimer() {
result.modifyDisappearingMessageTimer= null
result.modifyDisappearingMessageTimer = null
}
override fun clearModifyAttributesAccess() {