Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update Screenshot Functionality + Screenshot Automation #272

Merged
merged 21 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading