Compare commits
2
Commits
v0.3.0
...
android-ui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
570624fb8b | ||
|
|
5517792387 |
No files matched your search
@@ -1,8 +1,6 @@
|
|||||||
name: Android
|
name: Android
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -22,16 +20,11 @@ jobs:
|
|||||||
- uses: android-actions/setup-android@v3
|
- uses: android-actions/setup-android@v3
|
||||||
# Gitea's act resolver cannot peel the annotated v4 tag alias.
|
# Gitea's act resolver cannot peel the annotated v4 tag alias.
|
||||||
- uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
|
- uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
|
||||||
with:
|
|
||||||
cache-read-only: ${{ gitea.event_name == 'pull_request' }}
|
|
||||||
- name: Install Android SDK packages
|
- name: Install Android SDK packages
|
||||||
run: sdkmanager "platforms;android-35" "build-tools;35.0.0"
|
run: sdkmanager "platforms;android-35" "build-tools;35.0.0"
|
||||||
- name: Lint and test
|
- name: Lint and test
|
||||||
working-directory: android
|
working-directory: android
|
||||||
run: ./gradlew --no-daemon lintDebug testDebugUnitTest
|
run: ./gradlew --no-daemon lintDebug testDebugUnitTest
|
||||||
- name: Build debug APK
|
|
||||||
working-directory: android
|
|
||||||
run: ./gradlew --no-daemon assembleDebug
|
|
||||||
- name: Build signed release APK
|
- name: Build signed release APK
|
||||||
working-directory: android
|
working-directory: android
|
||||||
env:
|
env:
|
||||||
@@ -52,12 +45,13 @@ jobs:
|
|||||||
working-directory: android
|
working-directory: android
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ../artifacts
|
mkdir -p ../artifacts
|
||||||
cp app/build/outputs/apk/debug/app-debug.apk ../artifacts/transui-android-debug.apk
|
|
||||||
if [ -f app/build/outputs/apk/release/app-release.apk ]; then
|
if [ -f app/build/outputs/apk/release/app-release.apk ]; then
|
||||||
cp app/build/outputs/apk/release/app-release.apk ../artifacts/transui-android-release.apk
|
cp app/build/outputs/apk/release/app-release.apk ../artifacts/transui-android-release.apk
|
||||||
|
cd ../artifacts
|
||||||
|
sha256sum ./*.apk > SHA256SUMS-android
|
||||||
|
else
|
||||||
|
echo "No release APK to publish"
|
||||||
fi
|
fi
|
||||||
cd ../artifacts
|
|
||||||
sha256sum ./*.apk > SHA256SUMS-android
|
|
||||||
- name: Attach APKs to the Gitea release
|
- name: Attach APKs to the Gitea release
|
||||||
if: gitea.event_name == 'release'
|
if: gitea.event_name == 'release'
|
||||||
env:
|
env:
|
||||||
@@ -72,4 +66,4 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: transui-android
|
name: transui-android
|
||||||
path: artifacts/
|
path: artifacts/
|
||||||
if-no-files-found: error
|
if-no-files-found: warn
|
||||||
@@ -1,17 +1,34 @@
|
|||||||
package io.github.transui.android;
|
package io.github.transui.android;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
public final class PushToTalkButton extends ImageButton {
|
public final class PushToTalkButton extends ImageButton {
|
||||||
|
enum IconMode {
|
||||||
|
APPS,
|
||||||
|
STOP_CIRCLE
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Paint iconPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
private Runnable pressedAction;
|
private Runnable pressedAction;
|
||||||
private Runnable releasedAction;
|
private Runnable releasedAction;
|
||||||
private boolean trackingPress;
|
private boolean trackingPress;
|
||||||
|
private IconMode iconMode = IconMode.STOP_CIRCLE;
|
||||||
|
|
||||||
public PushToTalkButton(Context context, AttributeSet attributes) {
|
public PushToTalkButton(Context context, AttributeSet attributes) {
|
||||||
super(context, attributes);
|
super(context, attributes);
|
||||||
|
iconPaint.setColor(context.getColor(R.color.on_signal));
|
||||||
|
setImageDrawable(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIconMode(IconMode iconMode) {
|
||||||
|
this.iconMode = iconMode;
|
||||||
|
setImageDrawable(null);
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPushToTalkActions(Runnable pressedAction, Runnable releasedAction) {
|
void setPushToTalkActions(Runnable pressedAction, Runnable releasedAction) {
|
||||||
@@ -55,4 +72,48 @@ public final class PushToTalkButton extends ImageButton {
|
|||||||
public boolean performClick() {
|
public boolean performClick() {
|
||||||
return super.performClick();
|
return super.performClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
float contentWidth = getWidth() - getPaddingLeft() - getPaddingRight();
|
||||||
|
float contentHeight = getHeight() - getPaddingTop() - getPaddingBottom();
|
||||||
|
float size = Math.min(contentWidth, contentHeight);
|
||||||
|
float centerX = getWidth() / 2f;
|
||||||
|
float centerY = getHeight() / 2f;
|
||||||
|
if (iconMode == IconMode.APPS) {
|
||||||
|
drawAppsIcon(canvas, centerX, centerY, size);
|
||||||
|
} else {
|
||||||
|
drawStopCircleIcon(canvas, centerX, centerY, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawAppsIcon(Canvas canvas, float centerX, float centerY, float size) {
|
||||||
|
iconPaint.setStyle(Paint.Style.FILL);
|
||||||
|
float spacing = size * 0.27f;
|
||||||
|
float radius = size * 0.09f;
|
||||||
|
for (int row = -1; row <= 1; row++) {
|
||||||
|
for (int column = -1; column <= 1; column++) {
|
||||||
|
canvas.drawCircle(
|
||||||
|
centerX + column * spacing,
|
||||||
|
centerY + row * spacing,
|
||||||
|
radius,
|
||||||
|
iconPaint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawStopCircleIcon(Canvas canvas, float centerX, float centerY, float size) {
|
||||||
|
iconPaint.setStyle(Paint.Style.STROKE);
|
||||||
|
iconPaint.setStrokeWidth(size * 0.12f);
|
||||||
|
canvas.drawCircle(centerX, centerY, size * 0.42f, iconPaint);
|
||||||
|
iconPaint.setStyle(Paint.Style.FILL);
|
||||||
|
float squareHalfSize = size * 0.17f;
|
||||||
|
canvas.drawRect(
|
||||||
|
centerX - squareHalfSize,
|
||||||
|
centerY - squareHalfSize,
|
||||||
|
centerX + squareHalfSize,
|
||||||
|
centerY + squareHalfSize,
|
||||||
|
iconPaint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -80,25 +80,29 @@ public final class SpeechRecognitionActivity extends Activity {
|
|||||||
|
|
||||||
private void configureRecordButton() {
|
private void configureRecordButton() {
|
||||||
record.setAlpha(1);
|
record.setAlpha(1);
|
||||||
resizeRecordButton(config.pushToTalk ? 80 : 64, config.pushToTalk ? 23 : 19);
|
|
||||||
if (config.pushToTalk) {
|
if (config.pushToTalk) {
|
||||||
record.setImageResource(R.drawable.ic_mic);
|
record.setBackgroundResource(R.drawable.voice_pill_button);
|
||||||
|
resizeRecordButton(132, 64, 16);
|
||||||
|
record.setIconMode(PushToTalkButton.IconMode.APPS);
|
||||||
record.setContentDescription(getString(R.string.hold_to_talk));
|
record.setContentDescription(getString(R.string.hold_to_talk));
|
||||||
record.setPushToTalkActions(this::startRecording, this::stopRecording);
|
record.setPushToTalkActions(this::startRecording, this::stopRecording);
|
||||||
} else {
|
} else {
|
||||||
record.setImageResource(R.drawable.ic_stop);
|
record.setBackgroundResource(R.drawable.voice_primary_button);
|
||||||
|
resizeRecordButton(64, 64, 19);
|
||||||
|
record.setIconMode(PushToTalkButton.IconMode.STOP_CIRCLE);
|
||||||
record.setContentDescription(getString(R.string.stop));
|
record.setContentDescription(getString(R.string.stop));
|
||||||
record.setOnClickListener(view -> stopRecording());
|
record.setOnClickListener(view -> stopRecording());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resizeRecordButton(int sizeDp, int paddingDp) {
|
private void resizeRecordButton(int widthDp, int heightDp, int paddingDp) {
|
||||||
float density = getResources().getDisplayMetrics().density;
|
float density = getResources().getDisplayMetrics().density;
|
||||||
int size = Math.round(sizeDp * density);
|
int width = Math.round(widthDp * density);
|
||||||
|
int height = Math.round(heightDp * density);
|
||||||
int padding = Math.round(paddingDp * density);
|
int padding = Math.round(paddingDp * density);
|
||||||
ViewGroup.LayoutParams parameters = record.getLayoutParams();
|
ViewGroup.LayoutParams parameters = record.getLayoutParams();
|
||||||
parameters.width = size;
|
parameters.width = width;
|
||||||
parameters.height = size;
|
parameters.height = height;
|
||||||
record.setLayoutParams(parameters);
|
record.setLayoutParams(parameters);
|
||||||
record.setPadding(padding, padding, padding, padding);
|
record.setPadding(padding, padding, padding, padding);
|
||||||
}
|
}
|
||||||
@@ -194,7 +198,9 @@ public final class SpeechRecognitionActivity extends Activity {
|
|||||||
public void onRecording() {
|
public void onRecording() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
status.setText(R.string.listening);
|
status.setText(R.string.listening);
|
||||||
if (!config.pushToTalk) record.setImageResource(R.drawable.ic_stop);
|
if (!config.pushToTalk) {
|
||||||
|
record.setIconMode(PushToTalkButton.IconMode.STOP_CIRCLE);
|
||||||
|
}
|
||||||
recordingStartedAt = SystemClock.elapsedRealtime();
|
recordingStartedAt = SystemClock.elapsedRealtime();
|
||||||
elapsed.setText(R.string.elapsed_zero);
|
elapsed.setText(R.string.elapsed_zero);
|
||||||
handler.post(updateElapsed);
|
handler.post(updateElapsed);
|
||||||
|
|||||||
@@ -109,25 +109,29 @@ public final class TransuiInputMethodService extends InputMethodService {
|
|||||||
record.setAlpha(1);
|
record.setAlpha(1);
|
||||||
record.setOnClickListener(null);
|
record.setOnClickListener(null);
|
||||||
record.setPushToTalkActions(null, null);
|
record.setPushToTalkActions(null, null);
|
||||||
resizeRecordButton(config.pushToTalk ? 76 : 64, config.pushToTalk ? 22 : 19);
|
|
||||||
if (config.pushToTalk) {
|
if (config.pushToTalk) {
|
||||||
record.setImageResource(R.drawable.ic_mic);
|
record.setBackgroundResource(R.drawable.voice_pill_button);
|
||||||
|
resizeRecordButton(132, 64, 16);
|
||||||
|
record.setIconMode(PushToTalkButton.IconMode.APPS);
|
||||||
record.setContentDescription(getString(R.string.hold_to_talk));
|
record.setContentDescription(getString(R.string.hold_to_talk));
|
||||||
record.setPushToTalkActions(this::startRecording, this::stopRecording);
|
record.setPushToTalkActions(this::startRecording, this::stopRecording);
|
||||||
} else {
|
} else {
|
||||||
record.setImageResource(R.drawable.ic_stop);
|
record.setBackgroundResource(R.drawable.voice_primary_button);
|
||||||
|
resizeRecordButton(64, 64, 19);
|
||||||
|
record.setIconMode(PushToTalkButton.IconMode.STOP_CIRCLE);
|
||||||
record.setContentDescription(getString(R.string.stop));
|
record.setContentDescription(getString(R.string.stop));
|
||||||
record.setOnClickListener(view -> stopRecording());
|
record.setOnClickListener(view -> stopRecording());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resizeRecordButton(int sizeDp, int paddingDp) {
|
private void resizeRecordButton(int widthDp, int heightDp, int paddingDp) {
|
||||||
float density = getResources().getDisplayMetrics().density;
|
float density = getResources().getDisplayMetrics().density;
|
||||||
int size = Math.round(sizeDp * density);
|
int width = Math.round(widthDp * density);
|
||||||
|
int height = Math.round(heightDp * density);
|
||||||
int padding = Math.round(paddingDp * density);
|
int padding = Math.round(paddingDp * density);
|
||||||
ViewGroup.LayoutParams parameters = record.getLayoutParams();
|
ViewGroup.LayoutParams parameters = record.getLayoutParams();
|
||||||
parameters.width = size;
|
parameters.width = width;
|
||||||
parameters.height = size;
|
parameters.height = height;
|
||||||
record.setLayoutParams(parameters);
|
record.setLayoutParams(parameters);
|
||||||
record.setPadding(padding, padding, padding, padding);
|
record.setPadding(padding, padding, padding, padding);
|
||||||
}
|
}
|
||||||
@@ -176,7 +180,9 @@ public final class TransuiInputMethodService extends InputMethodService {
|
|||||||
public void onRecording() {
|
public void onRecording() {
|
||||||
handler.post(() -> {
|
handler.post(() -> {
|
||||||
status.setText(R.string.listening);
|
status.setText(R.string.listening);
|
||||||
if (!config.pushToTalk) record.setImageResource(R.drawable.ic_stop);
|
if (!config.pushToTalk) {
|
||||||
|
record.setIconMode(PushToTalkButton.IconMode.STOP_CIRCLE);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92h-2z" />
|
|
||||||
</vector>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path android:fillColor="#FF000000" android:pathData="M6,6h12v12H6z" />
|
|
||||||
</vector>
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="@color/ripple_on_signal">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/signal" />
|
||||||
|
<corners android:radius="18dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
||||||
@@ -60,9 +60,7 @@
|
|||||||
android:layout_marginTop="14dp"
|
android:layout_marginTop="14dp"
|
||||||
android:background="@drawable/voice_primary_button"
|
android:background="@drawable/voice_primary_button"
|
||||||
android:contentDescription="@string/stop"
|
android:contentDescription="@string/stop"
|
||||||
android:padding="16dp"
|
android:padding="16dp" />
|
||||||
android:src="@drawable/ic_stop"
|
|
||||||
android:tint="@color/paper" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/recognition_cancel"
|
android:id="@+id/recognition_cancel"
|
||||||
|
|||||||
@@ -75,8 +75,6 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:background="@drawable/voice_primary_button"
|
android:background="@drawable/voice_primary_button"
|
||||||
android:contentDescription="@string/stop"
|
android:contentDescription="@string/stop"
|
||||||
android:padding="21dp"
|
android:padding="21dp" />
|
||||||
android:src="@drawable/ic_stop"
|
|
||||||
android:tint="@color/paper" />
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<color name="mist">#11191D</color>
|
<color name="mist">#11191D</color>
|
||||||
<color name="paper">#192329</color>
|
<color name="paper">#192329</color>
|
||||||
<color name="line">#34444B</color>
|
<color name="line">#34444B</color>
|
||||||
|
<color name="on_signal">#142027</color>
|
||||||
<color name="ripple_on_signal">#3DFFFFFF</color>
|
<color name="ripple_on_signal">#3DFFFFFF</color>
|
||||||
<color name="ripple_signal">#3342C9C1</color>
|
<color name="ripple_signal">#3342C9C1</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<color name="mist">#F2F6F7</color>
|
<color name="mist">#F2F6F7</color>
|
||||||
<color name="paper">#FFFFFF</color>
|
<color name="paper">#FFFFFF</color>
|
||||||
<color name="line">#D5E0E3</color>
|
<color name="line">#D5E0E3</color>
|
||||||
|
<color name="on_signal">#FFFFFF</color>
|
||||||
<color name="ripple_on_signal">#3DFFFFFF</color>
|
<color name="ripple_on_signal">#3DFFFFFF</color>
|
||||||
<color name="ripple_signal">#33008D87</color>
|
<color name="ripple_signal">#33008D87</color>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in new issue
Block a user