diff --git a/.gitignore b/.gitignore index ea8c8d29..a4eaef14 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,41 @@ .externalNativeBuild .cxx local.properties + +# build files +*.apk +*.ap_ +*.aab +*.aar +*.dex +*.class + +# 日志文件 +*.log + +# 虚拟机崩溃日志 +hs_err_pid* + +# Android Studio +/.idea/jarRepositories.xml +/.idea/inspectionProfiles +/.idea/dictionaries +/.idea/.name +/.idea/vcs.xml +/.idea/shelf +/.idea/tasks.xml +/.idea/usage.statistics.xml +/.idea/jsLibraryMappings.xml +/.idea/misc.xml + +# Gradle +.gradle/ +build/ +**/build/ +**/outputs/ + +# local +.gradletasknamecache + +# system +Thumbs.db diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 00000000..4a53bee8 --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/other.xml b/.idea/other.xml deleted file mode 100644 index 0d3a1fbb..00000000 --- a/.idea/other.xml +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 00000000..16660f1d --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 72e74daa..9f413294 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -27,7 +27,7 @@ plugins { } kotlin { - jvmToolchain(17) + jvmToolchain(21) } secrets { @@ -55,15 +55,21 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } kotlinOptions { - jvmTarget = "17" + jvmTarget = "21" freeCompilerArgs = listOf("-Xcontext-receivers") + freeCompilerArgs += listOf( + "-Xmetadata-version=2.0.0", + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true" + ) } buildFeatures { compose = true + buildConfig = true } composeOptions { kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() @@ -80,6 +86,7 @@ dependencies { implementation(libs.camera.extensions) implementation(libs.profileinstaller) + implementation(libs.glance.appwidget) implementation(libs.glance.material) diff --git a/app/src/main/java/com/google/android/samples/socialite/data/AppDatabase.kt b/app/src/main/java/com/google/android/samples/socialite/data/AppDatabase.kt index 79a36331..b7c48283 100644 --- a/app/src/main/java/com/google/android/samples/socialite/data/AppDatabase.kt +++ b/app/src/main/java/com/google/android/samples/socialite/data/AppDatabase.kt @@ -38,6 +38,7 @@ import com.google.android.samples.socialite.widget.model.WidgetModelDao ], views = [ChatWithLastMessage::class], version = 1, + exportSchema = false, ) abstract class AppDatabase : RoomDatabase() { abstract fun contactDao(): ContactDao diff --git a/app/src/main/java/com/google/android/samples/socialite/data/ChatDao.kt b/app/src/main/java/com/google/android/samples/socialite/data/ChatDao.kt index 31fefeca..af38d6ac 100644 --- a/app/src/main/java/com/google/android/samples/socialite/data/ChatDao.kt +++ b/app/src/main/java/com/google/android/samples/socialite/data/ChatDao.kt @@ -27,15 +27,19 @@ import kotlinx.coroutines.flow.Flow @Dao interface ChatDao { + @Transaction @Query("SELECT * FROM ChatWithLastMessage ORDER BY timestamp DESC") fun allDetails(): Flow> + @Transaction @Query("SELECT * FROM ChatWithLastMessage WHERE id = :id") suspend fun loadDetailById(id: Long): ChatDetail? + @Transaction @Query("SELECT * FROM ChatWithLastMessage WHERE id = :id") fun detailById(id: Long): Flow + @Transaction @Query("SELECT * FROM ChatWithLastMessage") suspend fun loadAllDetails(): List diff --git a/app/src/main/java/com/google/android/samples/socialite/model/Chat.kt b/app/src/main/java/com/google/android/samples/socialite/model/Chat.kt index 3a2a2604..bd0e1e39 100644 --- a/app/src/main/java/com/google/android/samples/socialite/model/Chat.kt +++ b/app/src/main/java/com/google/android/samples/socialite/model/Chat.kt @@ -45,6 +45,7 @@ data class Chat( ], indices = [ Index("chatId", "attendeeId", unique = true), + Index("attendeeId") ], ) data class ChatAttendee( diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/Flow.kt b/app/src/main/java/com/google/android/samples/socialite/ui/Flow.kt index 61776e4f..db3f0197 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/Flow.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/Flow.kt @@ -27,9 +27,9 @@ import kotlinx.coroutines.flow.stateIn * In context of a ViewModel, converts this [Flow] into a [StateFlow] so that it is suitable for * use in UI. */ -context(ViewModel) fun Flow.stateInUi( + viewModel: ViewModel, initialValue: T, ): StateFlow { - return stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), initialValue) + return stateIn(viewModel.viewModelScope, SharingStarted.WhileSubscribed(5000L), initialValue) } diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt b/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt index de030958..7a8edecf 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt @@ -37,7 +37,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Autorenew import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -49,6 +49,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -56,18 +57,21 @@ 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.platform.LocalLifecycleOwner +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.window.layout.FoldingFeature import androidx.window.layout.WindowInfoTracker import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState +import com.google.android.samples.socialite.R import kotlin.reflect.KFunction1 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor +@SuppressLint("CheckResult") @OptIn(ExperimentalPermissionsApi::class) @Composable fun Camera( @@ -97,7 +101,7 @@ fun Camera( val foldingFeature = newLayoutInfo.displayFeatures .filterIsInstance().firstOrNull() isLayoutUnfolded = (foldingFeature != null) - } catch (e: Exception) { + } catch (_: Exception) { // If there was an issue detecting a foldable in the open position, default // to isLayoutUnfolded being false. isLayoutUnfolded = false @@ -107,7 +111,7 @@ fun Camera( val viewFinderState by viewModel.viewFinderState.collectAsStateWithLifecycle() val surfaceRequest by viewModel.surfaceRequest.collectAsStateWithLifecycle() - var rotation by remember { mutableStateOf(Surface.ROTATION_0) } + var rotation by remember { mutableIntStateOf(Surface.ROTATION_0) } DisposableEffect(lifecycleOwner, context) { val rotationProvider = RotationProvider(context) @@ -176,8 +180,7 @@ fun Camera( onMediaCaptured(null) }) { Icon( - imageVector = Icons.Default.ArrowBack, - contentDescription = null, + contentDescription = stringResource(R.string.back), tint = Color.White, ) } @@ -384,8 +387,8 @@ fun CameraSwitcher( }, ) { Icon( - imageVector = Icons.Default.Autorenew, - contentDescription = null, + imageVector = Icons.Filled.Autorenew, + contentDescription = stringResource(R.string.settings), tint = Color.White, modifier = Modifier .height(75.dp) diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatScreen.kt b/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatScreen.kt index 95bcce74..90000085 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatScreen.kt @@ -48,11 +48,11 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.PhotoCamera import androidx.compose.material.icons.filled.PhotoLibrary import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material.icons.filled.Send import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilledIconButton import androidx.compose.material3.Icon @@ -82,7 +82,6 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardCapitalization @@ -90,11 +89,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage import coil.request.ImageRequest import com.google.android.samples.socialite.R @@ -268,7 +268,7 @@ private fun ChatAppBar( if (onBackPressed != null) { IconButton(onClick = onBackPressed) { Icon( - imageVector = Icons.Default.ArrowBack, + imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back), ) } @@ -281,7 +281,7 @@ private fun ChatAppBar( private fun SmallContactIcon(iconUri: Uri, size: Dp) { Image( painter = rememberIconPainter(contentUri = iconUri), - contentDescription = null, + contentDescription = stringResource(R.string.description_icon), modifier = Modifier .size(size) .clip(CircleShape) @@ -355,7 +355,7 @@ private fun MessageBubble( model = ImageRequest.Builder(LocalContext.current) .data(message.mediaUri) .build(), - contentDescription = null, + contentDescription = stringResource(R.string.description_photo), modifier = Modifier .height(250.dp) .padding(10.dp), @@ -389,7 +389,7 @@ private fun VideoMessagePreview(videoUri: String, onClick: () -> Unit) { if (videoUri.contains("https://")) { mediaMetadataRetriever.setDataSource(videoUri, HashMap()) } else { // Locally saved files - mediaMetadataRetriever.setDataSource(context, Uri.parse(videoUri)) + mediaMetadataRetriever.setDataSource(context, videoUri.toUri()) } // Return any frame that the framework considers representative of a valid frame value = mediaMetadataRetriever.frameAtTime @@ -404,14 +404,14 @@ private fun VideoMessagePreview(videoUri: String, onClick: () -> Unit) { ) { Image( bitmap = bitmap.asImageBitmap(), - contentDescription = null, + contentDescription = stringResource(R.string.video_preview), colorFilter = ColorFilter.tint(Color.Gray, BlendMode.Darken), ) Icon( Icons.Filled.PlayArrow, tint = Color.White, - contentDescription = null, + contentDescription = stringResource(R.string.play_title), modifier = Modifier .size(50.dp) .align(Alignment.Center) @@ -445,14 +445,14 @@ private fun InputBar( ) { IconButton(onClick = onCameraClick) { Icon( - imageVector = Icons.Default.PhotoCamera, - contentDescription = null, + imageVector = Icons.Filled.PhotoCamera, + contentDescription = stringResource(R.string.camera_not_available), tint = MaterialTheme.colorScheme.primary, ) } IconButton(onClick = onPhotoPickerClick) { Icon( - imageVector = Icons.Default.PhotoLibrary, + imageVector = Icons.Filled.PhotoLibrary, contentDescription = "Select Photo or video", tint = MaterialTheme.colorScheme.primary, ) @@ -484,8 +484,8 @@ private fun InputBar( enabled = sendEnabled, ) { Icon( - imageVector = Icons.Default.Send, - contentDescription = null, + imageVector = Icons.AutoMirrored.Filled.Send, + contentDescription = stringResource(R.string.send), ) } } diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatViewModel.kt b/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatViewModel.kt index 4df65974..01462eda 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatViewModel.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/chat/ChatViewModel.kt @@ -45,7 +45,7 @@ class ChatViewModel @Inject constructor( @OptIn(ExperimentalCoroutinesApi::class) private val _messages = chatId.flatMapLatest { id -> repository.findMessages(id) } - val chat = _chat.stateInUi(null) + val chat = _chat.stateInUi(this, null) val messages = combine(_messages, attendees) { messages, attendees -> // Build a list of `ChatMessage` from this list of `Message`. @@ -69,13 +69,13 @@ class ChatViewModel @Inject constructor( ) } } - }.stateInUi(emptyList()) + }.stateInUi(this, emptyList()) private val _input = MutableStateFlow("") val input: StateFlow = _input private var inputPrefilled = false - val sendEnabled = _input.map(::isInputValid).stateInUi(false) + val sendEnabled = _input.map(::isInputValid).stateInUi(this, false) /** * We want to update the notification when the corresponding chat screen is open. Setting this diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/home/chatlist/ChatListViewModel.kt b/app/src/main/java/com/google/android/samples/socialite/ui/home/chatlist/ChatListViewModel.kt index a6afbb6c..393b248a 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/home/chatlist/ChatListViewModel.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/home/chatlist/ChatListViewModel.kt @@ -29,5 +29,5 @@ class ChatListViewModel @Inject constructor( val chats = repository .getChats() - .stateInUi(emptyList()) + .stateInUi(this, emptyList()) } diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/player/VideoPlayerScreen.kt b/app/src/main/java/com/google/android/samples/socialite/ui/player/VideoPlayerScreen.kt index 6024df60..23b43af2 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/player/VideoPlayerScreen.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/player/VideoPlayerScreen.kt @@ -16,6 +16,7 @@ package com.google.android.samples.socialite.ui.player +import android.annotation.SuppressLint import android.app.PictureInPictureParams import android.content.BroadcastReceiver import android.content.Context @@ -148,7 +149,7 @@ private fun VideoPlayerTopAppBar( navigationIcon = { IconButton(onClick = onCloseButtonClicked) { Icon( - imageVector = Icons.Default.Close, + imageVector = Icons.Filled.Close, contentDescription = stringResource(R.string.back), ) } @@ -295,6 +296,7 @@ fun isInPipMode(): Boolean { * Uses Disposable Effect to add a listener for onUserLeaveHint - allowing us to add PiP pre * Android 12 */ +@SuppressLint("ImplicitSamInstance") @Composable fun PipListenerPreAPI12(shouldEnterPipMode: Boolean) { // Using the rememberUpdatedState ensures that the updated version of shouldEnterPipMode is diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/player/preloadmanager/PreloadManagerWrapper.kt b/app/src/main/java/com/google/android/samples/socialite/ui/player/preloadmanager/PreloadManagerWrapper.kt index 4cd9f104..7f4f4748 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/player/preloadmanager/PreloadManagerWrapper.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/player/preloadmanager/PreloadManagerWrapper.kt @@ -27,7 +27,6 @@ import androidx.media3.exoplayer.DefaultRenderersFactory import androidx.media3.exoplayer.source.DefaultMediaSourceFactory import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.source.preload.DefaultPreloadManager -import androidx.media3.exoplayer.source.preload.DefaultPreloadManager.Status.STAGE_LOADED_TO_POSITION_MS import androidx.media3.exoplayer.source.preload.TargetPreloadStatusControl import androidx.media3.exoplayer.trackselection.DefaultTrackSelector import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter @@ -72,7 +71,7 @@ private constructor( DefaultBandwidthMeter.getSingletonInstance(context), DefaultRendererCapabilitiesList.Factory(renderersFactory), loadControl.allocator, - playbackLooper, + playbackLooper ) return PreloadManagerWrapper(preloadManager) } @@ -160,7 +159,7 @@ private constructor( class PreloadStatusControl : TargetPreloadStatusControl { override fun getTargetPreloadStatus(rankingData: Int): DefaultPreloadManager.Status { // By default preload first 3 seconds of the video - return DefaultPreloadManager.Status(STAGE_LOADED_TO_POSITION_MS, 3000L) + return DefaultPreloadManager.Status(DefaultPreloadManager.Status.STAGE_LOADED_FOR_DURATION_MS, 3000L) } } } diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt b/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt index ef6db537..0f702312 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt @@ -38,11 +38,12 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.VolumeMute +import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.DonutLarge import androidx.compose.material.icons.filled.FormatSize import androidx.compose.material.icons.filled.Movie -import androidx.compose.material.icons.filled.VolumeMute import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator @@ -149,7 +150,7 @@ fun VideoEditScreen( .padding(15.dp), ) { VideoEditFilterChip( - icon = Icons.Filled.VolumeMute, + icon = Icons.AutoMirrored.Filled.VolumeMute, selected = removeAudioEnabled, onClick = { removeAudioEnabled = !removeAudioEnabled }, label = stringResource(id = R.string.remove_audio), @@ -245,7 +246,7 @@ private fun VideoMessagePreview(videoUri: String, isProcessing: Boolean) { Icon( Icons.Filled.Movie, tint = Color.White, - contentDescription = null, + contentDescription = stringResource(R.string.video_preview), modifier = Modifier .size(60.dp) .padding(10.dp), @@ -294,7 +295,6 @@ fun TextOverlayOption( selected = redTextCheckedState, onClick = redTextCheckedStateChange, label = stringResource(id = R.string.red_text_option), - iconColor = Color.Red, ) Spacer(modifier = Modifier.padding(10.dp)) @@ -315,14 +315,12 @@ private fun VideoEditFilterChip( selected: Boolean, onClick: () -> Unit, label: String, - iconColor: Color = Color.White, - selectedIconColor: Color = Color.Black, ) { FilterChip( leadingIcon = { Icon( imageVector = icon, - contentDescription = null, + contentDescription = label, modifier = Modifier.size(FilterChipDefaults.IconSize), ) }, @@ -333,8 +331,6 @@ private fun VideoEditFilterChip( labelColor = Color.White, selectedContainerColor = colorResource(id = R.color.light_purple), selectedLabelColor = Color.Black, - iconColor = iconColor, - selectedLeadingIconColor = selectedIconColor, ), ) } diff --git a/app/src/main/res/drawable/ic_ff_24dp.xml b/app/src/main/res/drawable/ic_ff_24dp.xml index 81035363..7fbdb6c9 100644 --- a/app/src/main/res/drawable/ic_ff_24dp.xml +++ b/app/src/main/res/drawable/ic_ff_24dp.xml @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportHeight="24.0" - android:viewportWidth="24.0"> + android:viewportWidth="24.0" + android:autoMirrored="true"> diff --git a/app/src/main/res/drawable/ic_pause_24dp.xml b/app/src/main/res/drawable/ic_pause_24dp.xml index 1d993140..37a8120b 100644 --- a/app/src/main/res/drawable/ic_pause_24dp.xml +++ b/app/src/main/res/drawable/ic_pause_24dp.xml @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:autoMirrored="true"> diff --git a/app/src/main/res/drawable/ic_play_24dp.xml b/app/src/main/res/drawable/ic_play_24dp.xml index 67965214..15364707 100644 --- a/app/src/main/res/drawable/ic_play_24dp.xml +++ b/app/src/main/res/drawable/ic_play_24dp.xml @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:autoMirrored="true"> diff --git a/app/src/main/res/drawable/ic_rw_24dp.xml b/app/src/main/res/drawable/ic_rw_24dp.xml index dcfd21d1..319175cc 100644 --- a/app/src/main/res/drawable/ic_rw_24dp.xml +++ b/app/src/main/res/drawable/ic_rw_24dp.xml @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportHeight="24.0" - android:viewportWidth="24.0"> + android:viewportWidth="24.0" + android:autoMirrored="true"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a55c13e4..d2eefb8b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,6 +59,7 @@ Add text overlay Red Large + Video preview Play diff --git a/build.gradle.kts b/build.gradle.kts index a60e1334..5fac2f57 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,7 @@ plugins { alias(libs.plugins.ksp) apply false } + subprojects { plugins.apply(rootProject.libs.plugins.spotless.get().pluginId) configure { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 05adf77a..99bd9ae6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,13 +14,13 @@ [versions] accompanist = "0.32.0" -activity = "1.9.3" -agp = "8.7.3" -benchmarkMacroJunit4 = "1.3.3" -baselineprofile = "1.3.3" -camera = "1.5.0-alpha05" +activity = "1.10.1" +agp = "8.9.1" +benchmarkMacroJunit4 = "1.3.4" +baselineprofile = "1.3.4" +camera = "1.5.0-alpha06" coil = "2.4.0" -compose_bom = "2024.11.00" +compose_bom = "2025.03.01" composeCompiler = "1.5.4" # Used in app/build.gradle.kts concurrent = "1.2.0" core = "1.15.0" @@ -35,10 +35,11 @@ kotlin = "2.0.0" kotlinxSerializationJson = "1.7.3" ksp = "2.0.0-1.0.21" lifecycle = "2.8.7" -android-material3 = "1.13.0-alpha11" +android-material3 = "1.13.0-alpha12" +lifecycleRuntimeCompose = "2.7.0" material3 = "1.3.1" -media3 = "1.4.0-rc01" -navigation = "2.8.5" +media3 = "1.6.0" +navigation = "2.8.9" profileinstaller = "1.4.1" room = "2.6.1" spotless = "6.24.0" @@ -51,7 +52,7 @@ material3-adaptive-navigation-suite = "1.3.1" glance = "1.1.1" secrets = "2.0.1" generativeai = "0.9.0" -datastore = "1.1.1" +datastore = "1.1.4" [libraries] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4ad77960..6245a4e4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu Dec 08 17:47:03 JST 2022 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists