Skip to content
Open
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
3a0cd72
feat(mobile): add quick archive controls
Feighery89 Aug 1, 2026
edade0e
fix(mobile): hide empty states when archives match
Feighery89 Aug 1, 2026
fe4bef7
feat(mobile): add Android background connection service
snipemanmike Aug 1, 2026
54b5714
feat(mobile): keep connection state mounted headlessly
snipemanmike Aug 1, 2026
e2890f9
refactor(mobile): share the thread outbox drain worker
snipemanmike Aug 1, 2026
bb48473
feat(mobile): retain relay auth for headless connections
snipemanmike Aug 1, 2026
1afeb24
fix(mobile): preserve healthy background sessions on resume
snipemanmike Aug 1, 2026
9c7b100
docs(mobile): document the Android background runtime
snipemanmike Aug 1, 2026
9ebcc37
fix(mobile): close background connection races
snipemanmike Aug 1, 2026
f05becb
feat(mobile): add local Android agent notifications
Feighery89 Aug 1, 2026
ddf6c2a
ci(mobile): publish personal Android preview
Feighery89 Aug 2, 2026
aa29da5
fix(ci): avoid nested submodule checkout cleanup
Feighery89 Aug 2, 2026
61e7b34
fix(ci): parse preview package name exactly
Feighery89 Aug 2, 2026
bf515fe
chore(ci): clean preview release metadata
Feighery89 Aug 2, 2026
3e0f960
feat(mobile): update personal Android preview in app
Feighery89 Aug 2, 2026
8476ef8
ci(mobile): ship signed preview updates
Feighery89 Aug 2, 2026
11f823d
fix(ci): retain personal preview features after merges
Feighery89 Aug 2, 2026
30835fe
fix(ci): retain and publish signed preview artifacts
Feighery89 Aug 2, 2026
ce8e7c0
fix(ci): embed personal preview configuration
Feighery89 Aug 2, 2026
900a62b
fix(mobile): embed personal preview setup
Feighery89 Aug 2, 2026
4c95746
fix(ci): pin embedded preview setup
Feighery89 Aug 2, 2026
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
106 changes: 106 additions & 0 deletions .github/scripts/prepare-personal-android-preview.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";

const [sourceRootArgument, versionCodeArgument] = process.argv.slice(2);

if (!sourceRootArgument || !versionCodeArgument) {
throw new Error(
"Usage: prepare-personal-android-preview.mjs <source-root> <version-code>",
);
}

const sourceRoot = path.resolve(sourceRootArgument);
const versionCode = Number(versionCodeArgument);

if (
!Number.isSafeInteger(versionCode) ||
versionCode < 1 ||
versionCode > 2_100_000_000
) {
throw new Error(`Invalid Android version code: ${versionCodeArgument}`);
}

function replaceOnce(contents, search, replacement, label) {
const firstIndex = contents.indexOf(search);
const lastIndex = contents.lastIndexOf(search);

if (firstIndex === -1) {
throw new Error(`Could not find ${label}`);
}

if (firstIndex !== lastIndex) {
throw new Error(`Found ${label} more than once`);
}

return `${contents.slice(0, firstIndex)}${replacement}${contents.slice(firstIndex + search.length)}`;
}

const manifestPath = path.join(
sourceRoot,
"apps/mobile/android/app/src/main/AndroidManifest.xml",
);
const buildGradlePath = path.join(
sourceRoot,
"apps/mobile/android/app/build.gradle",
);

let manifest = await readFile(manifestPath, "utf8");
manifest = replaceOnce(
manifest,
'<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>',
'<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>',
"enabled Expo updates metadata",
);
await writeFile(manifestPath, manifest);

let buildGradle = await readFile(buildGradlePath, "utf8");

if (
!buildGradle.includes("namespace 'com.t3tools.t3code.preview'") ||
!buildGradle.includes("applicationId 'com.t3tools.t3code.preview'")
) {
throw new Error("Refusing to sign a build that is not the Android preview variant");
}

const versionCodeMatches = [...buildGradle.matchAll(/^\s*versionCode \d+$/gm)];
if (versionCodeMatches.length !== 1) {
throw new Error(
`Expected one generated versionCode declaration, found ${versionCodeMatches.length}`,
);
}
buildGradle = buildGradle.replace(
versionCodeMatches[0][0],
` versionCode ${versionCode}`,
);

buildGradle = replaceOnce(
buildGradle,
" signingConfigs {\n debug {",
` signingConfigs {
previewRelease {
storeFile file(System.getenv("T3CODE_PREVIEW_KEYSTORE_FILE"))
storePassword System.getenv("T3CODE_PREVIEW_KEYSTORE_PASSWORD")
keyAlias "t3code-preview"
keyPassword System.getenv("T3CODE_PREVIEW_KEYSTORE_PASSWORD")
}
debug {`,
"generated Android signingConfigs block",
);

const releaseBlockIndex = buildGradle.indexOf(" release {");
const releaseSigning = " signingConfig signingConfigs.debug";
const releaseSigningIndex = buildGradle.indexOf(
releaseSigning,
releaseBlockIndex,
);

if (releaseBlockIndex === -1 || releaseSigningIndex === -1) {
throw new Error("Could not find the generated release signing configuration");
}

buildGradle = `${buildGradle.slice(0, releaseSigningIndex)} signingConfig signingConfigs.previewRelease${buildGradle.slice(releaseSigningIndex + releaseSigning.length)}`;
await writeFile(buildGradlePath, buildGradle);

console.log(
`Prepared com.t3tools.t3code.preview versionCode ${versionCode} with private signing and official OTA updates disabled.`,
);
15 changes: 15 additions & 0 deletions .github/systemd/t3code-preview-dispatch.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=Dispatch the personal T3 Code Android preview build
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
Environment=GH_CONFIG_DIR=/home/admin/.config/gh
Environment=HOME=/home/admin
ExecStart=/usr/bin/gh workflow run personal-android-preview.yml --repo Feighery89/t3code --ref main -f force_rebuild=false
Restart=on-failure
RestartSec=15min
TimeoutStartSec=2min
NoNewPrivileges=true
PrivateTmp=true
12 changes: 12 additions & 0 deletions .github/systemd/t3code-preview-dispatch.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=Check daily for a new personal T3 Code Android preview

[Timer]
OnCalendar=*-*-* 05:47:00 Europe/Dublin
Persistent=true
RandomizedDelaySec=20min
AccuracySec=1min
Unit=t3code-preview-dispatch.service

[Install]
WantedBy=timers.target
Loading
Loading