Skip to content

Commit

Permalink
[feature|build] Supports exporting stickers to Zip backup file when m…
Browse files Browse the repository at this point in the history
…ultiple selections on the search page or on the sticker list page; update dependencies version
  • Loading branch information
SkyD666 committed Dec 16, 2023
1 parent caf2a04 commit d7b3625
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 45 deletions.
10 changes: 5 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ android {
applicationId "com.skyd.rays"
minSdk 24
targetSdk 34
versionCode 55
versionName "2.0-alpha12"
versionCode 56
versionName "2.0-alpha13"
flavorDimensions = ["versionName"]

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -132,15 +132,15 @@ dependencies {
implementation "androidx.compose.material:material:1.5.4"
implementation "androidx.compose.material:material-icons-extended:1.5.4"
implementation "androidx.compose.ui:ui-tooling-preview:$md3_version"
implementation "com.google.android.material:material:1.10.0"
implementation "com.google.android.material:material:1.11.0"
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.2"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
implementation "androidx.activity:activity-compose:1.8.1"
implementation "androidx.activity:activity-compose:1.8.2"
implementation "androidx.palette:palette-ktx:1.0.0"
implementation "com.google.dagger:hilt-android:2.48.1"
kapt "com.google.dagger:hilt-android-compiler:2.48.1"
implementation "androidx.hilt:hilt-navigation-compose:1.1.0"
implementation "androidx.navigation:navigation-compose:2.7.5"
implementation "androidx.navigation:navigation-compose:2.7.6"
implementation "androidx.security:security-crypto:1.1.0-alpha06"
implementation "com.google.accompanist:accompanist-drawablepainter:$accompanist_version"
implementation "io.coil-kt:coil-compose:2.5.0"
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/com/skyd/rays/model/db/dao/sticker/StickerDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ interface StickerDao {
@Query("SELECT * FROM $STICKER_TABLE_NAME")
fun getAllStickerWithTagsList(): List<StickerWithTags>

@Transaction
@Query("SELECT * FROM $STICKER_TABLE_NAME WHERE $UUID_COLUMN IN (:uuids)")
fun getAllStickerWithTagsList(uuids: Collection<String>): List<StickerWithTags>

@Transaction
@Query("SELECT * FROM $STICKER_TABLE_NAME")
fun getStickerList(): List<StickerBean>
Expand Down Expand Up @@ -182,6 +186,15 @@ interface StickerDao {
.fromApplication(appContext, StickerDaoEntryPoint::class.java)
var updatedCount = 0
stickerWithTagsList.forEach {
val currentTimeMillis = System.currentTimeMillis()
it.stickerWithTags.sticker.apply {
if (createTime == 0L) {
createTime = currentTimeMillis
}
if (modifyTime == 0L) {
modifyTime = currentTimeMillis
}
}
val updated = proxy.handle(
stickerDao = this,
tagDao = hiltEntryPoint.tagDao,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ object SearchResultSortPreference : BasePreference<String> {
override fun fromPreferences(preferences: Preferences): String = preferences[key] ?: default

fun toDisplayName(sort: String): String = when (sort) {
"CreateTime" -> appContext.getString(R.string.search_result_sort_create_time)
"ModifyTime" -> appContext.getString(R.string.search_result_sort_modify_time)
"CreateTime" -> appContext.getString(R.string.sticker_create_time)
"ModifyTime" -> appContext.getString(R.string.sticker_modify_time)
"TagCount" -> appContext.getString(R.string.search_result_sort_tag_count)
"Title" -> appContext.getString(R.string.search_result_sort_title)
"ClickCount" -> appContext.getString(R.string.search_result_sort_click_count)
"ShareCount" -> appContext.getString(R.string.search_result_sort_share_count)
else -> appContext.getString(R.string.search_result_sort_create_time)
"ClickCount" -> appContext.getString(R.string.sticker_click_count)
"ShareCount" -> appContext.getString(R.string.sticker_share_count)
else -> appContext.getString(R.string.sticker_create_time)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,29 @@ class ImportExportFilesRepository @Inject constructor(
}
}

suspend fun requestExport(dirUri: Uri): Flow<ImportExportInfo> {
suspend fun requestExport(
dirUri: Uri,
excludeClickCount: Boolean = false,
excludeShareCount: Boolean = false,
excludeCreateTime: Boolean = false,
excludeModifyTime: Boolean = false,
exportStickers: Collection<String>? = null,
): Flow<ImportExportInfo> {
return flowOnIo {
val startTime = System.currentTimeMillis()
val allStickerWithTagsList = stickerDao.getAllStickerWithTagsList()
val allStickerWithTagsList = if (exportStickers == null) {
stickerDao.getAllStickerWithTagsList()
} else {
stickerDao.getAllStickerWithTagsList(exportStickers)
}
val totalCount = allStickerWithTagsList.size
var currentCount = 0
EXPORT_FILES_DIR.deleteRecursively()
allStickerWithTagsList.forEach {
if (excludeClickCount) it.sticker.clickCount = 0L
if (excludeShareCount) it.sticker.shareCount = 0L
if (excludeCreateTime) it.sticker.createTime = 0L
if (excludeModifyTime) it.sticker.modifyTime = 0L
stickerWithTagsToJsonFile(it)
stickerUuidToFile(it.sticker.uuid)
.copyTo(File("$EXPORT_FILES_DIR/$BACKUP_STICKER_DIR", it.sticker.uuid))
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/com/skyd/rays/ui/activity/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ class MainActivity : AppCompatActivity() {
WebDavScreen()
}
composable(route = EXPORT_FILES_SCREEN_ROUTE) {
ExportFilesScreen()
ExportFilesScreen(
exportStickers = it.arguments?.getStringArrayList("exportStickers")
)
}
composable(route = IMPORT_FILES_SCREEN_ROUTE) {
ImportFilesScreen()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.skyd.rays.ui.component.dialog

import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import com.skyd.rays.R

@Composable
fun MultiChoiceDialog(
modifier: Modifier = Modifier,
visible: Boolean,
onDismissRequest: () -> Unit = {},
title: @Composable (() -> Unit)? = null,
options: List<String>,
checkedIndexList: List<Int>,
onConfirm: (List<Int>) -> Unit,
confirmText: String = stringResource(id = R.string.dialog_ok),
dismissText: String? = stringResource(id = R.string.cancel),
) {
val selectedIndexList = remember(visible) { checkedIndexList.toMutableStateList() }
RaysDialog(
modifier = modifier,
visible = visible,
onDismissRequest = onDismissRequest,
title = title,
text = {
Column {
options.forEachIndexed { index, item ->
MultiChoiceItem(
checked = index in selectedIndexList,
text = item,
onClick = {
if (index in selectedIndexList) {
selectedIndexList.remove(index)
} else {
selectedIndexList.add(index)
}
},
)
}
}
},
confirmButton = {
TextButton(onClick = { onConfirm(selectedIndexList) }) { Text(text = confirmText) }
},
dismissButton = if (dismissText == null) null else {
{ TextButton(onClick = onDismissRequest) { Text(text = dismissText) } }
},
)
}

@Composable
private fun MultiChoiceItem(
checked: Boolean,
text: String,
onClick: () -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
Row(
Modifier
.fillMaxWidth()
.height(50.dp)
.clip(RoundedCornerShape(20))
.selectable(
selected = checked,
onClick = onClick,
interactionSource = interactionSource,
indication = LocalIndication.current,
role = Role.Checkbox
)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = checked,
interactionSource = interactionSource,
onCheckedChange = null // null recommended for accessibility with screen readers
)
Text(
text = text,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -451,17 +451,17 @@ fun StickerDetailInfo(modifier: Modifier = Modifier, stickerWithTags: StickerWit
)
DetailInfoItem(
icon = Icons.Default.AdsClick,
title = stringResource(id = R.string.detail_screen_sticker_info_click_count),
title = stringResource(id = R.string.sticker_click_count),
text = sticker.clickCount.toString(),
)
DetailInfoItem(
icon = Icons.Default.Share,
title = stringResource(id = R.string.detail_screen_sticker_info_share_count),
title = stringResource(id = R.string.sticker_share_count),
text = sticker.shareCount.toString()
)
DetailInfoItem(
icon = Icons.Default.AddCircle,
title = stringResource(id = R.string.detail_screen_sticker_info_create_time),
title = stringResource(id = R.string.sticker_create_time),
text = dateTime(sticker.createTime)
)
DetailInfoItem(
Expand Down
26 changes: 24 additions & 2 deletions app/src/main/java/com/skyd/rays/ui/screen/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.skyd.rays.ui.screen.home

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand Down Expand Up @@ -41,6 +42,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
Expand All @@ -63,13 +65,15 @@ import com.skyd.rays.ui.screen.add.openAddScreen
import com.skyd.rays.ui.screen.detail.openDetailScreen
import com.skyd.rays.ui.screen.search.SEARCH_SCREEN_ROUTE
import com.skyd.rays.ui.screen.stickerslist.openStickersListScreen
import com.skyd.rays.util.sendStickerByUuid


const val HOME_SCREEN_ROUTE = "homeScreen"

@Composable
fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
val navController = LocalNavController.current
val context = LocalContext.current
val snackbarHostState = remember { SnackbarHostState() }
val uiState by viewModel.viewState.collectAsStateWithLifecycle()
var fabHeight by remember { mutableStateOf(0.dp) }
Expand Down Expand Up @@ -134,6 +138,12 @@ fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
count = mostSharedStickersList.size,
itemImage = { mostSharedStickersList[it].sticker.uuid },
itemTitle = { mostSharedStickersList[it].sticker.title },
onItemLongClick = {
context.sendStickerByUuid(
uuid = mostSharedStickersList[it].sticker.uuid,
onSuccess = { mostSharedStickersList[it].sticker.shareCount++ }
)
},
onItemClick = {
openDetailScreen(
navController = navController,
Expand All @@ -149,6 +159,12 @@ fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
count = recentCreatedStickersList.size,
itemImage = { recentCreatedStickersList[it].sticker.uuid },
itemTitle = { recentCreatedStickersList[it].sticker.title },
onItemLongClick = {
context.sendStickerByUuid(
uuid = recentCreatedStickersList[it].sticker.uuid,
onSuccess = { recentCreatedStickersList[it].sticker.shareCount++ }
)
},
onItemClick = {
openDetailScreen(
navController = navController,
Expand Down Expand Up @@ -203,6 +219,7 @@ private fun DisplayStickersRow(
count: Int,
itemImage: (Int) -> String,
itemTitle: (Int) -> String,
onItemLongClick: (Int) -> Unit,
onItemClick: (Int) -> Unit,
) {
Column {
Expand All @@ -227,11 +244,16 @@ private fun DisplayStickersRow(
) {
items(count) { index ->
Column(modifier = Modifier.width(IntrinsicSize.Min)) {
ElevatedCard(onClick = { onItemClick(index) }) {
ElevatedCard {
RaysImage(
modifier = Modifier
.height(150.dp)
.aspectRatio(1f),
.aspectRatio(1f)
.combinedClickable(
onLongClick = { onItemLongClick(index) },
onClick = { onItemClick(index) }

),
uuid = itemImage(index),
contentScale = ContentScale.Crop,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.FolderZip
import androidx.compose.material.icons.filled.Save
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.outlined.CheckCircle
Expand Down Expand Up @@ -224,6 +225,7 @@ internal fun MultiSelectActionBar(
selectedStickers: List<StickerWithTags>,
onDeleteClick: () -> Unit,
onExportClick: () -> Unit,
onExportAsZipClick: () -> Unit,
) {
val context = LocalContext.current
val windowSizeClass = LocalWindowSizeClass.current
Expand Down Expand Up @@ -256,6 +258,14 @@ internal fun MultiSelectActionBar(
contentDescription = stringResource(id = R.string.home_screen_export)
)
},
@Composable {
RaysIconButton(
onClick = onExportAsZipClick,
enabled = selectedStickers.isNotEmpty(),
imageVector = Icons.Default.FolderZip,
contentDescription = stringResource(id = R.string.home_screen_export_to_backup_zip)
)
},
@Composable {
RaysIconButton(
onClick = onDeleteClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import com.skyd.rays.ui.local.LocalQuery
import com.skyd.rays.ui.local.LocalShowPopularTags
import com.skyd.rays.ui.local.LocalWindowSizeClass
import com.skyd.rays.ui.screen.detail.openDetailScreen
import com.skyd.rays.ui.screen.settings.data.importexport.file.exportfiles.openExportFilesScreen
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -245,6 +246,12 @@ fun SearchScreen(viewModel: SearchViewModel = hiltViewModel()) {
searchResultUiState.stickerWithTagsList.toSet()
},
onExportClick = { openMultiStickersExportPathDialog = true },
onExportAsZipClick = {
openExportFilesScreen(
navController = navController,
exportStickers = selectedStickers.map { it.sticker.uuid },
)
},
)
ExportDialog(
visible = openMultiStickersExportPathDialog,
Expand Down
Loading

0 comments on commit d7b3625

Please sign in to comment.