Merge pull request 'v26.03.12.1' (#3) from dev into main

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
2026-03-12 00:41:40 -04:00
11 changed files with 18 additions and 48 deletions
+3 -35
View File
@@ -1,9 +1,6 @@
# CI runs first; build only proceeds if analyze and test pass.
# CI runs only on release tags.
#
# Push to dev: analyze + test → build APK → upload artifact (fabledapp-dev-<sha>)
# Push to main: analyze + test only (no build — wait for release tag)
# Tag v*: analyze + test → build APK → upload artifact + attach to Forgejo Release
# Pull request: analyze + test only
# Tag v*: analyze + test → build APK → attach to Forgejo Release
#
# To cut a release:
# Create a release via the Forgejo UI on main with a v* tag name.
@@ -19,25 +16,7 @@ name: CI & Build
on:
push:
branches: [main, dev]
tags: ["v*"]
paths:
- "lib/**"
- "test/**"
- "pubspec.yaml"
- "pubspec.lock"
- "analysis_options.yaml"
- "android/**"
- "assets/**"
- ".forgejo/workflows/ci.yml"
pull_request:
paths:
- "lib/**"
- "test/**"
- "pubspec.yaml"
- "pubspec.lock"
- "analysis_options.yaml"
- ".forgejo/workflows/ci.yml"
jobs:
analyze:
@@ -63,12 +42,6 @@ jobs:
build:
name: Build release APK
needs: [analyze]
# Build on dev branch pushes and version tag pushes only.
# main branch pushes run CI for safety but do not build —
# the release tag (v*) is the sole trigger for a production APK.
if: |
github.event_name == 'push' &&
(github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/'))
runs-on: py3.12-node22
container:
image: ghcr.io/cirruslabs/flutter:stable
@@ -87,11 +60,7 @@ jobs:
- name: Set artifact name
id: artifact
run: |
if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then
echo "name=fabledapp-dev-${{ github.sha }}" >> $GITHUB_OUTPUT
else
echo "name=fabledapp-${{ github.sha }}" >> $GITHUB_OUTPUT
fi
echo "name=fabledapp-${{ github.ref_name }}-${{ github.sha }}" >> $GITHUB_OUTPUT
- name: Upload artifact to Forgejo
env:
@@ -107,7 +76,6 @@ jobs:
-F "file=@$APK" || echo "Artifact upload skipped (API may not support this endpoint)."
- name: Publish Forgejo release
if: startsWith(github.ref, 'refs/tags/')
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
TAG: ${{ github.ref_name }}
+1 -1
View File
@@ -371,7 +371,7 @@ class _QuickCaptureBarState extends ConsumerState<_QuickCaptureBar> {
String _hintForLocation(String location) {
if (location.startsWith(Routes.library) &&
location.contains('tasks')) return 'Add a task…';
location.contains('tasks')) { return 'Add a task…'; }
if (location.startsWith(Routes.conversations)) return 'Ask Fabled…';
return 'Capture a note…';
}
+1 -1
View File
@@ -35,7 +35,7 @@ class BriefingApi {
}
}
/// GET /api/briefing/conversations/<id>/messages
/// GET /api/briefing/conversations/`<id>`/messages
Future<List<Message>> getMessages(int convId) async {
try {
final response =
+2 -2
View File
@@ -38,7 +38,7 @@ class NotesApi {
'title': title,
'body': body,
'tags': tags,
if (projectId != null) 'project_id': projectId,
?'project_id': projectId,
});
return Note.fromJson(response.data as Map<String, dynamic>);
} on DioException catch (e) {
@@ -59,7 +59,7 @@ class NotesApi {
'title': title,
'body': body,
'tags': tags,
if (clearProject) 'project_id': null else if (projectId != null) 'project_id': projectId,
if (clearProject) 'project_id': null else ?'project_id': projectId,
});
return Note.fromJson(response.data as Map<String, dynamic>);
} on DioException catch (e) {
+1 -1
View File
@@ -44,7 +44,7 @@ class ProjectsApi {
if (description != null && description.isNotEmpty)
'description': description,
if (goal != null && goal.isNotEmpty) 'goal': goal,
if (color != null) 'color': color,
?'color': color,
});
return Project.fromJson(response.data as Map<String, dynamic>);
} on DioException catch (e) {
+2 -2
View File
@@ -43,8 +43,8 @@ class TasksApi {
'status': status.value,
'priority': priority.value,
'due_date': dueDate?.toIso8601String(),
if (projectId != null) 'project_id': projectId,
if (parentId != null) 'parent_id': parentId,
?'project_id': projectId,
?'parent_id': parentId,
});
return Task.fromJson(response.data as Map<String, dynamic>);
} on DioException catch (e) {
+2 -2
View File
@@ -72,7 +72,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
_usernameController.text.trim(),
_passwordController.text,
);
if (mounted) context.go(Routes.notes);
if (mounted) context.go(Routes.briefing);
} on AuthException catch (e) {
setState(() => _error = e.message);
} on AppException catch (e) {
@@ -90,7 +90,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
cookieJar: ref.read(cookieJarProvider),
onSuccess: () async {
await ref.read(authProvider.notifier).verify();
if (mounted) context.go(Routes.notes);
if (mounted) context.go(Routes.briefing);
},
),
));
+1 -1
View File
@@ -30,7 +30,7 @@ class _SplashScreenState extends ConsumerState<SplashScreen> {
if (!mounted) return;
final status = ref.read(authProvider);
if (status == AuthStatus.authenticated) {
context.go(Routes.notes);
context.go(Routes.briefing);
} else {
context.go(Routes.login);
}
+2 -1
View File
@@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart';
import '../../core/constants.dart';
import '../../core/exceptions.dart';
import '../../data/api/tasks_api.dart';
import '../../data/models/task.dart';
import '../../providers/api_client_provider.dart';
import '../../providers/tasks_provider.dart';
@@ -239,6 +238,7 @@ class _TaskEditScreenState extends ConsumerState<TaskEditScreen> {
),
const SizedBox(height: 16),
DropdownButtonFormField<TaskStatus>(
// ignore: deprecated_member_use
value: _status,
decoration: const InputDecoration(
labelText: 'Status',
@@ -253,6 +253,7 @@ class _TaskEditScreenState extends ConsumerState<TaskEditScreen> {
),
const SizedBox(height: 16),
DropdownButtonFormField<TaskPriority>(
// ignore: deprecated_member_use
value: _priority,
decoration: const InputDecoration(
labelText: 'Priority',
+2 -1
View File
@@ -23,12 +23,13 @@ class ProjectSelector extends ConsumerWidget {
return projectsAsync.when(
loading: () => const LinearProgressIndicator(),
error: (_, __) => const SizedBox.shrink(),
error: (_, _) => const SizedBox.shrink(),
data: (projects) {
final active =
projects.where((p) => p.status == 'active').toList();
return DropdownButtonFormField<int?>(
// ignore: deprecated_member_use
value: value,
decoration: decoration ??
const InputDecoration(
+1 -1
View File
@@ -2,7 +2,7 @@ name: fabled_app
description: "FabledAssistant mobile client for Android."
publish_to: 'none'
version: 26.03.02+1
version: 26.03.12+1
environment:
sdk: ^3.11.0