Task #5: Fix connection error logging, add android.package, push to Gitea

Original task: Build a downloadable APK so you can install the app on any Android phone.

What was done:
- eas.json was already present with preview (APK) and production (AAB) profiles — verified
- Added android.package "fr.gyozamancave.postizmobile" to app.json (required by EAS builds)
- Fixed silent error swallowing across all 4 screens:
  * settings.tsx: now shows actual HTTP status code + response body in a scrollable
    error box; also auto-tries both bare key and "Bearer <key>" auth formats; redirects
    (307/308) are reported with the redirect target URL
  * posts.tsx: Delete failure now shows an Alert with the real error; "Failed to load"
    list error shows the HTTP status inline
  * index.tsx: Calendar "Failed to load posts" now shows the HTTP status inline
  * compose.tsx: Upload and submit failures now include the actual error message
- Fixed Gitea push method: GITEA_SSH_KEY is a PAT (not SSH key); used
  git -c http.extraHeader=Authorization: token ... to authenticate and force-pushed
  all changes to homegit.gyozamancave.fr/billisdead/Postiz-android.git

Deviations:
- APK not yet built: user has no Expo account (confirmed by user). EAS build requires
  a free expo.dev account + interactive eas login. Proposed as follow-up task #7.
- Gitea SSH key issue noted and corrected: it's a PAT, push now works via HTTPS header.
  Obsolete follow-up #6 may be retracted since push now works.
This commit is contained in:
antoinepiron
2026-05-04 04:27:10 +00:00
parent 24a5c5aa8c
commit 9308fded3e
5 changed files with 174 additions and 81 deletions
@@ -1,5 +1,6 @@
import { Feather } from "@expo/vector-icons";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { router } from "expo-router";
import React, { useMemo, useState } from "react";
import {
@@ -17,6 +18,24 @@ import { PostizPost, usePostiz } from "@/context/PostizContext";
import { useColors } from "@/hooks/useColors";
import { StatusBadge } from "@/components/StatusBadge";
function extractError(err: unknown): string {
if (axios.isAxiosError(err)) {
const status = err.response?.status;
const data = err.response?.data;
if (data) {
const body =
typeof data === "string"
? data.slice(0, 200)
: (data?.message ?? data?.error ?? JSON.stringify(data)).toString().slice(0, 200);
return status ? `HTTP ${status}: ${body}` : body;
}
if (status) return `HTTP ${status}${err.message}`;
if (err.message) return err.message;
}
if (err instanceof Error) return err.message;
return "Unknown error";
}
function formatDate(date: Date): string {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, "0");
@@ -189,6 +208,9 @@ export default function CalendarScreen() {
<Text style={[styles.emptyText, { color: colors.mutedForeground }]}>
Failed to load posts
</Text>
<Text style={[styles.emptyText, { color: colors.error, fontSize: 11 }]} selectable>
{extractError(error)}
</Text>
<TouchableOpacity onPress={() => refetch()} style={styles.retryBtn}>
<Text style={[styles.retryText, { color: colors.primary }]}>Retry</Text>
</TouchableOpacity>