Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ad849166 | ||
|
|
761db7a69d | ||
|
|
428749d8a8 | ||
|
|
460c50bfd9 | ||
|
|
5832e2db4a |
No files matched your search
@@ -9,8 +9,13 @@ import androidx.datastore.preferences.core.floatPreferencesKey
|
|||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
import androidx.datastore.preferences.preferencesDataStore
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -41,17 +46,26 @@ class UserPreferencesRepository @Inject constructor(
|
|||||||
val SCREEN_TRANSITIONS_ENABLED = booleanPreferencesKey("screen_transitions_enabled")
|
val SCREEN_TRANSITIONS_ENABLED = booleanPreferencesKey("screen_transitions_enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
val userPreferencesFlow: Flow<UserPreferences> = context.dataStore.data.map { prefs ->
|
// Hot, process-wide cache: the DataStore file is read once, and every screen
|
||||||
UserPreferences(
|
// created later receives the current value synchronously on subscription,
|
||||||
rootFolderUri = prefs[Keys.ROOT_FOLDER_URI],
|
// instead of re-reading disk per screen and flashing default positions.
|
||||||
cameraFabXFraction = prefs[Keys.CAMERA_FAB_X_FRACTION]?.coerceIn(0f, 1f) ?: 1f,
|
val userPreferencesFlow: StateFlow<UserPreferences> = context.dataStore.data
|
||||||
cameraFabYFraction = prefs[Keys.CAMERA_FAB_Y_FRACTION]?.coerceIn(0f, 1f) ?: 1f,
|
.map { prefs ->
|
||||||
gallerySortAscending = prefs[Keys.GALLERY_SORT_ASCENDING] ?: true,
|
UserPreferences(
|
||||||
galleryGridMode = prefs[Keys.GALLERY_GRID_MODE] ?: true,
|
rootFolderUri = prefs[Keys.ROOT_FOLDER_URI],
|
||||||
zipJpegCompression = prefs[Keys.ZIP_JPEG_COMPRESSION] ?: true,
|
cameraFabXFraction = prefs[Keys.CAMERA_FAB_X_FRACTION]?.coerceIn(0f, 1f) ?: 1f,
|
||||||
screenTransitionsEnabled = prefs[Keys.SCREEN_TRANSITIONS_ENABLED] ?: true,
|
cameraFabYFraction = prefs[Keys.CAMERA_FAB_Y_FRACTION]?.coerceIn(0f, 1f) ?: 1f,
|
||||||
|
gallerySortAscending = prefs[Keys.GALLERY_SORT_ASCENDING] ?: true,
|
||||||
|
galleryGridMode = prefs[Keys.GALLERY_GRID_MODE] ?: true,
|
||||||
|
zipJpegCompression = prefs[Keys.ZIP_JPEG_COMPRESSION] ?: true,
|
||||||
|
screenTransitionsEnabled = prefs[Keys.SCREEN_TRANSITIONS_ENABLED] ?: true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.stateIn(
|
||||||
|
scope = CoroutineScope(SupervisorJob() + Dispatchers.IO),
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = UserPreferences(),
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun setRootFolderUri(uri: String) {
|
suspend fun setRootFolderUri(uri: String) {
|
||||||
context.dataStore.edit { prefs ->
|
context.dataStore.edit { prefs ->
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ import kotlinx.serialization.Serializable
|
|||||||
object FoldersRoute
|
object FoldersRoute
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GalleryRoute(val folderUri: String)
|
data class GalleryRoute(
|
||||||
|
val folderUri: String,
|
||||||
|
val folderName: String = "",
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CameraRoute(
|
data class CameraRoute(
|
||||||
@@ -64,14 +67,20 @@ fun OneCameraNavGraph(navController: NavHostController) {
|
|||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = FoldersRoute,
|
startDestination = FoldersRoute,
|
||||||
enterTransition = { if (transitionsEnabled) fadeIn(tween(250)) else EnterTransition.None },
|
enterTransition = { if (transitionsEnabled) fadeIn(tween(250)) else EnterTransition.None },
|
||||||
exitTransition = { if (transitionsEnabled) fadeOut(tween(250)) else ExitTransition.None },
|
exitTransition = {
|
||||||
popEnterTransition = { if (transitionsEnabled) fadeIn(tween(250)) else EnterTransition.None },
|
if (transitionsEnabled) {
|
||||||
|
ExitTransition.KeepUntilTransitionsFinished
|
||||||
|
} else {
|
||||||
|
ExitTransition.None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
popEnterTransition = { EnterTransition.None },
|
||||||
popExitTransition = { if (transitionsEnabled) fadeOut(tween(250)) else ExitTransition.None },
|
popExitTransition = { if (transitionsEnabled) fadeOut(tween(250)) else ExitTransition.None },
|
||||||
) {
|
) {
|
||||||
composable<FoldersRoute> {
|
composable<FoldersRoute> {
|
||||||
FoldersScreen(
|
FoldersScreen(
|
||||||
onNavigateToGallery = { folderUri ->
|
onNavigateToGallery = { folderUri, folderName ->
|
||||||
navController.navigate(GalleryRoute(folderUri))
|
navController.navigate(GalleryRoute(folderUri, folderName))
|
||||||
},
|
},
|
||||||
onNavigateToCamera = { folderUri ->
|
onNavigateToCamera = { folderUri ->
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
@@ -93,8 +102,8 @@ fun OneCameraNavGraph(navController: NavHostController) {
|
|||||||
onNavigateToCamera = { folderUri ->
|
onNavigateToCamera = { folderUri ->
|
||||||
navController.navigate(CameraRoute(folderUri))
|
navController.navigate(CameraRoute(folderUri))
|
||||||
},
|
},
|
||||||
onNavigateToSubfolder = { folderUri ->
|
onNavigateToSubfolder = { folderUri, folderName ->
|
||||||
navController.navigate(GalleryRoute(folderUri))
|
navController.navigate(GalleryRoute(folderUri, folderName))
|
||||||
},
|
},
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import com.example.onecamera.ui.components.oneCameraTopAppBarColors
|
|||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun FoldersScreen(
|
fun FoldersScreen(
|
||||||
onNavigateToGallery: (String) -> Unit,
|
onNavigateToGallery: (folderUri: String, folderName: String) -> Unit,
|
||||||
onNavigateToCamera: (String) -> Unit,
|
onNavigateToCamera: (String) -> Unit,
|
||||||
onNavigateToSettings: () -> Unit,
|
onNavigateToSettings: () -> Unit,
|
||||||
viewModel: FoldersViewModel = hiltViewModel(),
|
viewModel: FoldersViewModel = hiltViewModel(),
|
||||||
@@ -230,7 +230,7 @@ fun FoldersScreen(
|
|||||||
|
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.prefetchFolderForNavigation(folder.uri.toString())
|
viewModel.prefetchFolderForNavigation(folder.uri.toString())
|
||||||
onNavigateToGallery(folder.uri.toString())
|
onNavigateToGallery(folder.uri.toString(), folder.name)
|
||||||
},
|
},
|
||||||
onCompress = { viewModel.zipFolderAndShare(folder) },
|
onCompress = { viewModel.zipFolderAndShare(folder) },
|
||||||
onCompressJpeg85 = {
|
onCompressJpeg85 = {
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ import androidx.compose.runtime.snapshotFlow
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
@@ -93,7 +93,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|||||||
fun GalleryScreen(
|
fun GalleryScreen(
|
||||||
folderUri: String,
|
folderUri: String,
|
||||||
onNavigateToCamera: (String) -> Unit,
|
onNavigateToCamera: (String) -> Unit,
|
||||||
onNavigateToSubfolder: (String) -> Unit,
|
onNavigateToSubfolder: (folderUri: String, folderName: String) -> Unit,
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
viewModel: GalleryViewModel = hiltViewModel(),
|
viewModel: GalleryViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
@@ -281,9 +281,7 @@ fun GalleryScreen(
|
|||||||
title = {
|
title = {
|
||||||
Column {
|
Column {
|
||||||
Text(
|
Text(
|
||||||
uiState.folderName.ifEmpty {
|
uiState.folderName,
|
||||||
stringResource(R.string.gallery_title)
|
|
||||||
},
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
@@ -408,14 +406,6 @@ fun GalleryScreen(
|
|||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
when {
|
when {
|
||||||
|
|
||||||
uiState.selectedPhoto != null -> {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(Color.Black),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
!uiState.viewPreferencesLoaded -> {
|
!uiState.viewPreferencesLoaded -> {
|
||||||
Box(modifier = Modifier.fillMaxSize())
|
Box(modifier = Modifier.fillMaxSize())
|
||||||
}
|
}
|
||||||
@@ -442,7 +432,7 @@ fun GalleryScreen(
|
|||||||
|
|
||||||
onFolderClick = {
|
onFolderClick = {
|
||||||
viewModel.prefetchFolderForNavigation(it.uri.toString())
|
viewModel.prefetchFolderForNavigation(it.uri.toString())
|
||||||
onNavigateToSubfolder(it.uri.toString())
|
onNavigateToSubfolder(it.uri.toString(), it.name)
|
||||||
},
|
},
|
||||||
onFolderCompress = { viewModel.zipFolderAndShare(it) },
|
onFolderCompress = { viewModel.zipFolderAndShare(it) },
|
||||||
onFolderCompressJpeg85 = { viewModel.zipFolderCompressedJpegsAndShare(it) },
|
onFolderCompressJpeg85 = { viewModel.zipFolderCompressedJpegsAndShare(it) },
|
||||||
@@ -484,12 +474,14 @@ fun GalleryScreen(
|
|||||||
enter = fadeIn(tween(250)),
|
enter = fadeIn(tween(250)),
|
||||||
exit = fadeOut(tween(150)),
|
exit = fadeOut(tween(150)),
|
||||||
) {
|
) {
|
||||||
DraggableCameraFab(
|
if (uiState.viewPreferencesLoaded) {
|
||||||
xFraction = uiState.cameraFabXFraction,
|
DraggableCameraFab(
|
||||||
yFraction = uiState.cameraFabYFraction,
|
xFraction = uiState.cameraFabXFraction,
|
||||||
onPositionChange = viewModel::saveCameraFabPosition,
|
yFraction = uiState.cameraFabYFraction,
|
||||||
onClick = { onNavigateToCamera(uiState.currentFolderUri ?: folderUri) },
|
onPositionChange = viewModel::saveCameraFabPosition,
|
||||||
)
|
onClick = { onNavigateToCamera(uiState.currentFolderUri ?: folderUri) },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionActionsBar(
|
SelectionActionsBar(
|
||||||
@@ -670,16 +662,16 @@ private fun ZoomablePhoto(
|
|||||||
|
|
||||||
Box(modifier = modifier.fillMaxSize()) {
|
Box(modifier = modifier.fillMaxSize()) {
|
||||||
|
|
||||||
AsyncImage(
|
if (fullAlpha < 1f) {
|
||||||
model = remember(photo.uri, context, fadeMs) {
|
AsyncImage(
|
||||||
thumbnailDraftRequest(context, photo.uri, crossfadeMillis = fadeMs)
|
model = remember(photo.uri, context, fadeMs) {
|
||||||
},
|
thumbnailDraftRequest(context, photo.uri, crossfadeMillis = fadeMs)
|
||||||
contentDescription = null,
|
},
|
||||||
contentScale = ContentScale.Fit,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
contentScale = ContentScale.Fit,
|
||||||
.fillMaxSize()
|
modifier = Modifier.fillMaxSize(),
|
||||||
.graphicsLayer { alpha = 1f - fullAlpha },
|
)
|
||||||
)
|
}
|
||||||
CoilZoomAsyncImage(
|
CoilZoomAsyncImage(
|
||||||
model = fullImageRequest,
|
model = fullImageRequest,
|
||||||
contentDescription = photo.name,
|
contentDescription = photo.name,
|
||||||
@@ -688,7 +680,7 @@ private fun ZoomablePhoto(
|
|||||||
onError = { isFullReady = false },
|
onError = { isFullReady = false },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.graphicsLayer { alpha = fullAlpha },
|
.alpha(fullAlpha),
|
||||||
zoomState = zoomState,
|
zoomState = zoomState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import coil3.SingletonImageLoader
|
import coil3.SingletonImageLoader
|
||||||
@@ -113,6 +114,7 @@ data class GalleryUiState(
|
|||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class GalleryViewModel @Inject constructor(
|
class GalleryViewModel @Inject constructor(
|
||||||
|
savedStateHandle: SavedStateHandle,
|
||||||
private val preferencesRepository: UserPreferencesRepository,
|
private val preferencesRepository: UserPreferencesRepository,
|
||||||
private val listGalleryUseCase: ListGalleryUseCase,
|
private val listGalleryUseCase: ListGalleryUseCase,
|
||||||
private val listFolderTreeUseCase: ListFolderTreeUseCase,
|
private val listFolderTreeUseCase: ListFolderTreeUseCase,
|
||||||
@@ -128,7 +130,11 @@ class GalleryViewModel @Inject constructor(
|
|||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val uiState: StateFlow<GalleryUiState>
|
val uiState: StateFlow<GalleryUiState>
|
||||||
field: MutableStateFlow<GalleryUiState> = MutableStateFlow(GalleryUiState())
|
field: MutableStateFlow<GalleryUiState> = MutableStateFlow(
|
||||||
|
// Navigation puts type-safe route args into the SavedStateHandle, so the
|
||||||
|
// title is correct from the very first frame, before any listing completes.
|
||||||
|
GalleryUiState(folderName = savedStateHandle.get<String>("folderName").orEmpty()),
|
||||||
|
)
|
||||||
|
|
||||||
private var forceReload = false
|
private var forceReload = false
|
||||||
|
|
||||||
@@ -199,6 +205,9 @@ class GalleryViewModel @Inject constructor(
|
|||||||
loadJob = viewModelScope.launch {
|
loadJob = viewModelScope.launch {
|
||||||
uiState.value = uiState.value.copy(
|
uiState.value = uiState.value.copy(
|
||||||
currentFolderUri = folderUriString,
|
currentFolderUri = folderUriString,
|
||||||
|
folderName = state.folderName.ifEmpty {
|
||||||
|
folderUriString.substringAfterLast(':').substringAfterLast('/')
|
||||||
|
},
|
||||||
isLoading = true,
|
isLoading = true,
|
||||||
error = null,
|
error = null,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,20 +4,7 @@
|
|||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="108"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="108">
|
android:viewportHeight="108">
|
||||||
|
|
||||||
<path
|
<path
|
||||||
android:strokeColor="#000000"
|
android:fillColor="#C9584D"
|
||||||
android:strokeWidth="3.375"
|
android:pathData="M66.90,53.85C66.90,54.93 66.82,56.08 66.67,57.08C66.53,58.07 66.30,58.95 66.00,59.80C65.71,60.66 65.34,61.46 64.91,62.20C64.48,62.94 63.97,63.63 63.41,64.25C62.86,64.87 62.23,65.42 61.56,65.90C60.89,66.38 60.16,66.79 59.39,67.11C58.61,67.44 57.82,67.69 56.92,67.85C56.02,68.02 54.97,68.10 54.00,68.10C53.03,68.10 51.98,68.02 51.08,67.85C50.18,67.69 49.39,67.44 48.61,67.11C47.84,66.79 47.11,66.38 46.44,65.90C45.77,65.42 45.14,64.87 44.59,64.25C44.03,63.63 43.52,62.94 43.09,62.20C42.66,61.46 42.29,60.66 42.00,59.80C41.70,58.95 41.47,58.07 41.33,57.08C41.18,56.08 41.10,54.93 41.10,53.85C41.10,52.77 41.18,51.62 41.33,50.62C41.47,49.63 41.70,48.75 42.00,47.90C42.29,47.04 42.66,46.24 43.09,45.50C43.52,44.76 44.03,44.07 44.59,43.45C45.14,42.83 45.77,42.28 46.44,41.80C47.11,41.32 47.84,40.91 48.61,40.59C49.39,40.26 50.18,40.01 51.08,39.85C51.98,39.68 53.03,39.60 54.00,39.60C54.97,39.60 56.02,39.68 56.92,39.85C57.82,40.01 58.61,40.26 59.39,40.59C60.16,40.91 60.89,41.32 61.56,41.80C62.23,42.28 62.86,42.83 63.41,43.45C63.97,44.07 64.48,44.76 64.91,45.50C65.34,46.24 65.71,47.04 66.00,47.90C66.30,48.75 66.53,49.63 66.67,50.62C66.82,51.62 66.90,52.77 66.90,53.85ZM61.50,54.00C61.50,53.30 61.46,52.54 61.37,51.90C61.29,51.25 61.16,50.67 60.99,50.12C60.82,49.56 60.61,49.03 60.36,48.55C60.12,48.07 59.83,47.62 59.51,47.21C59.20,46.81 58.84,46.45 58.46,46.14C58.08,45.83 57.66,45.56 57.22,45.35C56.78,45.13 56.33,44.97 55.81,44.86C55.30,44.75 54.70,44.70 54.15,44.70C53.60,44.70 53.00,44.75 52.49,44.86C51.97,44.97 51.52,45.13 51.08,45.35C50.64,45.56 50.22,45.83 49.84,46.14C49.46,46.45 49.10,46.81 48.79,47.21C48.47,47.62 48.18,48.07 47.94,48.55C47.69,49.03 47.48,49.56 47.31,50.12C47.14,50.67 47.01,51.25 46.93,51.90C46.84,52.54 46.80,53.30 46.80,54.00C46.80,54.70 46.84,55.46 46.93,56.10C47.01,56.75 47.14,57.33 47.31,57.88C47.48,58.44 47.69,58.97 47.94,59.45C48.18,59.93 48.47,60.38 48.79,60.79C49.10,61.19 49.46,61.55 49.84,61.86C50.22,62.17 50.64,62.44 51.08,62.65C51.52,62.87 51.97,63.03 52.49,63.14C53.00,63.25 53.60,63.30 54.15,63.30C54.70,63.30 55.30,63.25 55.81,63.14C56.33,63.03 56.78,62.87 57.22,62.65C57.66,62.44 58.08,62.17 58.46,61.86C58.84,61.55 59.20,61.19 59.51,60.79C59.83,60.38 60.12,59.93 60.36,59.45C60.61,58.97 60.82,58.44 60.99,57.88C61.16,57.33 61.29,56.75 61.37,56.10C61.46,55.46 61.50,54.70 61.50,54.00Z" />
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:pathData="M 43.453125 32.90625 L 64.546875 32.90625 a 10.546875 10.546875 0 0 1 10.546875 10.546875 L 75.09375 64.546875 a 10.546875 10.546875 0 0 1 -10.546875 10.546875 L 43.453125 75.09375 a 10.546875 10.546875 0 0 1 -10.546875 -10.546875 L 32.90625 43.453125 a 10.546875 10.546875 0 0 1 10.546875 -10.546875 Z" />
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:strokeColor="#000000"
|
|
||||||
android:strokeWidth="3.375"
|
|
||||||
android:pathData="M 41.34375 54 a 12.65625 12.65625 0 1 0 25.3125 0 a 12.65625 12.65625 0 1 0 -25.3125 0 Z" />
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:fillColor="#d94e47"
|
|
||||||
android:pathData="M 68.71875 38.390625 a 2.53125 2.53125 0 1 0 5.0625 0 a 2.53125 2.53125 0 1 0 -5.0625 0 Z" />
|
|
||||||
|
|
||||||
</vector>
|
</vector>
|
||||||
@@ -4,20 +4,7 @@
|
|||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="108"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="108">
|
android:viewportHeight="108">
|
||||||
|
|
||||||
<path
|
|
||||||
android:strokeColor="#FFFFFF"
|
|
||||||
android:strokeWidth="3.375"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:pathData="M 43.453125 32.90625 L 64.546875 32.90625 a 10.546875 10.546875 0 0 1 10.546875 10.546875 L 75.09375 64.546875 a 10.546875 10.546875 0 0 1 -10.546875 10.546875 L 43.453125 75.09375 a 10.546875 10.546875 0 0 1 -10.546875 -10.546875 L 32.90625 43.453125 a 10.546875 10.546875 0 0 1 10.546875 -10.546875 Z" />
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:strokeColor="#FFFFFF"
|
|
||||||
android:strokeWidth="3.375"
|
|
||||||
android:pathData="M 41.34375 54 a 12.65625 12.65625 0 1 0 25.3125 0 a 12.65625 12.65625 0 1 0 -25.3125 0 Z" />
|
|
||||||
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFF"
|
android:fillColor="#FFFFFF"
|
||||||
android:pathData="M 67.5 38.390625 a 2.109375 2.109375 0 1 0 4.21875 0 a 2.109375 2.109375 0 1 0 -4.21875 0 Z" />
|
android:pathData="M66.90,53.85C66.90,54.93 66.82,56.08 66.67,57.08C66.53,58.07 66.30,58.95 66.00,59.80C65.71,60.66 65.34,61.46 64.91,62.20C64.48,62.94 63.97,63.63 63.41,64.25C62.86,64.87 62.23,65.42 61.56,65.90C60.89,66.38 60.16,66.79 59.39,67.11C58.61,67.44 57.82,67.69 56.92,67.85C56.02,68.02 54.97,68.10 54.00,68.10C53.03,68.10 51.98,68.02 51.08,67.85C50.18,67.69 49.39,67.44 48.61,67.11C47.84,66.79 47.11,66.38 46.44,65.90C45.77,65.42 45.14,64.87 44.59,64.25C44.03,63.63 43.52,62.94 43.09,62.20C42.66,61.46 42.29,60.66 42.00,59.80C41.70,58.95 41.47,58.07 41.33,57.08C41.18,56.08 41.10,54.93 41.10,53.85C41.10,52.77 41.18,51.62 41.33,50.62C41.47,49.63 41.70,48.75 42.00,47.90C42.29,47.04 42.66,46.24 43.09,45.50C43.52,44.76 44.03,44.07 44.59,43.45C45.14,42.83 45.77,42.28 46.44,41.80C47.11,41.32 47.84,40.91 48.61,40.59C49.39,40.26 50.18,40.01 51.08,39.85C51.98,39.68 53.03,39.60 54.00,39.60C54.97,39.60 56.02,39.68 56.92,39.85C57.82,40.01 58.61,40.26 59.39,40.59C60.16,40.91 60.89,41.32 61.56,41.80C62.23,42.28 62.86,42.83 63.41,43.45C63.97,44.07 64.48,44.76 64.91,45.50C65.34,46.24 65.71,47.04 66.00,47.90C66.30,48.75 66.53,49.63 66.67,50.62C66.82,51.62 66.90,52.77 66.90,53.85ZM61.50,54.00C61.50,53.30 61.46,52.54 61.37,51.90C61.29,51.25 61.16,50.67 60.99,50.12C60.82,49.56 60.61,49.03 60.36,48.55C60.12,48.07 59.83,47.62 59.51,47.21C59.20,46.81 58.84,46.45 58.46,46.14C58.08,45.83 57.66,45.56 57.22,45.35C56.78,45.13 56.33,44.97 55.81,44.86C55.30,44.75 54.70,44.70 54.15,44.70C53.60,44.70 53.00,44.75 52.49,44.86C51.97,44.97 51.52,45.13 51.08,45.35C50.64,45.56 50.22,45.83 49.84,46.14C49.46,46.45 49.10,46.81 48.79,47.21C48.47,47.62 48.18,48.07 47.94,48.55C47.69,49.03 47.48,49.56 47.31,50.12C47.14,50.67 47.01,51.25 46.93,51.90C46.84,52.54 46.80,53.30 46.80,54.00C46.80,54.70 46.84,55.46 46.93,56.10C47.01,56.75 47.14,57.33 47.31,57.88C47.48,58.44 47.69,58.97 47.94,59.45C48.18,59.93 48.47,60.38 48.79,60.79C49.10,61.19 49.46,61.55 49.84,61.86C50.22,62.17 50.64,62.44 51.08,62.65C51.52,62.87 51.97,63.03 52.49,63.14C53.00,63.25 53.60,63.30 54.15,63.30C54.70,63.30 55.30,63.25 55.81,63.14C56.33,63.03 56.78,62.87 57.22,62.65C57.66,62.44 58.08,62.17 58.46,61.86C58.84,61.55 59.20,61.19 59.51,60.79C59.83,60.38 60.12,59.93 60.36,59.45C60.61,58.97 60.82,58.44 60.99,57.88C61.16,57.33 61.29,56.75 61.37,56.10C61.46,55.46 61.50,54.70 61.50,54.00Z" />
|
||||||
|
|
||||||
</vector>
|
</vector>
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 982 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -46,7 +46,6 @@
|
|||||||
<item quantity="other">%d photos</item>
|
<item quantity="other">%d photos</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
<string name="gallery_title">Gallery</string>
|
|
||||||
<string name="gallery_create_subfolder">Create subfolder</string>
|
<string name="gallery_create_subfolder">Create subfolder</string>
|
||||||
<string name="gallery_sort_ascending">Sort ascending</string>
|
<string name="gallery_sort_ascending">Sort ascending</string>
|
||||||
<string name="gallery_sort_descending">Sort descending</string>
|
<string name="gallery_sort_descending">Sort descending</string>
|
||||||
|
|||||||