Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions app/src/commonMain/kotlin/com/crosspaste/db/paste/PasteDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.crosspaste.paste.PasteTag
import com.crosspaste.paste.SearchContentService
import com.crosspaste.paste.item.PasteFiles
import com.crosspaste.paste.item.PasteItem
import com.crosspaste.paste.item.PasteItemProperties
import com.crosspaste.paste.plugin.process.PasteProcessPlugin
import com.crosspaste.path.UserDataPathProvider
import com.crosspaste.task.TaskBuilder
Expand All @@ -28,6 +29,8 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.coroutines.withContext
import kotlin.time.ExperimentalTime

Expand Down Expand Up @@ -467,14 +470,18 @@ class PasteDao(
commonConfigManager.getCurrentConfig().maxBackupFileSize,
)

val isLargeFile = fileSize > maxBackupFileSize
val syncToDownload =
fileSize > maxBackupFileSize ||
pasteData.pasteAppearItem?.extraInfo
?.get(PasteItemProperties.SYNC_TO_DOWNLOAD)
?.jsonPrimitive?.booleanOrNull == true

val pasteCoordinate = pasteData.getPasteCoordinate(id)
val pasteAppearItem = pasteData.pasteAppearItem
val pasteCollection = pasteData.pasteCollection

val newPasteAppearItem = pasteAppearItem?.bind(pasteCoordinate, isLargeFile)
val newPasteCollection = pasteCollection.bind(pasteCoordinate, isLargeFile)
val newPasteAppearItem = pasteAppearItem?.bind(pasteCoordinate, syncToDownload)
val newPasteCollection = pasteCollection.bind(pasteCoordinate, syncToDownload)

