mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-07 21:37:02 +09:00
DROID-3047 Chats | Enhancement | Clear chat temp folder after sending message (#2513)
This commit is contained in:
parent
e384832a9a
commit
50bc12b04f
4 changed files with 107 additions and 9 deletions
|
@ -48,6 +48,7 @@ import com.anytypeio.anytype.domain.objects.CreateObjectFromUrl
|
|||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.getTypeOfObject
|
||||
import com.anytypeio.anytype.feature_chats.BuildConfig
|
||||
import com.anytypeio.anytype.feature_chats.tools.ClearChatsTempFolder
|
||||
import com.anytypeio.anytype.feature_chats.tools.DummyMessageGenerator
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.confgs.ChatConfig
|
||||
|
@ -101,7 +102,8 @@ class ChatViewModel @Inject constructor(
|
|||
private val generateSpaceInviteLink: GenerateSpaceInviteLink,
|
||||
private val makeSpaceShareable: MakeSpaceShareable,
|
||||
private val getSpaceInviteLink: GetSpaceInviteLink,
|
||||
private val revokeSpaceInviteLink: RevokeSpaceInviteLink
|
||||
private val revokeSpaceInviteLink: RevokeSpaceInviteLink,
|
||||
private val clearChatsTempFolder: ClearChatsTempFolder
|
||||
) : BaseViewModel(), ExitToVaultDelegate by exitToVaultDelegate {
|
||||
|
||||
private val visibleRangeUpdates = MutableSharedFlow<Pair<Id, Id>>(
|
||||
|
@ -547,6 +549,8 @@ class ChatViewModel @Inject constructor(
|
|||
|
||||
val normalizedMarkup = (markup + parsedUrls).sortedBy { it.range.first }
|
||||
|
||||
var shouldClearChatTempFolder = false
|
||||
|
||||
chatBoxMode.value = chatBoxMode.value.updateIsSendingBlocked(isBlocked = true)
|
||||
val attachments = buildList {
|
||||
val currAttachments = chatBoxAttachments.value
|
||||
|
@ -594,6 +598,7 @@ class ChatViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
val path = if (attachment.capturedByCamera) {
|
||||
shouldClearChatTempFolder = true
|
||||
withContext(dispatchers.io) {
|
||||
copyFileToCacheDirectory.copy(attachment.uri)
|
||||
}.orEmpty()
|
||||
|
@ -610,6 +615,14 @@ class ChatViewModel @Inject constructor(
|
|||
Block.Content.File.Type.IMAGE
|
||||
)
|
||||
).onSuccess { file ->
|
||||
withContext(dispatchers.io) {
|
||||
val isDeleted = copyFileToCacheDirectory.delete(path)
|
||||
if (isDeleted) {
|
||||
Timber.d("DROID-2966 Successfully deleted temp file: ${attachment.uri}")
|
||||
} else {
|
||||
Timber.w("DROID-2966 Error while deleting temp file: ${attachment.uri}")
|
||||
}
|
||||
}
|
||||
add(
|
||||
Chat.Message.Attachment(
|
||||
target = file.id,
|
||||
|
@ -688,7 +701,7 @@ class ChatViewModel @Inject constructor(
|
|||
type = Block.Content.File.Type.NONE
|
||||
)
|
||||
).onSuccess { file ->
|
||||
// TODO delete file.
|
||||
copyFileToCacheDirectory.delete(path)
|
||||
add(
|
||||
Chat.Message.Attachment(
|
||||
target = file.id,
|
||||
|
@ -792,6 +805,12 @@ class ChatViewModel @Inject constructor(
|
|||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldClearChatTempFolder) {
|
||||
withContext(dispatchers.io) {
|
||||
clearChatsTempFolder()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
|||
import com.anytypeio.anytype.domain.notifications.NotificationBuilder
|
||||
import com.anytypeio.anytype.domain.objects.CreateObjectFromUrl
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.feature_chats.tools.ClearChatsTempFolder
|
||||
import com.anytypeio.anytype.presentation.notifications.NotificationPermissionManager
|
||||
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
|
||||
import com.anytypeio.anytype.presentation.vault.ExitToVaultDelegate
|
||||
|
@ -51,7 +52,8 @@ class ChatViewModelFactory @Inject constructor(
|
|||
private val generateSpaceInviteLink: GenerateSpaceInviteLink,
|
||||
private val makeSpaceShareable: MakeSpaceShareable,
|
||||
private val getSpaceInviteLink: GetSpaceInviteLink,
|
||||
private val revokeSpaceInviteLink: RevokeSpaceInviteLink
|
||||
private val revokeSpaceInviteLink: RevokeSpaceInviteLink,
|
||||
private val clearChatsTempFolder: ClearChatsTempFolder
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = ChatViewModel(
|
||||
|
@ -78,6 +80,7 @@ class ChatViewModelFactory @Inject constructor(
|
|||
generateSpaceInviteLink = generateSpaceInviteLink,
|
||||
makeSpaceShareable = makeSpaceShareable,
|
||||
getSpaceInviteLink = getSpaceInviteLink,
|
||||
revokeSpaceInviteLink = revokeSpaceInviteLink
|
||||
revokeSpaceInviteLink = revokeSpaceInviteLink,
|
||||
clearChatsTempFolder = clearChatsTempFolder
|
||||
) as T
|
||||
}
|
|
@ -5,6 +5,8 @@ import android.net.Uri
|
|||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.core.content.FileProvider
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
fun launchCamera(
|
||||
|
@ -12,7 +14,13 @@ fun launchCamera(
|
|||
launcher: ManagedActivityResultLauncher<Uri, Boolean>,
|
||||
onUriReceived: (Uri) -> Unit
|
||||
) {
|
||||
val photoFile = File.createTempFile("IMG_", ".jpg", context.cacheDir).apply {
|
||||
val tempDir = File(context.cacheDir, CHATS_TEMP_FOLDER_NAME)
|
||||
if (!tempDir.exists()) {
|
||||
val created = tempDir.mkdirs()
|
||||
Timber.d("Created camera temp dir: $created at ${tempDir.absolutePath}")
|
||||
}
|
||||
|
||||
val photoFile = File.createTempFile("IMG_", ".jpg", tempDir).apply {
|
||||
createNewFile()
|
||||
deleteOnExit()
|
||||
}
|
||||
|
@ -23,7 +31,29 @@ fun launchCamera(
|
|||
photoFile
|
||||
)
|
||||
|
||||
onUriReceived(uri)
|
||||
Timber.d("Launching camera with URI: $uri (path: ${photoFile.absolutePath})")
|
||||
|
||||
onUriReceived(uri)
|
||||
launcher.launch(uri)
|
||||
}
|
||||
|
||||
const val CHATS_TEMP_FOLDER_NAME = "chats_temp_folder"
|
||||
|
||||
class ClearChatsTempFolder @Inject constructor(
|
||||
private val context: Context
|
||||
) {
|
||||
companion object {
|
||||
private const val CHATS_TEMP_FOLDER_NAME = "chats_temp_folder"
|
||||
}
|
||||
|
||||
operator fun invoke(): Boolean {
|
||||
val folder = File(context.cacheDir, CHATS_TEMP_FOLDER_NAME)
|
||||
return if (folder.exists()) {
|
||||
val deleted = folder.deleteRecursively()
|
||||
// Optional: log if needed
|
||||
deleted
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import com.anytypeio.anytype.core_utils.ext.msg
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
@ -11,9 +14,6 @@ import kotlinx.coroutines.isActive
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* Interface defining the contract for copying files to a cache directory.
|
||||
|
@ -42,6 +42,8 @@ interface CopyFileToCacheDirectory {
|
|||
* @return `true` if the operation is active, `false` otherwise.
|
||||
*/
|
||||
fun isActive(): Boolean
|
||||
|
||||
fun delete(uri: String): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,6 +214,37 @@ class DefaultCopyFileToCacheDirectory(context: Context) : CopyFileToCacheDirecto
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun delete(uri: String): Boolean {
|
||||
val context = mContext?.get() ?: return false
|
||||
return try {
|
||||
val path = Uri.parse(uri).path ?: return false
|
||||
val file = File(path)
|
||||
|
||||
// Optional: check if file is in cache or external files dir
|
||||
val allowedRoots = listOfNotNull(
|
||||
context.cacheDir?.absolutePath,
|
||||
context.getExternalFilesDir(null)?.absolutePath
|
||||
)
|
||||
|
||||
if (allowedRoots.any { file.absolutePath.startsWith(it) }) {
|
||||
if (!file.exists()) {
|
||||
Timber.w("File does not exist: $path")
|
||||
return false
|
||||
}
|
||||
|
||||
val deleted = file.delete()
|
||||
Timber.d("Attempting to delete file: $path → deleted=$deleted")
|
||||
deleted
|
||||
} else {
|
||||
Timber.w("Blocked delete attempt outside allowed folders: $path")
|
||||
false
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error deleting file at $uri")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -330,6 +363,19 @@ class NetworkModeCopyFileToCacheDirectory(context: Context) : CopyFileToCacheDir
|
|||
return result
|
||||
}
|
||||
|
||||
override fun delete(uri: String): Boolean {
|
||||
val context = mContext?.get() ?: return false
|
||||
return try {
|
||||
val file = File(Uri.parse(uri).path ?: return false)
|
||||
val deleted = file.delete()
|
||||
Timber.d("Attempting to delete file by uri: $uri → $deleted")
|
||||
deleted
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error deleting file by uri: $uri")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CONFIG_FILE_NAME = "configCustom.txt"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue