Skip to content

Commit

Permalink
feat: Update Screenshot Functionality + Screenshot Automation (#272)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrii Bodnar <[email protected]>
  • Loading branch information
MykhailoNester and andrii-bodnar authored Nov 28, 2024
1 parent 1333c6d commit 93ad752
Show file tree
Hide file tree
Showing 100 changed files with 1,215 additions and 637 deletions.
1 change: 0 additions & 1 deletion .github/workflows/basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ jobs:
- name: Tests
run: |
./gradlew jacocoTestReport
./gradlew connectedCheck
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id 'com.android.application' version '8.0.2' apply false
id 'com.android.application' version '8.7.2' apply false
id 'com.android.library' version '8.0.2' apply false
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
id 'org.jetbrains.kotlin.android' version '1.9.24' apply false
}

ext {
Expand Down
3 changes: 2 additions & 1 deletion crowdin-controls/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ android {
}

dependencies {
implementation 'com.github.crowdin.mobile-sdk-android:sdk:1.10.1'
implementation project(":crowdin")
// implementation 'com.github.crowdin.mobile-sdk-android:sdk:1.10.1'

implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.core:core-ktx:1.10.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ import android.content.IntentFilter
import android.graphics.PixelFormat
import android.os.Build
import android.os.IBinder
import android.text.InputFilter
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
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.TextView
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
Expand All @@ -38,6 +44,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
Expand All @@ -58,7 +65,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
)

Expand Down Expand Up @@ -89,6 +96,30 @@ 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.filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
if (source != null && !source.matches(Regex("^[^\\\\/:*?\"<>|]*$"))) {
showToast("Invalid character removed. Please avoid: \\\\ / : * ? \\\" < > |")
"" // Reject the invalid input
} else {
null
}
})
screenshotEt.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
hideKeyboard(screenshotEt)
true
} else {
false
}
}

floatingView.findViewById<Button>(R.id.screenshotBtn)
.setOnClickListener { captureScreenshot() }

Expand Down Expand Up @@ -116,6 +147,7 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
initialTouchY = event.rawY
return true
}

MotionEvent.ACTION_UP -> {
val xDiff = (event.rawX - initialTouchX).toInt()
val yDiff = (event.rawY - initialTouchY).toInt()
Expand All @@ -129,6 +161,7 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
}
return true
}

MotionEvent.ACTION_MOVE -> {
// Calculate the X and Y coordinates of the view.
params.x = initialX + (event.rawX - initialTouchX).toInt()
Expand Down Expand Up @@ -178,11 +211,20 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
}

private fun captureScreenshot() {
val screenshotName = screenshotEt.text.trim().toString()
if (screenshotName.isEmpty()) {
showToast("Screenshot name is empty")
return
}

if (Crowdin.isAuthorized()) {
showToast("Screenshot uploading in progress")
sendBroadcast(Intent().apply {
action = BROADCAST_SCREENSHOT
})
sendBroadcast(
Intent().apply {
setPackage(packageName)
action = BROADCAST_SCREENSHOT
putExtra(SCREENSHOT_NAME_KEY, screenshotName)
})
} else {
showToast(AUTH_REQUIRED)
}
Expand Down Expand Up @@ -224,7 +266,9 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
realTimeBtn.isEnabled = Crowdin.isRealTimeUpdatesEnabled()
realTimeBtn.isChecked = Crowdin.isRealTimeUpdatesConnected()

captureScreenshotBtn.isEnabled = Crowdin.isCaptureScreenshotEnabled()
val isEnabled = Crowdin.isCaptureScreenshotEnabled()
captureScreenshotBtn.isEnabled = isEnabled
screenshotEt.isVisible = isEnabled
}

private fun collapseView() {
Expand All @@ -245,6 +289,11 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
windowManager.removeView(floatingView)
}

private fun hideKeyboard(view: View) {
val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}

companion object {

private const val AUTH_REQUIRED =
Expand All @@ -253,6 +302,7 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
"Translations successfully reloaded from the distribution"
private const val TRANSLATION_RELOADED = "The latest translations successfully reloaded"
private const val RELOAD_FAILED = "Data reload failed"
private const val SCREENSHOT_NAME_KEY = "screenshot_name_key"

private const val BROADCAST_SCREENSHOT = "com.crowdin.crowdin_controls.broadcast.SCREENSHOT"
private lateinit var receiver: BroadcastReceiver
Expand All @@ -263,16 +313,21 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == BROADCAST_SCREENSHOT) {
activity.get()?.let {
Crowdin.sendScreenshot(it, object : ScreenshotCallback {
override fun onSuccess() {
it.showToast("Screenshot uploaded")
}

override fun onFailure(throwable: Throwable) {
it.showToast("Screenshot upload failed")
}
})
activity.get()?.let { it ->
val name = intent.getStringExtra(SCREENSHOT_NAME_KEY).takeIf { it?.isNotEmpty() == true }
Crowdin.sendScreenshot(
activity = it,
screenshotName = name,
screenshotCallback = object : ScreenshotCallback {
override fun onSuccess() {
it.showToast("Screenshot uploaded")
}

override fun onFailure(throwable: Throwable) {
Log.d(CROWDIN_TAG, throwable.message ?: "Screenshot upload failed")
it.showToast("Screenshot upload failed")
}
})
}
}
}
Expand Down Expand Up @@ -301,5 +356,11 @@ class CrowdinWidgetService : Service(), LoadingStateListener {
}

fun Context.showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
val toast = Toast(this)
val toastView = LayoutInflater.from(this).inflate(R.layout.custom_toast_layout, null)
toast.view = toastView
toastView.findViewById<TextView>(R.id.toast_message).text = message
toast.setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 100)
toast.duration = Toast.LENGTH_SHORT
toast.show()
}
13 changes: 13 additions & 0 deletions crowdin-controls/src/main/res/drawable/custom_toast_bg.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="@android:color/darker_gray" />
<padding
android:bottom="8dp"
android:left="8dp"
android:right="8dp"
android:top="8dp" />
</shape>
24 changes: 24 additions & 0 deletions crowdin-controls/src/main/res/drawable/ic_crowdin_logo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="248dp"
android:height="248dp"
android:viewportWidth="248"
android:viewportHeight="248">
<path
android:fillColor="#263238"
android:pathData="M163.02,177.31C157.02,177.31 151.67,175.51 147.24,171.99C141.95,167.85 137.74,161.67 137.6,154.4C137.52,150.73 141.52,150.73 141.52,150.73C141.52,150.73 148.02,150.65 151.17,150.65C154.31,150.73 155.24,155.11 155.38,156.2C156.6,166.05 162.17,170.35 166.45,172.31C169.02,173.48 168.38,177.16 163.02,177.31Z" />
<path
android:fillColor="#263238"
android:pathData="M109.1,127.25C103.82,126.63 95.96,126.08 90.89,124.84C82.68,122.82 82.9,115.44 83.25,113.03C84.25,105.8 86.89,99.12 90.96,92.91C96.03,85.29 103.32,78.61 112.67,73.17C130.24,62.99 154.8,57.32 181.79,57.32C201.57,57.32 222.2,59.89 222.42,59.89C224.27,60.12 225.63,61.91 225.56,63.93C225.49,65.95 224.06,67.5 222.2,67.66C219.2,67.58 216.28,67.58 213.49,67.58C186,67.58 166.44,71.31 151.87,79.39C137.52,87.31 127.52,99.43 120.74,117.38C120.03,118.93 117.67,128.18 109.1,127.25Z" />
<path
android:fillColor="#263238"
android:pathData="M133.09,201.33C119.45,201.33 106.59,195.44 96.86,184.68C88.62,175.57 83.65,166.39 82.73,154.61C82.16,146.92 85.57,144.25 90.19,144.72C93.38,145.03 103.33,145.5 109.01,146.68C113.27,147.54 116.11,149.9 116.82,154.77C120.59,180.68 136.92,190.88 146.65,193.08C148.36,193.48 149.43,194.57 149.35,196.54C149.28,198.42 148.01,199.99 146.3,200.3C141.97,201.01 137.42,201.33 133.09,201.33Z" />
<path
android:fillColor="#263238"
android:pathData="M94.22,224.32C84.55,224.32 75.08,222.78 72.38,222.3C60.99,220.27 51.46,216.79 43.28,211.6C23.71,199.2 11.9,177.33 10.47,151.4C10.12,145.24 9.34,133.49 23.99,134.38C30.04,134.71 39.65,137.62 46.41,139.57C54.8,141.92 58.86,148.4 58.86,154.8C58.86,191.34 91.95,215.49 106.39,215.49C112.58,215.49 110.31,222.13 107.6,222.86C102.83,224.16 96.71,224.32 94.22,224.32Z" />
<path
android:fillColor="#263238"
android:pathData="M43.75,116.95C38.03,115.92 32.44,113.55 27.01,112.21C10.19,108.03 13.05,91.07 14.63,86.41C29.94,41.36 78.52,26.29 117.73,22.26C154.65,18.47 193.29,21.39 229.28,31.41C232.22,32.2 241.3,34.41 236.08,39.86C232.79,43.25 219.98,39.7 216.55,39.46C195.44,37.88 174.54,37.65 153.51,40.88C131.26,44.28 108.36,51.3 89.97,66.13C81.1,73.31 73.3,82.47 68.08,93.28C66.72,96.12 65.64,98.96 64.71,101.8C63.78,104.8 60.28,119.87 43.75,116.95Z" />
<path
android:fillColor="#263238"
android:pathData="M137.89,125.64C141.04,111.54 155.04,89.19 198.38,90.74C208.32,91.04 203.77,97.82 198.87,97.67C174.37,96.82 162.74,112.62 156.65,128.64C154.69,133.8 150.21,134.58 144.61,133.65C140.69,132.96 136.42,132.5 137.89,125.64Z" />
</vector>
36 changes: 0 additions & 36 deletions crowdin-controls/src/main/res/drawable/ic_crowdin_logo_icon.xml

This file was deleted.

28 changes: 28 additions & 0 deletions crowdin-controls/src/main/res/layout/custom_toast_layout.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/custom_toast_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="8dp">

<ImageView
android:id="@+id/toast_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_crowdin_logo" />

<TextView
android:id="@+id/toast_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textColor="@android:color/black"
android:textSize="16sp"
tools:text="Custom Toast Message" />

</LinearLayout>
Loading

0 comments on commit 93ad752

Please sign in to comment.