From 93c55324880303a9b999d32f1f865cfbd3f534e3 Mon Sep 17 00:00:00 2001 From: Mykhailo Nester Date: Wed, 13 Nov 2024 20:53:41 +0200 Subject: [PATCH 01/21] - fix issues with ids when upload screenshots; - update target to 35 and compile to 34; - add automation test that will send screenshot; --- build.gradle | 4 +- .../platform/data/remote/api/CrowdinApi.kt | 2 +- .../data/remote/api/CrowdinNetworkModels.kt | 4 +- .../platform/screenshot/ScreenshotManager.kt | 4 +- example/build.gradle | 3 ++ .../example/ScreenshotAutomationTest.kt | 52 +++++++++++++++++++ 6 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 example/src/androidTest/java/com/crowdin/platform/example/ScreenshotAutomationTest.kt diff --git a/build.gradle b/build.gradle index 498d5090..4e291d84 100755 --- a/build.gradle +++ b/build.gradle @@ -5,9 +5,9 @@ plugins { } ext { - compileSdkVersion = 33 + compileSdkVersion = 34 minSdkVersion = 16 - targetSdkVersion = 33 + targetSdkVersion = 35 } task clean(type: Delete) { diff --git a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt index a0d8370e..542a9868 100644 --- a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt +++ b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt @@ -32,7 +32,7 @@ internal interface CrowdinApi { @POST("api/v2/projects/{projectId}/screenshots/{screenshotId}/tags") fun createTag( @Path("projectId") projectId: String, - @Path("screenshotId") screenshotId: Int, + @Path("screenshotId") screenshotId: Long, @Body tags: MutableList, ): Call diff --git a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinNetworkModels.kt b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinNetworkModels.kt index f2598372..08709933 100644 --- a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinNetworkModels.kt +++ b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinNetworkModels.kt @@ -3,7 +3,7 @@ package com.crowdin.platform.data.remote.api import com.google.gson.annotations.SerializedName internal data class CreateScreenshotRequestBody( - var storageId: Int, + var storageId: Long, var name: String, ) @@ -28,7 +28,7 @@ internal data class UploadScreenshotResponse( ) internal data class Data( - var id: Int? = null, + var id: Long? = null, val fileName: String, ) diff --git a/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt b/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt index 5ef97598..54d2c6af 100644 --- a/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt +++ b/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt @@ -128,7 +128,7 @@ internal class ScreenshotManager( } private fun createScreenshot( - screenshotId: Int, + screenshotId: Long, tags: MutableList, projectId: String, fileName: String, @@ -161,7 +161,7 @@ internal class ScreenshotManager( } private fun createTag( - screenshotId: Int, + screenshotId: Long, tags: MutableList, projectId: String, ) { diff --git a/example/build.gradle b/example/build.gradle index 5bc99147..4bf281f5 100755 --- a/example/build.gradle +++ b/example/build.gradle @@ -55,4 +55,7 @@ dependencies { implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' + + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0' } \ No newline at end of file diff --git a/example/src/androidTest/java/com/crowdin/platform/example/ScreenshotAutomationTest.kt b/example/src/androidTest/java/com/crowdin/platform/example/ScreenshotAutomationTest.kt new file mode 100644 index 00000000..04f3b76f --- /dev/null +++ b/example/src/androidTest/java/com/crowdin/platform/example/ScreenshotAutomationTest.kt @@ -0,0 +1,52 @@ +package com.crowdin.platform.example + +import android.app.Activity +import android.graphics.Bitmap +import androidx.test.core.app.ActivityScenario +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner +import com.crowdin.crowdin_controls.showToast +import com.crowdin.platform.Crowdin +import com.crowdin.platform.screenshot.ScreenshotCallback +import org.junit.Test +import org.junit.runner.RunWith +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +@RunWith(AndroidJUnit4ClassRunner::class) +class ScreenshotAutomationTest { + + @Test + fun automateScreenshotCaptureAndUpload() { + val activityScenario = ActivityScenario.launch(MainActivity::class.java) + val latch = CountDownLatch(1) + + activityScenario.onActivity { activity -> + captureAndSendScreenshot(activity, latch) + } + + // Wait for the latch to be decremented, or timeout after 5 seconds + latch.await(5, TimeUnit.SECONDS) + activityScenario.close() + } + + private fun captureAndSendScreenshot(activity: Activity, latch: CountDownLatch) { + // Capture the screenshot as a Bitmap + val rootView = activity.window.decorView.rootView + rootView.isDrawingCacheEnabled = true + val bitmap = Bitmap.createBitmap(rootView.drawingCache) + rootView.isDrawingCacheEnabled = false + + // Upload the screenshot to Crowdin using Crowdin SDK + Crowdin.sendScreenshot(bitmap, object : ScreenshotCallback { + override fun onSuccess() { + activity.showToast("Screenshot uploaded") + latch.countDown() + } + + override fun onFailure(throwable: Throwable) { + activity.showToast("Screenshot upload failed") + latch.countDown() + } + }) + } +} \ No newline at end of file From 5b20d5358071b789e02251b3e16484a2d4800e47 Mon Sep 17 00:00:00 2001 From: Mykhailo Nester Date: Wed, 13 Nov 2024 23:59:23 +0200 Subject: [PATCH 02/21] - new API for get screenshots list; - new API for update screenshot; - new models for screenshot response; - revert to target 33 - breaks broadcast functionality; --- build.gradle | 4 +- .../data/model/ListScreenshotsResponse.kt | 76 +++++++ .../platform/data/remote/api/CrowdinApi.kt | 17 +- .../platform/screenshot/ScreenshotManager.kt | 190 +++++++++++++++--- .../crowdin/platform/ScreenshotManagerTest.kt | 4 +- 5 files changed, 261 insertions(+), 30 deletions(-) create mode 100644 crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt diff --git a/build.gradle b/build.gradle index 4e291d84..498d5090 100755 --- a/build.gradle +++ b/build.gradle @@ -5,9 +5,9 @@ plugins { } ext { - compileSdkVersion = 34 + compileSdkVersion = 33 minSdkVersion = 16 - targetSdkVersion = 35 + targetSdkVersion = 33 } task clean(type: Delete) { diff --git a/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt b/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt new file mode 100644 index 00000000..a34bcd10 --- /dev/null +++ b/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt @@ -0,0 +1,76 @@ +package com.crowdin.platform.data.model + +data class ListScreenshotsResponse( + val data: List, + val pagination: Pagination, +) + +data class ScreenshotData( + val data: Screenshot, +) + +// TODO: cleanup +data class Screenshot( + val id: Long, + val userId: Long, +// val url: String, +// val webUrl: String, + val name: String, +// val size: Any, +// val tagsCount: Int, +// val tags: List, +// val labels: List, +// val labelIds: List, +// val createdAt: String?, +// val updatedAt: String? +) + +data class Pagination( + val offset: Int, + val limit: Int, +) + +// { +// "data": [ +// { +// "data": { +// "id": 2, +// "userId": 6, +// "url": "https://production-enterprise-screenshots.downloads.crowdin.com/992000002/6/2/middle.jpg?X-Amz-Content-Sha256={sha}&X-Amz-Algorithm={algorithm}&X-Amz-Credential={credentials}&X-Amz-Date={date}&X-Amz-SignedHeaders={headers}&X-Amz-Expires={expires}&X-Amz-Signature={signature}", +// "webUrl": "https://production-enterprise-screenshots.downloads.crowdin.com/992000002/6/2/middle.jpg?X-Amz-Content-Sha256={sha}&X-Amz-Algorithm={algorithm}&X-Amz-Credential={credentials}&X-Amz-Date={date}&X-Amz-SignedHeaders={headers}&X-Amz-Expires={expires}&X-Amz-Signature={signature}", +// "name": "translate_with_siri.jpg", +// "size": { +// "width": 267, +// "height": 176 +// }, +// "tagsCount": 1, +// "tags": [ +// { +// "id": 98, +// "screenshotId": 2, +// "stringId": 2822, +// "position": { +// "x": 474, +// "y": 147, +// "width": 490, +// "height": 99 +// }, +// "createdAt": "2019-09-23T09:35:31+00:00" +// } +// ], +// "labels": [ +// 1 +// ], +// "labelIds": [ +// 1 +// ], +// "createdAt": "2019-09-23T09:29:19+00:00", +// "updatedAt": "2019-09-23T09:29:19+00:00" +// } +// } +// ], +// "pagination": { +// "offset": 0, +// "limit": 25 +// } +// } diff --git a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt index 542a9868..57a2679a 100644 --- a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt +++ b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt @@ -3,6 +3,7 @@ package com.crowdin.platform.data.remote.api import com.crowdin.platform.data.model.BuildTranslationRequest import com.crowdin.platform.data.model.FileResponse import com.crowdin.platform.data.model.LanguagesInfo +import com.crowdin.platform.data.model.ListScreenshotsResponse import com.crowdin.platform.data.model.TranslationResponse import okhttp3.RequestBody import okhttp3.ResponseBody @@ -11,14 +12,21 @@ import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.POST +import retrofit2.http.PUT import retrofit2.http.Path import retrofit2.http.Query private const val LANGUAGE_COUNT = 500 internal interface CrowdinApi { + @GET("/api/v2/projects/{projectId}/screenshots") + fun getScreenshotsList( + @Path("projectId") projectId: String, + @Query("search") search: String, + ): Call + @POST("api/v2/storages") - fun uploadScreenshot( + fun addToStorage( @Header("Crowdin-API-FileName") fileName: String, @Body requestBody: RequestBody, ): Call @@ -29,6 +37,13 @@ internal interface CrowdinApi { @Body requestBody: CreateScreenshotRequestBody, ): Call + @PUT("api/v2/projects/{projectId}/screenshots/{screenshotId}") + fun updateScreenshot( + @Path("projectId") projectId: String, + @Path("screenshotId") screenshotId: String, + @Body requestBody: CreateScreenshotRequestBody, + ): Call + @POST("api/v2/projects/{projectId}/screenshots/{screenshotId}/tags") fun createTag( @Path("projectId") projectId: String, diff --git a/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt b/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt index 54d2c6af..0d6c19df 100644 --- a/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt +++ b/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt @@ -4,18 +4,22 @@ import android.content.Context import android.database.ContentObserver import android.graphics.Bitmap import android.provider.MediaStore +import android.util.Log import android.widget.Toast +import com.crowdin.platform.Crowdin.CROWDIN_TAG import com.crowdin.platform.data.DataManager import com.crowdin.platform.data.getMappingValueForKey import com.crowdin.platform.data.model.LanguageData +import com.crowdin.platform.data.model.ListScreenshotsResponse +import com.crowdin.platform.data.model.Screenshot import com.crowdin.platform.data.model.ViewData import com.crowdin.platform.data.remote.api.CreateScreenshotRequestBody import com.crowdin.platform.data.remote.api.CreateScreenshotResponse import com.crowdin.platform.data.remote.api.CrowdinApi +import com.crowdin.platform.data.remote.api.Data import com.crowdin.platform.data.remote.api.DistributionInfoResponse import com.crowdin.platform.data.remote.api.TagData import com.crowdin.platform.data.remote.api.UploadScreenshotResponse -import com.crowdin.platform.util.parseToDateTimeFormat import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.ResponseBody @@ -23,7 +27,6 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response import java.io.ByteArrayOutputStream -import java.net.HttpURLConnection internal class ScreenshotManager( private var crowdinApi: CrowdinApi, @@ -58,7 +61,120 @@ internal class ScreenshotManager( val projectId = distributionData.project.id val tags = getMappingIds(mappingData, viewDataList) - uploadScreenshot(bitmap, tags, projectId, activityName) + + // TODO: replace with names + val name = "test1Screenshot$IMAGE_EXTENSION" + // 1. Get List Screenshots by search query + getScreenshotsList( + projectId = projectId, + name = name, + onResult = { screenshot -> + Log.d(CROWDIN_TAG, "Screenshot search result: $screenshot") + // 2. Add to storage + addToStorage( + bitmap = bitmap, + tags = tags, + projectId = projectId, + name = name, + screenshot = screenshot, + onFailure = { screenshotCallback?.onFailure(it) }, + ) + }, + ) + } + + private fun getScreenshotsList( + projectId: String, + name: String, + onResult: (Screenshot?) -> Unit, + ) { + crowdinApi + .getScreenshotsList(projectId, name) + .enqueue( + object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + val responseBody = response.body() + val list = responseBody?.data + + if (list != null && list.size > 1) { + Log.v( + CROWDIN_TAG, + "Encountered multiple screenshots with the same name; only one will be updated.", + ) + } + onResult(list?.lastOrNull()?.data) + } + + override fun onFailure( + call: Call, + throwable: Throwable, + ) { + Log.d(CROWDIN_TAG, "List screenshots onFailure: $throwable") + onResult(null) + } + }, + ) + } + + private fun addToStorage( + bitmap: Bitmap, + tags: MutableList, + projectId: String, + name: String, + screenshot: Screenshot?, + onFailure: (Throwable) -> Unit, + ) { + addScreenshotToStorage( + bitmap = bitmap, + activityName = name, + onResult = { + it?.let { + // 3. Update or create screenshot + onScreenshotAddedToStorage(projectId, it, tags, screenshot, onFailure) + } ?: onFailure(Throwable("Could not upload screenshot")) + }, + onFailure = { onFailure(it) }, + ) + } + + private fun onScreenshotAddedToStorage( + projectId: String, + data: Data, + tags: MutableList, + screenshot: Screenshot?, + onFailure: (Throwable) -> Unit, + ) { + if (data.id == null || data.fileName.isEmpty()) { + onFailure(Throwable("Could not create screenshot storage")) + return + } + + if (screenshot != null) { + updateScreenshot( + projectId = projectId, + storageId = data.id!!, + screenshotId = screenshot.id.toString(), + fileName = screenshot.name, + onSuccess = { replaceTags() }, // TODO: add replace tags + onFailure = onFailure, + ) + } else { + createScreenshot( + projectId = projectId, + storageId = data.id!!, + fileName = data.fileName, + onSuccess = { createTag(it, tags, projectId) }, + onFailure = onFailure, + ) + } + } + + private fun replaceTags() { + // 4. після апдейту, викликаємо метод Replace Tags і передаємо нові координати текстів на тому скріні +// createTag(screenshotId, tags, projectId) } fun registerScreenShotContentObserver(context: Context) { @@ -85,11 +201,11 @@ internal class ScreenshotManager( this.screenshotCallback = screenshotCallback } - private fun uploadScreenshot( + private fun addScreenshotToStorage( bitmap: Bitmap, - tags: MutableList, - projectId: String, - activityName: String?, + activityName: String, + onResult: (Data?) -> Unit, + onFailure: (Throwable) -> Unit, ) { val stream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.PNG, IMG_QUALITY, stream) @@ -99,10 +215,10 @@ internal class ScreenshotManager( bitmap.recycle() val prefix = activityName?.let { it + "_" } ?: "" - val fileName = - "$prefix${System.currentTimeMillis().parseToDateTimeFormat()}$IMAGE_EXTENSION" + val fileName = activityName // + IMAGE_EXTENSION +// "$prefix${System.currentTimeMillis().parseToDateTimeFormat()}$IMAGE_EXTENSION" crowdinApi - .uploadScreenshot(fileName, requestBody) + .addToStorage(fileName, requestBody) .enqueue( object : Callback { override fun onResponse( @@ -110,30 +226,58 @@ internal class ScreenshotManager( response: Response, ) { val responseBody = response.body() - if (response.code() == HttpURLConnection.HTTP_CREATED) { - responseBody?.data?.let { data -> - data.id?.let { createScreenshot(it, tags, projectId, data.fileName) } - } - } + onResult(responseBody?.data) } override fun onFailure( call: Call, throwable: Throwable, ) { - screenshotCallback?.onFailure(throwable) + onFailure(throwable) + } + }, + ) + } + + private fun updateScreenshot( + projectId: String, + storageId: Long, + screenshotId: String, + fileName: String, + onSuccess: (Long) -> Unit, + onFailure: (Throwable) -> Unit, + ) { + val requestBody = CreateScreenshotRequestBody(storageId, fileName) + crowdinApi + .updateScreenshot(projectId, screenshotId, requestBody) + .enqueue( + object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + val responseBody = response.body() + responseBody?.data?.id?.let { onSuccess(it) } ?: onFailure(Throwable("Could not update screenshot")) + } + + override fun onFailure( + call: Call, + throwable: Throwable, + ) { + onFailure(throwable) } }, ) } private fun createScreenshot( - screenshotId: Long, - tags: MutableList, + storageId: Long, projectId: String, fileName: String, + onSuccess: (Long) -> Unit, + onFailure: (Throwable) -> Unit, ) { - val requestBody = CreateScreenshotRequestBody(screenshotId, fileName) + val requestBody = CreateScreenshotRequestBody(storageId, fileName) crowdinApi .createScreenshot(projectId, requestBody) .enqueue( @@ -143,18 +287,14 @@ internal class ScreenshotManager( response: Response, ) { val responseBody = response.body() - if (response.code() == HttpURLConnection.HTTP_CREATED) { - responseBody?.data?.id?.let { screenshotId -> - createTag(screenshotId, tags, projectId) - } - } + responseBody?.data?.id?.let { onSuccess(it) } ?: onFailure(Throwable("Could not create screenshot")) } override fun onFailure( call: Call, throwable: Throwable, ) { - screenshotCallback?.onFailure(throwable) + onFailure(throwable) } }, ) diff --git a/crowdin/src/test/java/com/crowdin/platform/ScreenshotManagerTest.kt b/crowdin/src/test/java/com/crowdin/platform/ScreenshotManagerTest.kt index b450ef7f..60837fac 100644 --- a/crowdin/src/test/java/com/crowdin/platform/ScreenshotManagerTest.kt +++ b/crowdin/src/test/java/com/crowdin/platform/ScreenshotManagerTest.kt @@ -92,7 +92,7 @@ class ScreenshotManagerTest { // Then val inOrder = inOrder(mockCrowdinApi) - inOrder.verify(mockCrowdinApi).uploadScreenshot(any(), any()) + inOrder.verify(mockCrowdinApi).addToStorage(any(), any()) inOrder.verify(mockCrowdinApi).createScreenshot(any(), any()) inOrder.verify(mockCrowdinApi).createTag("projectIdTest", 10, mutableListOf()) } @@ -198,7 +198,7 @@ class ScreenshotManagerTest { successCode: Int = 201, ) { val mockedCall = mock(Call::class.java) as Call - `when`(mockCrowdinApi.uploadScreenshot(any(), any())).thenReturn(mockedCall) + `when`(mockCrowdinApi.addToStorage(any(), any())).thenReturn(mockedCall) doAnswer { val callback = it.getArgument(0, Callback::class.java) as Callback From 3ace137a593fb56f873b1b9b0cb66e9aae0b6605 Mon Sep 17 00:00:00 2001 From: Mykhailo Nester Date: Thu, 14 Nov 2024 18:44:03 +0200 Subject: [PATCH 03/21] - add replace tags API; --- .../data/model/ListScreenshotsResponse.kt | 55 ------------------- .../platform/data/remote/api/CrowdinApi.kt | 7 +++ .../platform/screenshot/ScreenshotManager.kt | 33 +++++++++-- 3 files changed, 34 insertions(+), 61 deletions(-) diff --git a/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt b/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt index a34bcd10..de53e23e 100644 --- a/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt +++ b/crowdin/src/main/java/com/crowdin/platform/data/model/ListScreenshotsResponse.kt @@ -9,68 +9,13 @@ data class ScreenshotData( val data: Screenshot, ) -// TODO: cleanup data class Screenshot( val id: Long, val userId: Long, -// val url: String, -// val webUrl: String, val name: String, -// val size: Any, -// val tagsCount: Int, -// val tags: List, -// val labels: List, -// val labelIds: List, -// val createdAt: String?, -// val updatedAt: String? ) data class Pagination( val offset: Int, val limit: Int, ) - -// { -// "data": [ -// { -// "data": { -// "id": 2, -// "userId": 6, -// "url": "https://production-enterprise-screenshots.downloads.crowdin.com/992000002/6/2/middle.jpg?X-Amz-Content-Sha256={sha}&X-Amz-Algorithm={algorithm}&X-Amz-Credential={credentials}&X-Amz-Date={date}&X-Amz-SignedHeaders={headers}&X-Amz-Expires={expires}&X-Amz-Signature={signature}", -// "webUrl": "https://production-enterprise-screenshots.downloads.crowdin.com/992000002/6/2/middle.jpg?X-Amz-Content-Sha256={sha}&X-Amz-Algorithm={algorithm}&X-Amz-Credential={credentials}&X-Amz-Date={date}&X-Amz-SignedHeaders={headers}&X-Amz-Expires={expires}&X-Amz-Signature={signature}", -// "name": "translate_with_siri.jpg", -// "size": { -// "width": 267, -// "height": 176 -// }, -// "tagsCount": 1, -// "tags": [ -// { -// "id": 98, -// "screenshotId": 2, -// "stringId": 2822, -// "position": { -// "x": 474, -// "y": 147, -// "width": 490, -// "height": 99 -// }, -// "createdAt": "2019-09-23T09:35:31+00:00" -// } -// ], -// "labels": [ -// 1 -// ], -// "labelIds": [ -// 1 -// ], -// "createdAt": "2019-09-23T09:29:19+00:00", -// "updatedAt": "2019-09-23T09:29:19+00:00" -// } -// } -// ], -// "pagination": { -// "offset": 0, -// "limit": 25 -// } -// } diff --git a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt index 57a2679a..4b689962 100644 --- a/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt +++ b/crowdin/src/main/java/com/crowdin/platform/data/remote/api/CrowdinApi.kt @@ -51,6 +51,13 @@ internal interface CrowdinApi { @Body tags: MutableList, ): Call + @PUT("api/v2/projects/{projectId}/screenshots/{screenshotId}/tags") + fun replaceTag( + @Path("projectId") projectId: String, + @Path("screenshotId") screenshotId: Long, + @Body tags: MutableList, + ): Call + @GET("/api/v2/distributions/metadata") fun getInfo( @Query("hash") distributionHash: String, diff --git a/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt b/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt index 0d6c19df..f0d08b1c 100644 --- a/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt +++ b/crowdin/src/main/java/com/crowdin/platform/screenshot/ScreenshotManager.kt @@ -158,7 +158,7 @@ internal class ScreenshotManager( storageId = data.id!!, screenshotId = screenshot.id.toString(), fileName = screenshot.name, - onSuccess = { replaceTags() }, // TODO: add replace tags + onSuccess = { replaceTags(it, tags, projectId) }, onFailure = onFailure, ) } else { @@ -172,11 +172,6 @@ internal class ScreenshotManager( } } - private fun replaceTags() { - // 4. після апдейту, викликаємо метод Replace Tags і передаємо нові координати текстів на тому скріні -// createTag(screenshotId, tags, projectId) - } - fun registerScreenShotContentObserver(context: Context) { val screenshotService = ScreenshotService(context) screenshotService.setOnErrorListener { @@ -326,6 +321,32 @@ internal class ScreenshotManager( ) } + private fun replaceTags( + screenshotId: Long, + tags: MutableList, + projectId: String, + ) { + crowdinApi + .replaceTag(projectId, screenshotId, tags) + .enqueue( + object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + screenshotCallback?.onSuccess() + } + + override fun onFailure( + call: Call, + throwable: Throwable, + ) { + screenshotCallback?.onFailure(throwable) + } + }, + ) + } + private fun getMappingIds( mappingData: LanguageData, viewDataList: List, From 69e1d0bd2a693299b90c2a17dfe7663939589cac Mon Sep 17 00:00:00 2001 From: Mykhailo Nester Date: Thu, 14 Nov 2024 20:54:14 +0200 Subject: [PATCH 04/21] - add screenshot name to API; - update documentation; - add ability to set name from controls; --- .../crowdin_controls/CrowdinWidgetService.kt | 57 +++++++++++++++---- .../res/layout/layout_floating_widget.xml | 14 +++++ .../main/java/com/crowdin/platform/Crowdin.kt | 51 +++++++++++------ .../platform/screenshot/ScreenshotManager.kt | 30 +++++----- .../platform/screenshot/ScreenshotService.kt | 29 +++++----- 5 files changed, 123 insertions(+), 58 deletions(-) diff --git a/crowdin-controls/src/main/java/com/crowdin/crowdin_controls/CrowdinWidgetService.kt b/crowdin-controls/src/main/java/com/crowdin/crowdin_controls/CrowdinWidgetService.kt index 0a580bb7..e9fbdef6 100644 --- a/crowdin-controls/src/main/java/com/crowdin/crowdin_controls/CrowdinWidgetService.kt +++ b/crowdin-controls/src/main/java/com/crowdin/crowdin_controls/CrowdinWidgetService.kt @@ -17,11 +17,15 @@ import android.view.MotionEvent import android.view.View import android.view.View.OnTouchListener import android.view.WindowManager +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager import android.widget.Button +import android.widget.EditText import android.widget.ImageView import android.widget.Toast import android.widget.ToggleButton import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import com.crowdin.platform.Crowdin import com.crowdin.platform.Crowdin.CROWDIN_TAG import com.crowdin.platform.LoadingStateListener @@ -38,6 +42,7 @@ class CrowdinWidgetService : Service(), LoadingStateListener { private lateinit var authBtn: ToggleButton private lateinit var captureScreenshotBtn: Button private lateinit var realTimeBtn: ToggleButton + private lateinit var screenshotEt: EditText override fun onBind(intent: Intent): IBinder? { return null @@ -58,7 +63,7 @@ class CrowdinWidgetService : Service(), LoadingStateListener { WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, layoutFlag, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // Allow focusable with input PixelFormat.TRANSLUCENT ) @@ -89,6 +94,22 @@ class CrowdinWidgetService : Service(), LoadingStateListener { captureScreenshotBtn = floatingView.findViewById(R.id.screenshotBtn) + screenshotEt = floatingView.findViewById(R.id.screenshotEt) + screenshotEt.setOnFocusChangeListener { view, hasFocus -> + if (hasFocus) { + val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) + } + } + screenshotEt.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + hideKeyboard(screenshotEt) + true + } else { + false + } + } + floatingView.findViewById