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