Files
forkmessager/client-mobile/stories/presentation/CreateStoryViewModel.kt
Халимов Рустам 1fb1be47dd Приложение
2026-04-14 01:15:54 +03:00

166 lines
5.1 KiB
Kotlin

package stories.presentation
import android.net.Uri
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import core.network.ServerConfig
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import stories.data.remote.api.CreateStoryRequest
import stories.data.remote.api.StoryApi
import java.io.File
import javax.inject.Inject
data class TextObject(
val id: Long = System.currentTimeMillis(),
val text: String,
val offset: Offset = Offset(100f, 100f),
val color: Color = Color.White,
val fontSize: Float = 24f,
val scale: Float = 1f
)
data class StickerObject(
val id: Long = System.currentTimeMillis(),
val emoji: String,
val offset: Offset = Offset(200f, 200f),
val scale: Float = 1.5f
)
sealed class StoryTool {
object None : StoryTool()
object Text : StoryTool()
object Crop : StoryTool()
object Stickers : StoryTool()
object Brush : StoryTool()
object Filters : StoryTool()
object Trim : StoryTool()
}
@HiltViewModel
class CreateStoryViewModel @Inject constructor(
private val storyApi: StoryApi,
private val serverConfig: ServerConfig
) : ViewModel() {
var selectedMediaUri by mutableStateOf<Uri?>(null)
private set
var isVideo by mutableStateOf(false)
private set
var currentTool by mutableStateOf<StoryTool>(StoryTool.None)
private set
var bgColor by mutableStateOf(Color(0xFF1E1E2E))
private set
val textObjects = mutableStateListOf<TextObject>()
val stickerObjects = mutableStateListOf<StickerObject>()
var isUploading by mutableStateOf(false)
private set
private val _uploadSuccess = MutableStateFlow(false)
val uploadSuccess = _uploadSuccess.asStateFlow()
private val _errorMessage = MutableStateFlow<String?>(null)
val errorMessage = _errorMessage.asStateFlow()
fun onMediaSelected(uri: Uri, isVideo: Boolean) {
this.selectedMediaUri = uri
this.isVideo = isVideo
if (isVideo) {
currentTool = StoryTool.Trim
} else {
currentTool = StoryTool.Crop
}
}
fun setTool(tool: StoryTool) {
currentTool = tool
}
fun addText(text: String) {
textObjects.add(TextObject(text = text))
currentTool = StoryTool.Text
}
fun addSticker(emoji: String) {
stickerObjects.add(StickerObject(emoji = emoji))
}
fun updateBgColor(color: Color) {
bgColor = color
}
fun removeMedia() {
selectedMediaUri = null
isVideo = false
currentTool = StoryTool.None
textObjects.clear()
stickerObjects.clear()
}
fun publishStory(context: android.content.Context) {
val uri = selectedMediaUri ?: return
val maxFileSize = serverConfig.getServerConfig().limits.maxFileSize
viewModelScope.launch {
isUploading = true
try {
val file = uriToFile(context, uri)
if (file.length() > maxFileSize) {
_errorMessage.value = "File too large for this server"
return@launch
}
val mediaUrl = if (isVideo) {
val part = MultipartBody.Part.createFormData(
"file", file.name, file.asRequestBody("video/*".toMediaTypeOrNull())
)
storyApi.uploadVideo(part).url
} else {
// Simulating image upload via same or different endpoint
"https://example.com/simulated_upload.jpg"
}
val request = CreateStoryRequest(
type = if (isVideo) "video" else "image",
mediaUrl = mediaUrl,
bgColor = String.format("#%06X", (0xFFFFFF and bgColor.value.toInt())),
content = null // Serialize stickers/text if needed
)
storyApi.createStory(request)
_uploadSuccess.value = true
} catch (e: Exception) {
_errorMessage.value = e.message ?: "Upload failed"
} finally {
isUploading = false
}
}
}
private fun uriToFile(context: android.content.Context, uri: Uri): File {
val inputStream = context.contentResolver.openInputStream(uri)
val file = File(context.cacheDir, "temp_story_${System.currentTimeMillis()}")
file.outputStream().use { outputStream ->
inputStream?.copyTo(outputStream)
}
return file
}
}