Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
280 changes: 167 additions & 113 deletions .github/workflows/debugbuild.yml

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ You can build the app in either release or debug mode. If you're building it in
flutter build ios --<INSERT MODE>
```

## iOS install via SideStore / AltStore

CI builds an IPA on each deploy, packages it for SideStore (correct `Payload/` zip layout + ad-hoc `codesign` on macOS), and regenerates an [AltStore source](https://faq.altstore.io/developers/make-a-source) at `docs/altstore-source.json` from **all** GitHub Releases, including pre-releases.

**Source URL** (add once in SideStore or AltStore):

`https://github.com/floatyfp/floaty/blob/release/docs/altstore-source.json?raw=true`

(or the equivalent raw URL for your fork/branch)

Edit static metadata in `docs/altstore-source.meta.json`; version entries are filled automatically from release assets (`floaty-*-ios.ipa`).

- **Windows**
```bash
flutter build windows --<INSERT MODE>
Expand Down
131 changes: 131 additions & 0 deletions docs/altstore-source.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
{
"name": "Floaty",
"subtitle": "Open-source Floatplane client for iOS",
"description": "Floaty builds for iOS from GitHub Releases. Includes pre-releases from nightly, beta, and development branches. IPAs are packaged for SideStore and AltStore.",
"iconURL": "https://floaty.fyi/assets/floaty.png",
"website": "https://floaty.fyi",
"tintColor": "#3b82f6",
"featuredApps": [
"uk.bw86.floaty"
],
"news": [],
"apps": [
{
"name": "Floaty",
"bundleIdentifier": "uk.bw86.floaty",
"developerName": "Floaty",
"subtitle": "Floatplane client for iOS",
"localizedDescription": "An open-source Floatplane client. Install via SideStore or AltStore; pick a build matching your branch (release, beta, nightly, or development).",
"iconURL": "https://floaty.fyi/assets/floaty.png",
"tintColor": "#3b82f6",
"category": "entertainment",
"screenshots": [],
"appPermissions": {
"entitlements": [],
"privacy": {}
},
"patreon": {},
"versions": [
{
"version": "0.0.22",
"buildVersion": "22",
"marketingVersion": "0.0.22 (22)",
"date": "2026-06-03T08:00:24Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.22-build22/floaty-0.0.22-ios.ipa",
"size": 24517758,
"localizedDescription": "[main] ## main iOS build"
},
{
"version": "0.0.21",
"buildVersion": "21",
"marketingVersion": "0.0.21 (21)",
"date": "2026-06-03T05:45:36Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.21-build21/floaty-0.0.21-ios.ipa",
"size": 24517762,
"localizedDescription": "[main] ## main iOS build"
},
{
"version": "0.0.20",
"buildVersion": "20",
"marketingVersion": "0.0.20 (20)",
"date": "2026-06-01T13:37:19Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.20-build20/floaty-0.0.20-ios.ipa",
"size": 24544867,
"localizedDescription": "[main] ## main iOS build"
},
{
"version": "0.0.19",
"buildVersion": "19",
"marketingVersion": "0.0.19 (19)",
"date": "2026-06-01T13:30:22Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/main-v0.0.19-build19/floaty-0.0.19-ios.ipa",
"size": 24946293,
"localizedDescription": "[main] ## main iOS build"
},
{
"version": "0.0.17",
"buildVersion": "17",
"marketingVersion": "0.0.17 (17)",
"date": "2026-06-01T12:21:56Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-altstore-duplicate-versions-81e9-v0.0.17-build17/floaty-0.0.17-ios.ipa",
"size": 24940996,
"localizedDescription": "[cursor/fix-altstore-duplicate-versions-81e9] ## cursor/fix-altstore-duplicate-versions-81e9 iOS build"
},
{
"version": "0.0.16",
"buildVersion": "16",
"marketingVersion": "0.0.16 (16)",
"date": "2026-06-01T11:31:59Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-altstore-duplicate-versions-81e9-v0.0.16-build16/floaty-0.0.16-ios.ipa",
"size": 24941003,
"localizedDescription": "[cursor/fix-altstore-duplicate-versions-81e9] ## cursor/fix-altstore-duplicate-versions-81e9 iOS build"
},
{
"version": "0.0.15",
"buildVersion": "15",
"marketingVersion": "0.0.15 (15)",
"date": "2026-06-01T10:36:43Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/altstore-source-github-pages-81e9-v0.0.15-build15/floaty-0.0.15-ios.ipa",
"size": 24941018,
"localizedDescription": "[cursor/altstore-source-github-pages-81e9] ## cursor/altstore-source-github-pages-81e9 iOS build"
},
{
"version": "0.0.14",
"buildVersion": "14",
"marketingVersion": "0.0.14 (14)",
"date": "2026-06-01T09:25:03Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ios-ipa-sidestore-packaging-81e9-v0.0.14-build14/floaty-0.0.14-ios.ipa",
"size": 24464495,
"localizedDescription": "[cursor/fix-ios-ipa-sidestore-packaging-81e9] ## cursor/fix-ios-ipa-sidestore-packaging-81e9 iOS build\r"
},
{
"version": "0.0.13",
"buildVersion": "13",
"marketingVersion": "0.0.13 (13)",
"date": "2026-05-17T18:23:04Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ota-manifest-plist-367d-v0.0.13-build13/floaty-0.0.13-ios.ipa",
"size": 24469024,
"localizedDescription": "[cursor/fix-ota-manifest-plist-367d] ## cursor/fix-ota-manifest-plist-367d iOS build\r"
},
{
"version": "0.0.12",
"buildVersion": "12",
"marketingVersion": "0.0.12 (12)",
"date": "2026-05-17T17:26:18Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ota-manifest-plist-367d-v0.0.12-build12/floaty-0.0.12-ios.ipa",
"size": 24469026,
"localizedDescription": "[cursor/fix-ota-manifest-plist-367d] ## cursor/fix-ota-manifest-plist-367d iOS build"
},
{
"version": "0.0.11",
"buildVersion": "11",
"marketingVersion": "0.0.11 (11)",
"date": "2026-05-17T17:10:22Z",
"downloadURL": "https://github.com/tojemoc/floaty/releases/download/cursor/fix-ios-versioning-ota-6e6e-v0.0.11-build11/floaty-0.0.11-ios.ipa",
"size": 24468788,
"localizedDescription": "[cursor/fix-ios-versioning-ota-6e6e] ## cursor/fix-ios-versioning-ota-6e6e iOS build"
}
]
}
]
}
26 changes: 26 additions & 0 deletions docs/altstore-source.meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "Floaty",
"subtitle": "Open-source Floatplane client for iOS",
"description": "Floaty builds for iOS from GitHub Releases. Includes pre-releases from nightly, beta, and development branches. IPAs are packaged for SideStore and AltStore.",
"iconURL": "https://floaty.fyi/assets/floaty.png",
"website": "https://floaty.fyi",
"tintColor": "#3b82f6",
"featuredApps": ["uk.bw86.floaty"],
"news": [],
"app": {
"name": "Floaty",
"bundleIdentifier": "uk.bw86.floaty",
"developerName": "Floaty",
"subtitle": "Floatplane client for iOS",
"localizedDescription": "An open-source Floatplane client. Install via SideStore or AltStore; pick a build matching your branch (release, beta, nightly, or development).",
"iconURL": "https://floaty.fyi/assets/floaty.png",
"tintColor": "#3b82f6",
"category": "entertainment",
"screenshots": [],
"appPermissions": {
"entitlements": [],
"privacy": {}
},
"patreon": {}
}
}
25 changes: 25 additions & 0 deletions docs/remote-debug-logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Remote debug logging

Floaty can mirror app logs and uncaught Flutter/Dart errors to an external HTTP
endpoint for debugging white-screen or startup issues.

Remote logging is off by default. Enable it at build or run time with Dart
defines:

```sh
flutter run -d linux \
--dart-define=FLOATY_REMOTE_LOG_ENDPOINT=https://example.com/floaty-logs
```

If the endpoint requires bearer auth, also pass:

```sh
--dart-define=FLOATY_REMOTE_LOG_TOKEN=your-token
```

The app sends JSON payloads with a session id, timestamp, platform, level, and
message. The developer logs screen can also upload the currently selected app or
download log view on demand.

Before logs are saved or sent, common authorization, token, and cookie patterns
are redacted.
4 changes: 4 additions & 0 deletions lib/app/flavor_theme.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import 'package:flutter/material.dart';

/// Set during [main] before [runApp]. Used by theme and settings UI.
late final Color? flavorPrimary;
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import 'package:flutter_discord_rpc/flutter_discord_rpc.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:get_it/get_it.dart';

import 'platform_check_stub.dart' if (dart.library.io) 'platform_check_io.dart'
as platform_check;

final discordRPCController = GetIt.I<DiscordRPCController>();
bool get isDiscordRPCSupported => platform_check.isDiscordRPCSupported;

class DiscordRPCController {
bool initialized = false;
Expand Down
3 changes: 3 additions & 0 deletions lib/features/discordrpc/controllers/platform_check_io.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import 'dart:io' show Platform;

bool get isDiscordRPCSupported => Platform.isWindows || Platform.isLinux;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bool get isDiscordRPCSupported => false;
37 changes: 30 additions & 7 deletions lib/features/download/controllers/fp_download_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ import 'package:floaty/features/download/controllers/download_log.dart';
import 'package:floaty/features/download/controllers/fp_download_url_helper.dart';
import 'package:floaty/features/api/models/definitions.dart';

Directory selectOfflineStorageDirectory({
required Directory applicationSupportDirectory,
required bool useExternalStorage,
Directory? externalStorageDirectory,
}) {
if (useExternalStorage && externalStorageDirectory != null) {
return externalStorageDirectory;
}
return applicationSupportDirectory;
}

/// Floatplane Download Service - UI client for the FP download isolate
class FPDownloadService {
static final FPDownloadService _instance = FPDownloadService._internal();
Expand Down Expand Up @@ -57,13 +68,15 @@ class FPDownloadService {

// Setup offline directory - ALWAYS use app's internal storage for offline library
// The custom download_path is only for external downloads (useExternalPath=true)
Directory? directory;
if (Platform.isAndroid || Platform.isIOS) {
directory = await getExternalStorageDirectory();
} else {
directory = await getApplicationSupportDirectory();
}
_offlinePath = p.join(directory?.path ?? '', 'floatplane_offline');
final appSupportDirectory = await getApplicationSupportDirectory();
final externalStorageDirectory =
Platform.isAndroid ? await getExternalStorageDirectory() : null;
final directory = selectOfflineStorageDirectory(
applicationSupportDirectory: appSupportDirectory,
externalStorageDirectory: externalStorageDirectory,
useExternalStorage: Platform.isAndroid,
);
_offlinePath = p.join(directory.path, 'floatplane_offline');
await Directory(_offlinePath!).create(recursive: true);
_logger!.log(
'[FPDownloadService] Offline library path (internal): $_offlinePath');
Expand Down Expand Up @@ -104,6 +117,16 @@ class FPDownloadService {

Future<void> _initNotifications() async {
try {
final dbusSessionBusAddress =
Platform.environment['DBUS_SESSION_BUS_ADDRESS'];
if (Platform.isLinux &&
(dbusSessionBusAddress == null || dbusSessionBusAddress.isEmpty)) {
_logger?.log(
'[FPDownloadService] Skipping notifications; D-Bus session bus is unavailable');
_notificationsInitialized = false;
return;
}

const androidSettings =
AndroidInitializationSettings('@mipmap/ic_launcher');
const iosSettings = DarwinInitializationSettings(
Expand Down
Loading