val newPasteData = pasteData.copy(
id = id,
Expand Down
19 changes: 18 additions & 1 deletion app/src/commonMain/kotlin/com/crosspaste/paste/PasteCollector.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ package com.crosspaste.paste

import com.crosspaste.app.AppInfo
import com.crosspaste.db.paste.PasteDao
import com.crosspaste.paste.item.PasteFiles
import com.crosspaste.paste.item.PasteItem
import com.crosspaste.paste.item.PasteItem.Companion.copy
import com.crosspaste.paste.item.PasteItemProperties
import com.crosspaste.paste.plugin.type.PasteTypePlugin
import com.crosspaste.utils.LoggerExtension.logSuspendExecutionTime
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.serialization.json.JsonPrimitive
import kotlin.collections.set
import kotlin.reflect.KClass

class PasteCollector(
itemCount: Int,
private val appInfo: AppInfo,
private val pasteDao: PasteDao,
private val dragAndDrop: Boolean = false,
) {

private val logger = KotlinLogging.logger {}
Expand Down Expand Up @@ -102,7 +107,19 @@ class PasteCollector(
markDeletePasteData(id)
} else {
runCatching {
val pasteItems = preCollectors.flatMap { it.values }
var pasteItems = preCollectors.flatMap { it.values }
if (dragAndDrop) {
pasteItems =
pasteItems.map { item ->
if (item is PasteFiles) {
item.copy {
put(PasteItemProperties.SYNC_TO_DOWNLOAD, JsonPrimitive(true))
}
} else {
item
}
}
}
pasteDao.releaseLocalPasteData(id, pasteItems)
}.onFailure { e ->
logger.error(e) { "Failed to complete paste $id" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface TransferableConsumer {
pasteTransferable: PasteTransferable,
source: String?,
remote: Boolean,
dragAndDrop: Boolean = false,
): Result<Unit>

fun getPlugin(identity: String): PasteTypePlugin?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class FilesToImagesPlugin(
basePath = basePath,
relativePathList = relativePathList,
fileInfoTreeMap = fileInfoTreeMap,
extraInfo = pasteAppearItem.extraInfo,
)
} else {
pasteAppearItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class DesktopTransferableConsumer(
pasteTransferable: PasteTransferable,
source: String?,
remote: Boolean,
dragAndDrop: Boolean,
): Result<Unit> {
return runCatching {
logSuspendExecutionTime(logger, "consume") {
Expand All @@ -47,7 +48,7 @@ class DesktopTransferableConsumer(
return@logSuspendExecutionTime
}

val pasteCollector = PasteCollector(dataFlavorMap.size, appInfo, pasteDao)
val pasteCollector = PasteCollector(dataFlavorMap.size, appInfo, pasteDao, dragAndDrop)

preCollect(dataFlavorMap, pasteTransferable, pasteCollector)
pasteCollector.createPrePasteData(source, remote = remote)?.also { id ->
Expand Down
122 changes: 87 additions & 35 deletions app/src/desktopMain/kotlin/com/crosspaste/ui/DragTargetContentView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
Expand All @@ -33,19 +35,26 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draganddrop.DragAndDropEvent
import androidx.compose.ui.draganddrop.DragAndDropTarget
import androidx.compose.ui.draganddrop.awtTransferable
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.text.style.TextAlign
import com.composables.icons.materialsymbols.MaterialSymbols
import com.composables.icons.materialsymbols.rounded.Content_paste
import com.crosspaste.app.DesktopAppWindowManager
import com.crosspaste.i18n.GlobalCopywriter
import com.crosspaste.paste.DesktopReadTransferable
import com.crosspaste.paste.TransferableConsumer
import com.crosspaste.ui.theme.AppUISize.huge
import com.crosspaste.ui.theme.AppUISize.large2X
import com.crosspaste.ui.theme.AppUISize.massive
import com.crosspaste.ui.theme.AppUISize.enormous
import com.crosspaste.ui.theme.AppUISize.medium
import com.crosspaste.ui.theme.AppUISize.mediumRoundedCornerShape
import com.crosspaste.ui.theme.AppUISize.tiny
import com.crosspaste.ui.theme.AppUISize.tiny4X
import com.crosspaste.ui.theme.AppUISize.xLarge
import com.crosspaste.ui.theme.AppUISize.xLargeRoundedCornerShape
import com.crosspaste.ui.theme.AppUISize.xxLarge
import kotlinx.coroutines.runBlocking
import org.koin.compose.koinInject

Expand All @@ -57,7 +66,7 @@ fun DragTargetContentView() {
val pasteConsumer = koinInject<TransferableConsumer>()
var isDragging by remember { mutableStateOf(false) }
val animatedAlpha by animateFloatAsState(
targetValue = if (isDragging) 0.8f else 0f,
targetValue = if (isDragging) 0.85f else 0f,
animationSpec = tween(300),
label = "drag_target_alpha",
)
Expand All @@ -80,7 +89,7 @@ fun DragTargetContentView() {
val source: String? = appWindowManager.getCurrentActiveAppName()
val pasteTransferable = DesktopReadTransferable(transferable)
return runBlocking {
pasteConsumer.consume(pasteTransferable, source, false)
pasteConsumer.consume(pasteTransferable, source, remote = false, dragAndDrop = true)
}.isSuccess
}
}
Expand All @@ -100,53 +109,96 @@ fun DragTargetContentView() {
Modifier
.fillMaxSize()
.background(
MaterialTheme.colorScheme.primaryContainer.copy(alpha = animatedAlpha),
MaterialTheme.colorScheme.surface.copy(alpha = animatedAlpha),
),
)

AnimatedVisibility(
visible = isDragging,
enter =
fadeIn(animationSpec = tween(300)) +
fadeIn(animationSpec = tween(250)) +
scaleIn(
initialScale = 0.9f,
animationSpec = tween(300),
initialScale = 0.92f,
animationSpec = tween(250),
),
exit =
fadeOut(animationSpec = tween(300)) +
fadeOut(animationSpec = tween(200)) +
scaleOut(
targetScale = 0.9f,
animationSpec = tween(300),
targetScale = 0.92f,
animationSpec = tween(200),
),
modifier = Modifier.align(Alignment.Center),
) {
Column(
val borderColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f)
Surface(
modifier =
Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(horizontal = massive)
.clip(mediumRoundedCornerShape)
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(vertical = large2X),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
.padding(horizontal = xLarge)
.drawWithContent {
drawContent()
val strokeWidth = tiny4X.toPx()
val dashEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
val halfStroke = strokeWidth / 2
drawRoundRect(
color = borderColor,
topLeft = Offset(halfStroke, halfStroke),
size =
Size(
width = size.width - strokeWidth,
height = size.height - strokeWidth,
),
style =
Stroke(
width = strokeWidth,
pathEffect = dashEffect,
),
cornerRadius = CornerRadius(xLarge.toPx()),
)
},
shape = xLargeRoundedCornerShape,
color = MaterialTheme.colorScheme.surfaceContainerHigh,
) {
Icon(
imageVector = MaterialSymbols.Rounded.Content_paste,
contentDescription = "clipboard icon",
modifier = Modifier.size(huge),
tint = MaterialTheme.colorScheme.onPrimaryContainer,
)
Column(
modifier =
Modifier
.fillMaxWidth()
.padding(vertical = xxLarge, horizontal = medium),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Surface(
modifier = Modifier.size(enormous),
shape = RoundedCornerShape(xxLarge),
color = MaterialTheme.colorScheme.primaryContainer,
) {
Icon(
imageVector = MaterialSymbols.Rounded.Content_paste,
contentDescription = null,
modifier = Modifier.padding(medium),
tint = MaterialTheme.colorScheme.onPrimaryContainer,
)
}

Spacer(modifier = Modifier.height(medium))
Spacer(modifier = Modifier.height(medium))

Text(
text = copywriter.getText("drop_to_clipboard_and_sync"),
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onPrimaryContainer,
fontWeight = FontWeight.Medium,
)
Text(
text = copywriter.getText("drop_to_clipboard_and_sync"),
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center,
)

Spacer(modifier = Modifier.height(tiny))

Text(
text = copywriter.getText("drop_hint"),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center,
)
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=Vertrauen Sie diesem Gerät?
double_click=Doppelklick
download=Herunterladen
drop_to_clipboard_and_sync=Loslassen, um zur Zwischenablage hinzuzufügen und zwischen Geräten zu synchronisieren
drop_hint=Dateien werden in das Download-Verzeichnis der gekoppelten Geräte synchronisiert
edit=Bearbeiten
edit_note_desc=Bitte geben Sie eine Bemerkung für das Gerät ein, um es leichter zu identifizieren.
empty=Leer
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=Do you trust this device?
double_click=Double Click
download=Download
drop_to_clipboard_and_sync=Drop to add to clipboard and sync across devices
drop_hint=Files will be synced to the download directory on paired devices
edit=Edit
edit_note_desc=Please enter a remark name for the device for easy identification.
empty=Empty
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=¿Confía en este dispositivo?
double_click=Doble clic
download=Descargar
drop_to_clipboard_and_sync=Suelta para agregar al portapapeles y sincronizar entre dispositivos
drop_hint=Los archivos se sincronizarán en el directorio de descargas de los dispositivos emparejados
edit=Editar
edit_note_desc=Ingrese un nombre de nota para el dispositivo para identificarlo fácilmente.
empty=Vacío
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/fa.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=آیا به این دستگاه اعتماد داری
double_click=دو بار کلیک
download=دانلود
drop_to_clipboard_and_sync=رها کنید تا به کلیپ‌بورد اضافه و بین دستگاه‌ها همگام‌سازی شود
drop_hint=فایل‌ها در پوشه دانلود دستگاه‌های جفت‌شده همگام‌سازی خواهند شد
edit=ویرایش
edit_note_desc=لطفاً برای شناسایی آسان، یک نام یادداشت برای دستگاه وارد کنید.
empty=خالی
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/fr.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=Faites-vous confiance à cet appareil ?
double_click=Double-cliquer
download=Télécharger
drop_to_clipboard_and_sync=Relâcher pour ajouter au presse-papiers et synchroniser entre les appareils
drop_hint=Les fichiers seront synchronisés dans le répertoire de téléchargement des appareils appairés
edit=Modifier
edit_note_desc=Veuillez saisir un nom de remarque pour l'appareil afin de l'identifier facilement.
empty=Vide
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/ja.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=このデバイスを信頼しますか?
double_click=ダブルクリック
download=ダウンロード
drop_to_clipboard_and_sync=ドロップしてクリップボードに追加し、デバイス間で同期
drop_hint=ファイルはペアリングされたデバイスのダウンロードディレクトリに同期されます
edit=編集
edit_note_desc=識別を容易にするために、デバイスの備考名を入力してください。
empty=空
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/ko.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=이 기기를 신뢰하시나요?
double_click=더블클릭
download=다운로드
drop_to_clipboard_and_sync=놓아서 클립보드에 추가하고 기기 간 동기화
drop_hint=파일은 페어링된 기기의 다운로드 디렉토리로 동기화됩니다
edit=편집
edit_note_desc=식별을 쉽게 하기 위해 장치의 비고 이름을 입력하십시오.
empty=비어있음
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ do_you_trust_this_device?=您信任此设备吗?
double_click=双击
download=下载
drop_to_clipboard_and_sync=释放添加到粘贴板并在设备间同步
drop_hint=文件将同步到配对设备的下载目录
edit=编辑
edit_note_desc=请输入设备的备注名称以方便识别。
empty=空
Expand Down
1 change: 1 addition & 0 deletions app/src/desktopMain/resources/i18n/zh_hant.properties
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ do_you_trust_this_device?=您信任此裝置嗎?
double_click=雙擊
download=下載
drop_to_clipboard_and_sync=釋放添加到剪貼板並在設備間同步
drop_hint=檔案將同步到配對裝置的下載目錄
edit=編輯
edit_note_desc=請輸入設備的備註名稱以方便識別。
empty=空
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ data class PasteCollection(

fun bind(
pasteCoordinate: PasteCoordinate,
isLargeFile: Boolean = false,
syncToDownload: Boolean = false,
): PasteCollection =
PasteCollection(
pasteItems.map {
it.bind(pasteCoordinate, isLargeFile)
it.bind(pasteCoordinate, syncToDownload)
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ data class FilesPasteItem(
// use to adapt relative paths when relative is no storage in crossPaste
override fun bind(
pasteCoordinate: PasteCoordinate,
isLargeFile: Boolean,
syncToDownload: Boolean,
): PasteItem {
val (newBasePath, newRelativePathList) = bindFilePaths(pasteCoordinate, isLargeFile)
val (newBasePath, newRelativePathList) = bindFilePaths(pasteCoordinate, syncToDownload)
return FilesPasteItem(
identifiers = identifiers,
count = count,
Expand Down
Loading