Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58f33da6bf | |||
| 1b3fcca0d5 | |||
| 4e480d7cb5 | |||
| 42a0a0bb8a | |||
| ca5d8a9c55 | |||
| 48befd7e9b |
@@ -0,0 +1,122 @@
|
|||||||
|
name: Android Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
ANDROID_HOME: /opt/android-sdk
|
||||||
|
NDK_VERSION: 30.0.14904198
|
||||||
|
BUILD_TOOLS_VERSION: "36.1.0"
|
||||||
|
PLATFORM: android-34
|
||||||
|
APK_OUT: target/release/apk/solitaire-quest.apk
|
||||||
|
GITEA_URL: https://git.aleshym.co
|
||||||
|
REPO: funman300/Rusty_Solitare
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-apk:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Java 17
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Cache Android SDK
|
||||||
|
uses: actions/cache@v4
|
||||||
|
id: android-cache
|
||||||
|
with:
|
||||||
|
path: /opt/android-sdk
|
||||||
|
key: android-sdk-${{ env.NDK_VERSION }}-${{ env.BUILD_TOOLS_VERSION }}
|
||||||
|
|
||||||
|
- name: Install Android SDK + NDK
|
||||||
|
if: steps.android-cache.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
mkdir -p $ANDROID_HOME/cmdline-tools
|
||||||
|
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip \
|
||||||
|
-O /tmp/cmdtools.zip
|
||||||
|
unzip -q /tmp/cmdtools.zip -d $ANDROID_HOME/cmdline-tools
|
||||||
|
mv $ANDROID_HOME/cmdline-tools/cmdline-tools $ANDROID_HOME/cmdline-tools/latest
|
||||||
|
yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses >/dev/null || true
|
||||||
|
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
|
||||||
|
"ndk;$NDK_VERSION" \
|
||||||
|
"build-tools;$BUILD_TOOLS_VERSION" \
|
||||||
|
"platforms;$PLATFORM"
|
||||||
|
|
||||||
|
- name: Set up Rust (stable + aarch64-android)
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: aarch64-linux-android
|
||||||
|
|
||||||
|
- name: Cache Cargo
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry/index
|
||||||
|
~/.cargo/registry/cache
|
||||||
|
~/.cargo/git/db
|
||||||
|
~/.cargo/bin/cargo-ndk
|
||||||
|
target/aarch64-linux-android
|
||||||
|
key: cargo-android-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: cargo-android-
|
||||||
|
|
||||||
|
- name: Install cargo-ndk
|
||||||
|
run: cargo-ndk --version 2>/dev/null || cargo install cargo-ndk --version 4.1.2 --locked
|
||||||
|
|
||||||
|
- name: Decode release keystore
|
||||||
|
run: echo "${{ secrets.RELEASE_KEYSTORE_B64 }}" | base64 -d > release.jks
|
||||||
|
|
||||||
|
- name: Build release APK
|
||||||
|
env:
|
||||||
|
ANDROID_NDK_HOME: /opt/android-sdk/ndk/${{ env.NDK_VERSION }}
|
||||||
|
PROFILE: release
|
||||||
|
ABIS: arm64-v8a
|
||||||
|
KEYSTORE: ./release.jks
|
||||||
|
KEYSTORE_PASS: ${{ secrets.RELEASE_KEYSTORE_PASS }}
|
||||||
|
KEY_ALIAS: release
|
||||||
|
KEY_PASS: ${{ secrets.RELEASE_KEYSTORE_PASS }}
|
||||||
|
run: bash scripts/build_android_apk.sh
|
||||||
|
|
||||||
|
- name: Get tag name
|
||||||
|
id: tag
|
||||||
|
run: echo "name=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Create or get Gitea release
|
||||||
|
id: release
|
||||||
|
run: |
|
||||||
|
TAG="${{ steps.tag.outputs.name }}"
|
||||||
|
BASE="${{ env.GITEA_URL }}/api/v1/repos/${{ env.REPO }}"
|
||||||
|
AUTH="Authorization: token ${{ secrets.CI_TOKEN }}"
|
||||||
|
|
||||||
|
# Re-use an existing release for this tag (e.g. created manually).
|
||||||
|
ID=$(curl -sf -H "$AUTH" "$BASE/releases/tags/$TAG" \
|
||||||
|
| python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" \
|
||||||
|
2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -z "$ID" ]; then
|
||||||
|
ID=$(curl -sf -X POST \
|
||||||
|
-H "$AUTH" -H "Content-Type: application/json" \
|
||||||
|
"$BASE/releases" \
|
||||||
|
-d "{
|
||||||
|
\"tag_name\": \"$TAG\",
|
||||||
|
\"name\": \"$TAG\",
|
||||||
|
\"body\": \"## Android release $TAG\n\n**Install / update with Obtainium** — add this source URL:\n\`\`\`\nhttps://git.aleshym.co/funman300/Rusty_Solitare\n\`\`\`\n\nOr download \`solitaire-quest.apk\` below and sideload it directly.\",
|
||||||
|
\"draft\": false,
|
||||||
|
\"prerelease\": false
|
||||||
|
}" \
|
||||||
|
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
||||||
|
fi
|
||||||
|
echo "id=$ID" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Upload APK to release
|
||||||
|
run: |
|
||||||
|
curl -sf -X POST \
|
||||||
|
-H "Authorization: token ${{ secrets.CI_TOKEN }}" \
|
||||||
|
-F "attachment=@${{ env.APK_OUT }};type=application/vnd.android.package-archive" \
|
||||||
|
"${{ env.GITEA_URL }}/api/v1/repos/${{ env.REPO }}/releases/${{ steps.release.outputs.id }}/assets"
|
||||||
@@ -3,11 +3,13 @@ name: Build and Deploy
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
# Only run when server code changes, not when CI itself updates deploy/.
|
paths:
|
||||||
paths-ignore:
|
- 'solitaire_server/**'
|
||||||
- 'deploy/**'
|
- 'solitaire_sync/**'
|
||||||
- 'argocd/**'
|
- 'solitaire_core/**'
|
||||||
- '**.md'
|
- 'Cargo.toml'
|
||||||
|
- 'Cargo.lock'
|
||||||
|
- '.gitea/workflows/docker-build.yml'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: git.aleshym.co
|
REGISTRY: git.aleshym.co
|
||||||
@@ -68,6 +70,9 @@ jobs:
|
|||||||
git config user.email "ci@gitea.local"
|
git config user.email "ci@gitea.local"
|
||||||
git config user.name "Gitea CI"
|
git config user.name "Gitea CI"
|
||||||
git add deploy/kustomization.yaml
|
git add deploy/kustomization.yaml
|
||||||
git commit -m "chore(deploy): bump image to ${{ steps.meta.outputs.sha }} [skip ci]" || true
|
git diff --cached --quiet && exit 0 # nothing to commit — skip push
|
||||||
git pull --rebase origin master
|
git commit -m "chore(deploy): bump image to ${{ steps.meta.outputs.sha }} [skip ci]"
|
||||||
git push
|
for i in 1 2 3; do
|
||||||
|
git pull --rebase origin master && git push && break
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ resources:
|
|||||||
images:
|
images:
|
||||||
- name: solitaire-server
|
- name: solitaire-server
|
||||||
newName: git.aleshym.co/funman300/solitaire-server
|
newName: git.aleshym.co/funman300/solitaire-server
|
||||||
newTag: c35c045f
|
newTag: ca5d8a9c
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ use crate::ui_modal::{
|
|||||||
spawn_modal, spawn_modal_actions, spawn_modal_button, spawn_modal_header, ButtonVariant,
|
spawn_modal, spawn_modal_actions, spawn_modal_button, spawn_modal_header, ButtonVariant,
|
||||||
ScrimDismissible,
|
ScrimDismissible,
|
||||||
};
|
};
|
||||||
use crate::ui_theme::{
|
use crate::ui_theme::{SPACE_2, TEXT_PRIMARY, TEXT_SECONDARY, TYPE_BODY, VAL_SPACE_2, VAL_SPACE_3, Z_MODAL_PANEL};
|
||||||
BORDER_SUBTLE, HighContrastBorder, RADIUS_SM, SPACE_2, TEXT_PRIMARY, TEXT_SECONDARY, TYPE_BODY,
|
#[cfg(not(target_os = "android"))]
|
||||||
TYPE_CAPTION, VAL_SPACE_1, VAL_SPACE_2, VAL_SPACE_3, Z_MODAL_PANEL,
|
use crate::ui_theme::{BORDER_SUBTLE, HighContrastBorder, RADIUS_SM, TYPE_CAPTION, VAL_SPACE_1};
|
||||||
};
|
|
||||||
|
|
||||||
/// Marker on the help overlay root node.
|
/// Marker on the help overlay root node.
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
@@ -123,6 +122,7 @@ fn scroll_help_panel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Each entry in the controls reference table.
|
/// Each entry in the controls reference table.
|
||||||
|
#[allow(dead_code)]
|
||||||
struct ControlRow {
|
struct ControlRow {
|
||||||
keys: &'static str,
|
keys: &'static str,
|
||||||
description: &'static str,
|
description: &'static str,
|
||||||
@@ -243,6 +243,7 @@ fn spawn_help_screen(commands: &mut Commands, font_res: Option<&FontResource>) {
|
|||||||
..default()
|
..default()
|
||||||
};
|
};
|
||||||
let font_row = font_section.clone();
|
let font_row = font_section.clone();
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
let font_kbd = TextFont {
|
let font_kbd = TextFont {
|
||||||
font: font_handle,
|
font: font_handle,
|
||||||
font_size: TYPE_CAPTION,
|
font_size: TYPE_CAPTION,
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ impl HomeMode {
|
|||||||
|
|
||||||
/// The keyboard accelerator that dispatches the same launch event,
|
/// The keyboard accelerator that dispatches the same launch event,
|
||||||
/// shown in a small chip on the card.
|
/// shown in a small chip on the card.
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
fn hotkey(self) -> &'static str {
|
fn hotkey(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
HomeMode::Classic => "N",
|
HomeMode::Classic => "N",
|
||||||
|
|||||||
@@ -799,8 +799,7 @@ fn spawn_action_button<M: Component>(
|
|||||||
// visibly clutter the narrow-viewport action row. Force the hint
|
// visibly clutter the narrow-viewport action row. Force the hint
|
||||||
// off on Android; the chevrons on Menu/Modes remain because they
|
// off on Android; the chevrons on Menu/Modes remain because they
|
||||||
// indicate dropdown behaviour and still apply on touch.
|
// indicate dropdown behaviour and still apply on touch.
|
||||||
#[cfg(target_os = "android")]
|
let hotkey = if cfg!(target_os = "android") { None } else { hotkey };
|
||||||
let hotkey: Option<&'static str> = None;
|
|
||||||
|
|
||||||
let hotkey_font = TextFont {
|
let hotkey_font = TextFont {
|
||||||
font: font.font.clone(),
|
font: font.font.clone(),
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ use crate::ui_modal::{
|
|||||||
spawn_modal, spawn_modal_actions, spawn_modal_body_text, spawn_modal_button,
|
spawn_modal, spawn_modal_actions, spawn_modal_body_text, spawn_modal_button,
|
||||||
spawn_modal_header, ButtonVariant,
|
spawn_modal_header, ButtonVariant,
|
||||||
};
|
};
|
||||||
|
use crate::ui_theme::{TEXT_SECONDARY, Z_ONBOARDING};
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
use crate::ui_theme::{
|
use crate::ui_theme::{
|
||||||
BORDER_SUBTLE, HighContrastBorder, RADIUS_SM, TEXT_PRIMARY, TEXT_SECONDARY, TYPE_BODY,
|
BORDER_SUBTLE, HighContrastBorder, RADIUS_SM, TEXT_PRIMARY, TYPE_BODY, TYPE_CAPTION,
|
||||||
TYPE_CAPTION, VAL_SPACE_1, VAL_SPACE_2, VAL_SPACE_3, Z_ONBOARDING,
|
VAL_SPACE_1, VAL_SPACE_2, VAL_SPACE_3,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -86,6 +88,7 @@ pub struct OnboardingSlideIndex(pub u8);
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/// A single `key — description` pair shown on slide 3.
|
/// A single `key — description` pair shown on slide 3.
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
struct HotkeyRow {
|
struct HotkeyRow {
|
||||||
keys: &'static str,
|
keys: &'static str,
|
||||||
description: &'static str,
|
description: &'static str,
|
||||||
@@ -96,6 +99,7 @@ struct HotkeyRow {
|
|||||||
/// Updating the list in `help_plugin.rs` should be mirrored here. The
|
/// Updating the list in `help_plugin.rs` should be mirrored here. The
|
||||||
/// ARCHITECTURE.md decision log calls out that we copy values rather than
|
/// ARCHITECTURE.md decision log calls out that we copy values rather than
|
||||||
/// refactor the help plugin.
|
/// refactor the help plugin.
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
const HOTKEYS: &[HotkeyRow] = &[
|
const HOTKEYS: &[HotkeyRow] = &[
|
||||||
HotkeyRow { keys: "D / Space", description: "Draw from stock" },
|
HotkeyRow { keys: "D / Space", description: "Draw from stock" },
|
||||||
HotkeyRow { keys: "U", description: "Undo last move" },
|
HotkeyRow { keys: "U", description: "Undo last move" },
|
||||||
@@ -359,6 +363,7 @@ fn spawn_slide_how_to_play(commands: &mut Commands, font_res: Option<&FontResour
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Slide 3 — Keyboard shortcuts.
|
/// Slide 3 — Keyboard shortcuts.
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
fn spawn_slide_hotkeys(commands: &mut Commands, font_res: Option<&FontResource>) {
|
fn spawn_slide_hotkeys(commands: &mut Commands, font_res: Option<&FontResource>) {
|
||||||
let font_handle = font_res.map(|f| f.0.clone()).unwrap_or_default();
|
let font_handle = font_res.map(|f| f.0.clone()).unwrap_or_default();
|
||||||
let font_row = TextFont {
|
let font_row = TextFont {
|
||||||
|
|||||||
@@ -1165,6 +1165,7 @@ fn keybind_footer_mode_text() -> &'static str {
|
|||||||
/// pause/resume, the ESC accelerator for stop, and the ← / →
|
/// pause/resume, the ESC accelerator for stop, and the ← / →
|
||||||
/// accelerators for paused single-move stepping. The footer never
|
/// accelerators for paused single-move stepping. The footer never
|
||||||
/// lists unimplemented keybinds (would lie to users).
|
/// lists unimplemented keybinds (would lie to users).
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
fn keybind_footer_hint_text() -> &'static str {
|
fn keybind_footer_hint_text() -> &'static str {
|
||||||
"[SPACE] pause/resume \u{00B7} [ESC] stop \u{00B7} [\u{2190}\u{2192}] step" // · separator
|
"[SPACE] pause/resume \u{00B7} [ESC] stop \u{00B7} [\u{2190}\u{2192}] step" // · separator
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,8 +335,7 @@ pub fn spawn_modal_button<M: Component>(
|
|||||||
variant: ButtonVariant,
|
variant: ButtonVariant,
|
||||||
font_res: Option<&FontResource>,
|
font_res: Option<&FontResource>,
|
||||||
) {
|
) {
|
||||||
#[cfg(target_os = "android")]
|
let hotkey = if cfg!(target_os = "android") { None } else { hotkey };
|
||||||
let hotkey: Option<&'static str> = None;
|
|
||||||
let font_handle = font_res.map(|f| f.0.clone()).unwrap_or_default();
|
let font_handle = font_res.map(|f| f.0.clone()).unwrap_or_default();
|
||||||
let font_label = TextFont {
|
let font_label = TextFont {
|
||||||
font: font_handle.clone(),
|
font: font_handle.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user