Enhance PhotoViewer with share and open-in actions, improve reply UI

This commit introduces "Share" and "Open in..." actions to the `PhotoViewScreen`, allowing users to share images via other apps or open them in external viewers.

**Key changes:**

- **PhotoViewer:**
    - Added "Share" and "Open in..." options to the `PhotoViewScreen` dropdown menu.
    - `PhotoViewViewModel`:
        - Implemented `onShareClicked()` and `onOpenInClicked()` to handle these new actions.
        - Added `shareRequest` StateFlow to manage image sharing intents.
        - Introduced `downloadAndStoreImageToCache()` to download and cache images for sharing.
        - `onImageShared()` resets `shareRequest` after sharing.
    - Updated `TopBar` to include the new menu items.
    - Added string resources for "Open in…" and "Share".
- **Reply UI:**
    - `Reply.kt`: Title and summary text now use `TextOverflow.Ellipsis` to prevent long text from breaking the layout.
- **API Model:**
    - `MessagesResponse.kt`: Added `MessagesMarkAsImportantResponse` data class to handle the response for marking messages as important.
- **Data Layer:**
    - `MessagesRepositoryImpl`: Updated `markAsImportant` to correctly map the API response using `MessagesMarkAsImportantResponse`.
- **Minor:**
    - `README.md`: Updated feature checklist for external viewer.
    - `ApplicationModule.kt`: Added experimental Coil API opt-in.
This commit is contained in:
2025-06-26 20:46:53 +03:00
parent a7307e7862
commit 70b552412c
10 changed files with 184 additions and 22 deletions
@@ -320,7 +320,12 @@ class MessagesRepositoryImpl(
messagesIds = messageIds.orEmpty(),
important = important
)
messagesService.markAsImportant(requestModel.map).mapApiDefault()
messagesService.markAsImportant(requestModel.map).mapApiResult(
successMapper = { apiResponse ->
apiResponse.requireResponse().marked.map { it.cmId }
},
errorMapper = { error -> error?.toDomain() }
)
}
override suspend fun delete(
@@ -58,3 +58,15 @@ data class MessagesSendResponse(
@Json(name = "message_id") val messageId: Long,
@Json(name = "cmid") val cmId: Long
)
@JsonClass(generateAdapter = true)
data class MessagesMarkAsImportantResponse(
@Json(name = "marked") val marked: List<Mark>
) {
@JsonClass(generateAdapter = true)
data class Mark(
@Json(name = "cmid") val cmId: Long,
@Json(name = "message_id") val messageId: Long,
@Json(name = "peer_id") val peerId: Long
)
}
@@ -9,6 +9,7 @@ import dev.meloda.fast.model.api.responses.MessagesGetByIdResponse
import dev.meloda.fast.model.api.responses.MessagesGetConversationMembersResponse
import dev.meloda.fast.model.api.responses.MessagesGetHistoryAttachmentsResponse
import dev.meloda.fast.model.api.responses.MessagesGetHistoryResponse
import dev.meloda.fast.model.api.responses.MessagesMarkAsImportantResponse
import dev.meloda.fast.model.api.responses.MessagesSendResponse
import dev.meloda.fast.network.ApiResponse
import dev.meloda.fast.network.RestApiError
@@ -76,7 +77,7 @@ interface MessagesService {
@POST(MessagesUrls.MARK_AS_IMPORTANT)
suspend fun markAsImportant(
@FieldMap params: Map<String, String>
): ApiResult<ApiResponse<List<Long>>, RestApiError>
): ApiResult<ApiResponse<MessagesMarkAsImportantResponse>, RestApiError>
@FormUrlEncoded
@POST(MessagesUrls.DELETE)
@@ -277,4 +277,6 @@
<string name="action_copy_link">Скопировать ссылку</string>
<string name="action_copy">Скопировать</string>
<string name="action_copy_image">Скопировать изображение</string>
<string name="action_open_in">Открыть в…</string>
<string name="action_share">Поделиться</string>
</resources>
+2
View File
@@ -354,4 +354,6 @@
<string name="action_copy_link">Copy link</string>
<string name="action_copy">Copy</string>
<string name="action_copy_image">Copy image</string>
<string name="action_open_in">Open in…</string>
<string name="action_share">Share</string>
</resources>