feat: update image requirements to landscape orientation and add CI/CD workflow
Some checks failed
Build App / build (push) Failing after 3m44s
43
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Build App
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 🏗 Setup repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: 🏗 Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: 🏗 Setup Expo and EAS
|
||||
uses: expo/expo-github-action@v7
|
||||
with:
|
||||
token: ${{ secrets.EXPO_TOKEN }}
|
||||
expo-version: latest
|
||||
eas-version: latest
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: npm install
|
||||
working-directory: App
|
||||
|
||||
- name: 👷 Build app
|
||||
run: |
|
||||
eas build --local \
|
||||
--non-interactive \
|
||||
--output=./app-build \
|
||||
--platform=android \
|
||||
--profile=preview
|
||||
working-directory: App
|
||||
|
||||
|
||||
- name: 📤 Upload build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: android-preview-build.zip
|
||||
path: App/app-build/*
|
||||
if-no-files-found: error
|
||||
4
.github/copilot-instructions.md
vendored
@@ -37,9 +37,9 @@ Images/rotator assets stored in MinIO at `content2.reversed.dev`, bucket `tv-con
|
||||
|
||||
`settings` is a persistent object with global TV display configuration (typed as `SettingsState` in `tv/src/types.ts`).
|
||||
|
||||
- **`background_url`** — a portrait image (height > width) rendered as a full-screen `object-cover` background behind all TV content. Empty string = no background.
|
||||
- **`background_url`** — a landscape image (width > height) rendered as a full-screen `object-cover` background behind all TV content. Empty string = no background.
|
||||
- Set via `push_settings { background_url }`, cleared by passing `""`.
|
||||
- The constraint (portrait orientation) is enforced in the mobile picker (`mobile/src/pages/settings.tsx`) — `asset.width >= asset.height` is rejected.
|
||||
- The constraint (landscape orientation) is enforced in the mobile picker (`mobile/src/pages/settings.tsx`) — `asset.width <= asset.height` is rejected.
|
||||
- Images are uploaded first via `push_upload_images` to get a MinIO URL, then saved via `push_settings`.
|
||||
- The Settings tab is visible in the mobile bottom nav (no `hideInNav`).
|
||||
|
||||
|
||||
@@ -1,30 +1,37 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "mobile",
|
||||
"slug": "mobile",
|
||||
"name": "TV Control",
|
||||
"slug": "tv-control",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"newArchEnabled": true,
|
||||
"splash": {
|
||||
"image": "./assets/splash-icon.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
"backgroundColor": "#8c8c8c"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
"supportsTablet": false,
|
||||
"bundleIdentifier": "dev.reversed.tvcontrol"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
"backgroundColor": "#8c8c8c"
|
||||
},
|
||||
"package": "dev.reversed.tvcontrol",
|
||||
"edgeToEdgeEnabled": true,
|
||||
"predictiveBackGestureEnabled": false
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
},
|
||||
"extra": {
|
||||
"eas": {
|
||||
"projectId": "4e663169-e9d3-4ca5-95e3-4c2477fcd072"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 584 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 584 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 584 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 584 KiB |
30
mobile/eas.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"cli": {
|
||||
"version": ">= 16.0.0",
|
||||
"appVersionSource": "local"
|
||||
},
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": true,
|
||||
"distribution": "internal",
|
||||
"android": {
|
||||
"buildType": "apk"
|
||||
},
|
||||
"ios": {
|
||||
"simulator": true
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal",
|
||||
"android": {
|
||||
"buildType": "apk"
|
||||
}
|
||||
},
|
||||
"production": {
|
||||
"autoIncrement": true,
|
||||
"android": {
|
||||
"buildType": "app-bundle"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export function SettingsPage() {
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
// ── Pick a portrait image from the gallery
|
||||
// ── Pick a landscape image from the gallery
|
||||
const handlePickBackground = async () => {
|
||||
const { granted } = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
if (!granted) {
|
||||
@@ -57,9 +57,9 @@ export function SettingsPage() {
|
||||
|
||||
const asset = result.assets[0];
|
||||
|
||||
// Enforce portrait orientation (height must exceed width)
|
||||
if (asset.width >= asset.height) {
|
||||
setStatus("Please pick a portrait image (height must be greater than width).");
|
||||
// Enforce landscape orientation (width must exceed height)
|
||||
if (asset.width <= asset.height) {
|
||||
setStatus("Please pick a landscape image (width must be greater than height).");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ export function SettingsPage() {
|
||||
<View style={styles.section}>
|
||||
<Text style={shared.sectionLabel}>TV Background</Text>
|
||||
<Text style={shared.hint}>
|
||||
Displayed behind all content on the TV. Must be a portrait image (taller than wide).
|
||||
Displayed behind all content on the TV. Must be a landscape image (wider than tall).
|
||||
</Text>
|
||||
|
||||
{loading ? (
|
||||
@@ -246,7 +246,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
preview: {
|
||||
width: "100%",
|
||||
aspectRatio: 9 / 16,
|
||||
aspectRatio: 16 / 9,
|
||||
},
|
||||
pendingBadge: {
|
||||
position: "absolute",
|
||||
@@ -266,7 +266,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
emptyPreview: {
|
||||
width: "100%",
|
||||
aspectRatio: 9 / 16,
|
||||
aspectRatio: 16 / 9,
|
||||
borderRadius: 14,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
|
||||