From 85e616c256dfe48db1cfa62ba19f860c8a63faa6 Mon Sep 17 00:00:00 2001 From: Tristan Michael Date: Tue, 31 Mar 2026 07:02:58 -0700 Subject: [PATCH] feat(flutter): add Rust bridge backend and generated bindings --- Cargo.toml | 1 + apps/flutter/lib/src/rust/api.dart | 195 ++++ apps/flutter/lib/src/rust/frb_generated.dart | 1024 +++++++++++++++++ .../lib/src/rust/frb_generated.io.dart | 190 +++ .../lib/src/rust/frb_generated.web.dart | 190 +++ apps/flutter/rust/Cargo.lock | 6 +- apps/flutter/rust/Cargo.toml | 14 + apps/flutter/rust/src/api.rs | 257 +++++ apps/flutter/rust/src/frb_generated.rs | 1018 ++++++++++++++++ apps/flutter/rust/src/lib.rs | 2 + 10 files changed, 2893 insertions(+), 4 deletions(-) create mode 100644 apps/flutter/lib/src/rust/api.dart create mode 100644 apps/flutter/lib/src/rust/frb_generated.dart create mode 100644 apps/flutter/lib/src/rust/frb_generated.io.dart create mode 100644 apps/flutter/lib/src/rust/frb_generated.web.dart create mode 100644 apps/flutter/rust/Cargo.toml create mode 100644 apps/flutter/rust/src/api.rs create mode 100644 apps/flutter/rust/src/frb_generated.rs create mode 100644 apps/flutter/rust/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 2a318a0..068f1fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ ] exclude = [ "apps/tauri/src-tauri", + "apps/flutter/rust", ] resolver = "2" diff --git a/apps/flutter/lib/src/rust/api.dart b/apps/flutter/lib/src/rust/api.dart new file mode 100644 index 0000000..957f28f --- /dev/null +++ b/apps/flutter/lib/src/rust/api.dart @@ -0,0 +1,195 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +// These functions are ignored because they are not marked as `pub`: `config_to_dto`, `ensure_repo`, `task_to_dto` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `AppState` + +Future getConfig() => RustLib.instance.api.crateApiGetConfig(); + +Future initWorkspace({required String path}) => + RustLib.instance.api.crateApiInitWorkspace(path: path); + +Future addWorkspace({required String name, required String path}) => + RustLib.instance.api.crateApiAddWorkspace(name: name, path: path); + +Future setCurrentWorkspace({required String name}) => + RustLib.instance.api.crateApiSetCurrentWorkspace(name: name); + +Future removeWorkspace({required String name}) => + RustLib.instance.api.crateApiRemoveWorkspace(name: name); + +Future> getLists() => RustLib.instance.api.crateApiGetLists(); + +Future createList({required String name}) => + RustLib.instance.api.crateApiCreateList(name: name); + +Future deleteList({required String listId}) => + RustLib.instance.api.crateApiDeleteList(listId: listId); + +Future> listTasks({required String listId}) => + RustLib.instance.api.crateApiListTasks(listId: listId); + +Future createTask({ + required String listId, + required String title, + required String description, +}) => RustLib.instance.api.crateApiCreateTask( + listId: listId, + title: title, + description: description, +); + +Future updateTask({required String listId, required TaskDto task}) => + RustLib.instance.api.crateApiUpdateTask(listId: listId, task: task); + +Future deleteTask({required String listId, required String taskId}) => + RustLib.instance.api.crateApiDeleteTask(listId: listId, taskId: taskId); + +Future toggleTask({required String listId, required String taskId}) => + RustLib.instance.api.crateApiToggleTask(listId: listId, taskId: taskId); + +Future reorderTask({ + required String listId, + required String taskId, + required int newPosition, +}) => RustLib.instance.api.crateApiReorderTask( + listId: listId, + taskId: taskId, + newPosition: newPosition, +); + +Future greet({required String name}) => + RustLib.instance.api.crateApiGreet(name: name); + +class AppConfigDto { + final List workspaces; + final String? currentWorkspace; + + const AppConfigDto({required this.workspaces, this.currentWorkspace}); + + @override + int get hashCode => workspaces.hashCode ^ currentWorkspace.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AppConfigDto && + runtimeType == other.runtimeType && + workspaces == other.workspaces && + currentWorkspace == other.currentWorkspace; +} + +class TaskDto { + final String id; + final String title; + final String description; + final String status; + final String? dueDate; + final String createdAt; + final String updatedAt; + final String? parentId; + + const TaskDto({ + required this.id, + required this.title, + required this.description, + required this.status, + this.dueDate, + required this.createdAt, + required this.updatedAt, + this.parentId, + }); + + @override + int get hashCode => + id.hashCode ^ + title.hashCode ^ + description.hashCode ^ + status.hashCode ^ + dueDate.hashCode ^ + createdAt.hashCode ^ + updatedAt.hashCode ^ + parentId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TaskDto && + runtimeType == other.runtimeType && + id == other.id && + title == other.title && + description == other.description && + status == other.status && + dueDate == other.dueDate && + createdAt == other.createdAt && + updatedAt == other.updatedAt && + parentId == other.parentId; +} + +class TaskListDto { + final String id; + final String title; + final String createdAt; + final String updatedAt; + final bool groupByDueDate; + + const TaskListDto({ + required this.id, + required this.title, + required this.createdAt, + required this.updatedAt, + required this.groupByDueDate, + }); + + @override + int get hashCode => + id.hashCode ^ + title.hashCode ^ + createdAt.hashCode ^ + updatedAt.hashCode ^ + groupByDueDate.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TaskListDto && + runtimeType == other.runtimeType && + id == other.id && + title == other.title && + createdAt == other.createdAt && + updatedAt == other.updatedAt && + groupByDueDate == other.groupByDueDate; +} + +class WorkspaceEntry { + final String name; + final String path; + final String? webdavUrl; + final String? lastSync; + + const WorkspaceEntry({ + required this.name, + required this.path, + this.webdavUrl, + this.lastSync, + }); + + @override + int get hashCode => + name.hashCode ^ path.hashCode ^ webdavUrl.hashCode ^ lastSync.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is WorkspaceEntry && + runtimeType == other.runtimeType && + name == other.name && + path == other.path && + webdavUrl == other.webdavUrl && + lastSync == other.lastSync; +} diff --git a/apps/flutter/lib/src/rust/frb_generated.dart b/apps/flutter/lib/src/rust/frb_generated.dart new file mode 100644 index 0000000..94a1a28 --- /dev/null +++ b/apps/flutter/lib/src/rust/frb_generated.dart @@ -0,0 +1,1024 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +import 'api.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'frb_generated.dart'; +import 'frb_generated.io.dart' + if (dart.library.js_interop) 'frb_generated.web.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +/// Main entrypoint of the Rust API +class RustLib extends BaseEntrypoint { + @internal + static final instance = RustLib._(); + + RustLib._(); + + /// Initialize flutter_rust_bridge + static Future init({ + RustLibApi? api, + BaseHandler? handler, + ExternalLibrary? externalLibrary, + bool forceSameCodegenVersion = true, + }) async { + await instance.initImpl( + api: api, + handler: handler, + externalLibrary: externalLibrary, + forceSameCodegenVersion: forceSameCodegenVersion, + ); + } + + /// Initialize flutter_rust_bridge in mock mode. + /// No libraries for FFI are loaded. + static void initMock({required RustLibApi api}) { + instance.initMockImpl(api: api); + } + + /// Dispose flutter_rust_bridge + /// + /// The call to this function is optional, since flutter_rust_bridge (and everything else) + /// is automatically disposed when the app stops. + static void dispose() => instance.disposeImpl(); + + @override + ApiImplConstructor get apiImplConstructor => + RustLibApiImpl.new; + + @override + WireConstructor get wireConstructor => + RustLibWire.fromExternalLibrary; + + @override + Future executeRustInitializers() async {} + + @override + ExternalLibraryLoaderConfig get defaultExternalLibraryLoaderConfig => + kDefaultExternalLibraryLoaderConfig; + + @override + String get codegenVersion => '2.11.1'; + + @override + int get rustContentHash => 1511441297; + + static const kDefaultExternalLibraryLoaderConfig = + ExternalLibraryLoaderConfig( + stem: 'bevy_tasks_flutter', + ioDirectory: 'rust/target/release/', + webPrefix: 'pkg/', + ); +} + +abstract class RustLibApi extends BaseApi { + Future crateApiAddWorkspace({ + required String name, + required String path, + }); + + Future crateApiCreateList({required String name}); + + Future crateApiCreateTask({ + required String listId, + required String title, + required String description, + }); + + Future crateApiDeleteList({required String listId}); + + Future crateApiDeleteTask({ + required String listId, + required String taskId, + }); + + Future crateApiGetConfig(); + + Future> crateApiGetLists(); + + Future crateApiGreet({required String name}); + + Future crateApiInitWorkspace({required String path}); + + Future> crateApiListTasks({required String listId}); + + Future crateApiRemoveWorkspace({required String name}); + + Future crateApiReorderTask({ + required String listId, + required String taskId, + required int newPosition, + }); + + Future crateApiSetCurrentWorkspace({required String name}); + + Future crateApiToggleTask({ + required String listId, + required String taskId, + }); + + Future crateApiUpdateTask({ + required String listId, + required TaskDto task, + }); +} + +class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { + RustLibApiImpl({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @override + Future crateApiAddWorkspace({ + required String name, + required String path, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(name, serializer); + sse_encode_String(path, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 1, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiAddWorkspaceConstMeta, + argValues: [name, path], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiAddWorkspaceConstMeta => const TaskConstMeta( + debugName: "add_workspace", + argNames: ["name", "path"], + ); + + @override + Future crateApiCreateList({required String name}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(name, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 2, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_task_list_dto, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiCreateListConstMeta, + argValues: [name], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiCreateListConstMeta => + const TaskConstMeta(debugName: "create_list", argNames: ["name"]); + + @override + Future crateApiCreateTask({ + required String listId, + required String title, + required String description, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + sse_encode_String(title, serializer); + sse_encode_String(description, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 3, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_task_dto, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiCreateTaskConstMeta, + argValues: [listId, title, description], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiCreateTaskConstMeta => const TaskConstMeta( + debugName: "create_task", + argNames: ["listId", "title", "description"], + ); + + @override + Future crateApiDeleteList({required String listId}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 4, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiDeleteListConstMeta, + argValues: [listId], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiDeleteListConstMeta => + const TaskConstMeta(debugName: "delete_list", argNames: ["listId"]); + + @override + Future crateApiDeleteTask({ + required String listId, + required String taskId, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + sse_encode_String(taskId, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 5, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiDeleteTaskConstMeta, + argValues: [listId, taskId], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiDeleteTaskConstMeta => const TaskConstMeta( + debugName: "delete_task", + argNames: ["listId", "taskId"], + ); + + @override + Future crateApiGetConfig() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 6, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_app_config_dto, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiGetConfigConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiGetConfigConstMeta => + const TaskConstMeta(debugName: "get_config", argNames: []); + + @override + Future> crateApiGetLists() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 7, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_task_list_dto, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiGetListsConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiGetListsConstMeta => + const TaskConstMeta(debugName: "get_lists", argNames: []); + + @override + Future crateApiGreet({required String name}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(name, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 8, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiGreetConstMeta, + argValues: [name], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiGreetConstMeta => + const TaskConstMeta(debugName: "greet", argNames: ["name"]); + + @override + Future crateApiInitWorkspace({required String path}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(path, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 9, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiInitWorkspaceConstMeta, + argValues: [path], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiInitWorkspaceConstMeta => + const TaskConstMeta(debugName: "init_workspace", argNames: ["path"]); + + @override + Future> crateApiListTasks({required String listId}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 10, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_task_dto, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiListTasksConstMeta, + argValues: [listId], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiListTasksConstMeta => + const TaskConstMeta(debugName: "list_tasks", argNames: ["listId"]); + + @override + Future crateApiRemoveWorkspace({required String name}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(name, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 11, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiRemoveWorkspaceConstMeta, + argValues: [name], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiRemoveWorkspaceConstMeta => + const TaskConstMeta(debugName: "remove_workspace", argNames: ["name"]); + + @override + Future crateApiReorderTask({ + required String listId, + required String taskId, + required int newPosition, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + sse_encode_String(taskId, serializer); + sse_encode_u_32(newPosition, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 12, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiReorderTaskConstMeta, + argValues: [listId, taskId, newPosition], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiReorderTaskConstMeta => const TaskConstMeta( + debugName: "reorder_task", + argNames: ["listId", "taskId", "newPosition"], + ); + + @override + Future crateApiSetCurrentWorkspace({required String name}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(name, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 13, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiSetCurrentWorkspaceConstMeta, + argValues: [name], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiSetCurrentWorkspaceConstMeta => + const TaskConstMeta( + debugName: "set_current_workspace", + argNames: ["name"], + ); + + @override + Future crateApiToggleTask({ + required String listId, + required String taskId, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + sse_encode_String(taskId, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 14, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_task_dto, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiToggleTaskConstMeta, + argValues: [listId, taskId], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiToggleTaskConstMeta => const TaskConstMeta( + debugName: "toggle_task", + argNames: ["listId", "taskId"], + ); + + @override + Future crateApiUpdateTask({ + required String listId, + required TaskDto task, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(listId, serializer); + sse_encode_box_autoadd_task_dto(task, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 15, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiUpdateTaskConstMeta, + argValues: [listId, task], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiUpdateTaskConstMeta => const TaskConstMeta( + debugName: "update_task", + argNames: ["listId", "task"], + ); + + @protected + String dco_decode_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as String; + } + + @protected + AppConfigDto dco_decode_app_config_dto(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 2) + throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); + return AppConfigDto( + workspaces: dco_decode_list_workspace_entry(arr[0]), + currentWorkspace: dco_decode_opt_String(arr[1]), + ); + } + + @protected + bool dco_decode_bool(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as bool; + } + + @protected + TaskDto dco_decode_box_autoadd_task_dto(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dco_decode_task_dto(raw); + } + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as Uint8List; + } + + @protected + List dco_decode_list_task_dto(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_task_dto).toList(); + } + + @protected + List dco_decode_list_task_list_dto(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_task_list_dto).toList(); + } + + @protected + List dco_decode_list_workspace_entry(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_workspace_entry).toList(); + } + + @protected + String? dco_decode_opt_String(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_String(raw); + } + + @protected + TaskDto dco_decode_task_dto(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 8) + throw Exception('unexpected arr length: expect 8 but see ${arr.length}'); + return TaskDto( + id: dco_decode_String(arr[0]), + title: dco_decode_String(arr[1]), + description: dco_decode_String(arr[2]), + status: dco_decode_String(arr[3]), + dueDate: dco_decode_opt_String(arr[4]), + createdAt: dco_decode_String(arr[5]), + updatedAt: dco_decode_String(arr[6]), + parentId: dco_decode_opt_String(arr[7]), + ); + } + + @protected + TaskListDto dco_decode_task_list_dto(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 5) + throw Exception('unexpected arr length: expect 5 but see ${arr.length}'); + return TaskListDto( + id: dco_decode_String(arr[0]), + title: dco_decode_String(arr[1]), + createdAt: dco_decode_String(arr[2]), + updatedAt: dco_decode_String(arr[3]), + groupByDueDate: dco_decode_bool(arr[4]), + ); + } + + @protected + int dco_decode_u_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + int dco_decode_u_8(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as int; + } + + @protected + void dco_decode_unit(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return; + } + + @protected + WorkspaceEntry dco_decode_workspace_entry(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 4) + throw Exception('unexpected arr length: expect 4 but see ${arr.length}'); + return WorkspaceEntry( + name: dco_decode_String(arr[0]), + path: dco_decode_String(arr[1]), + webdavUrl: dco_decode_opt_String(arr[2]), + lastSync: dco_decode_opt_String(arr[3]), + ); + } + + @protected + String sse_decode_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var inner = sse_decode_list_prim_u_8_strict(deserializer); + return utf8.decoder.convert(inner); + } + + @protected + AppConfigDto sse_decode_app_config_dto(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_workspaces = sse_decode_list_workspace_entry(deserializer); + var var_currentWorkspace = sse_decode_opt_String(deserializer); + return AppConfigDto( + workspaces: var_workspaces, + currentWorkspace: var_currentWorkspace, + ); + } + + @protected + bool sse_decode_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8() != 0; + } + + @protected + TaskDto sse_decode_box_autoadd_task_dto(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return (sse_decode_task_dto(deserializer)); + } + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var len_ = sse_decode_i_32(deserializer); + return deserializer.buffer.getUint8List(len_); + } + + @protected + List sse_decode_list_task_dto(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + var len_ = sse_decode_i_32(deserializer); + var ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_task_dto(deserializer)); + } + return ans_; + } + + @protected + List sse_decode_list_task_list_dto( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + var len_ = sse_decode_i_32(deserializer); + var ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_task_list_dto(deserializer)); + } + return ans_; + } + + @protected + List sse_decode_list_workspace_entry( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + var len_ = sse_decode_i_32(deserializer); + var ans_ = []; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_workspace_entry(deserializer)); + } + return ans_; + } + + @protected + String? sse_decode_opt_String(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return (sse_decode_String(deserializer)); + } else { + return null; + } + } + + @protected + TaskDto sse_decode_task_dto(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_id = sse_decode_String(deserializer); + var var_title = sse_decode_String(deserializer); + var var_description = sse_decode_String(deserializer); + var var_status = sse_decode_String(deserializer); + var var_dueDate = sse_decode_opt_String(deserializer); + var var_createdAt = sse_decode_String(deserializer); + var var_updatedAt = sse_decode_String(deserializer); + var var_parentId = sse_decode_opt_String(deserializer); + return TaskDto( + id: var_id, + title: var_title, + description: var_description, + status: var_status, + dueDate: var_dueDate, + createdAt: var_createdAt, + updatedAt: var_updatedAt, + parentId: var_parentId, + ); + } + + @protected + TaskListDto sse_decode_task_list_dto(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_id = sse_decode_String(deserializer); + var var_title = sse_decode_String(deserializer); + var var_createdAt = sse_decode_String(deserializer); + var var_updatedAt = sse_decode_String(deserializer); + var var_groupByDueDate = sse_decode_bool(deserializer); + return TaskListDto( + id: var_id, + title: var_title, + createdAt: var_createdAt, + updatedAt: var_updatedAt, + groupByDueDate: var_groupByDueDate, + ); + } + + @protected + int sse_decode_u_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint32(); + } + + @protected + int sse_decode_u_8(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getUint8(); + } + + @protected + void sse_decode_unit(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + WorkspaceEntry sse_decode_workspace_entry(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_name = sse_decode_String(deserializer); + var var_path = sse_decode_String(deserializer); + var var_webdavUrl = sse_decode_opt_String(deserializer); + var var_lastSync = sse_decode_opt_String(deserializer); + return WorkspaceEntry( + name: var_name, + path: var_path, + webdavUrl: var_webdavUrl, + lastSync: var_lastSync, + ); + } + + @protected + int sse_decode_i_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getInt32(); + } + + @protected + void sse_encode_String(String self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); + } + + @protected + void sse_encode_app_config_dto(AppConfigDto self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_workspace_entry(self.workspaces, serializer); + sse_encode_opt_String(self.currentWorkspace, serializer); + } + + @protected + void sse_encode_bool(bool self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self ? 1 : 0); + } + + @protected + void sse_encode_box_autoadd_task_dto(TaskDto self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_task_dto(self, serializer); + } + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + serializer.buffer.putUint8List(self); + } + + @protected + void sse_encode_list_task_dto(List self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_task_dto(item, serializer); + } + } + + @protected + void sse_encode_list_task_list_dto( + List self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_task_list_dto(item, serializer); + } + } + + @protected + void sse_encode_list_workspace_entry( + List self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_workspace_entry(item, serializer); + } + } + + @protected + void sse_encode_opt_String(String? self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_String(self, serializer); + } + } + + @protected + void sse_encode_task_dto(TaskDto self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.id, serializer); + sse_encode_String(self.title, serializer); + sse_encode_String(self.description, serializer); + sse_encode_String(self.status, serializer); + sse_encode_opt_String(self.dueDate, serializer); + sse_encode_String(self.createdAt, serializer); + sse_encode_String(self.updatedAt, serializer); + sse_encode_opt_String(self.parentId, serializer); + } + + @protected + void sse_encode_task_list_dto(TaskListDto self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.id, serializer); + sse_encode_String(self.title, serializer); + sse_encode_String(self.createdAt, serializer); + sse_encode_String(self.updatedAt, serializer); + sse_encode_bool(self.groupByDueDate, serializer); + } + + @protected + void sse_encode_u_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint32(self); + } + + @protected + void sse_encode_u_8(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putUint8(self); + } + + @protected + void sse_encode_unit(void self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + } + + @protected + void sse_encode_workspace_entry( + WorkspaceEntry self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.name, serializer); + sse_encode_String(self.path, serializer); + sse_encode_opt_String(self.webdavUrl, serializer); + sse_encode_opt_String(self.lastSync, serializer); + } + + @protected + void sse_encode_i_32(int self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putInt32(self); + } +} diff --git a/apps/flutter/lib/src/rust/frb_generated.io.dart b/apps/flutter/lib/src/rust/frb_generated.io.dart new file mode 100644 index 0000000..fdc7102 --- /dev/null +++ b/apps/flutter/lib/src/rust/frb_generated.io.dart @@ -0,0 +1,190 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +import 'api.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi' as ffi; +import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; + +abstract class RustLibApiImplPlatform extends BaseApiImpl { + RustLibApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @protected + String dco_decode_String(dynamic raw); + + @protected + AppConfigDto dco_decode_app_config_dto(dynamic raw); + + @protected + bool dco_decode_bool(dynamic raw); + + @protected + TaskDto dco_decode_box_autoadd_task_dto(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + List dco_decode_list_task_dto(dynamic raw); + + @protected + List dco_decode_list_task_list_dto(dynamic raw); + + @protected + List dco_decode_list_workspace_entry(dynamic raw); + + @protected + String? dco_decode_opt_String(dynamic raw); + + @protected + TaskDto dco_decode_task_dto(dynamic raw); + + @protected + TaskListDto dco_decode_task_list_dto(dynamic raw); + + @protected + int dco_decode_u_32(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + WorkspaceEntry dco_decode_workspace_entry(dynamic raw); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + AppConfigDto sse_decode_app_config_dto(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + TaskDto sse_decode_box_autoadd_task_dto(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + List sse_decode_list_task_dto(SseDeserializer deserializer); + + @protected + List sse_decode_list_task_list_dto(SseDeserializer deserializer); + + @protected + List sse_decode_list_workspace_entry( + SseDeserializer deserializer, + ); + + @protected + String? sse_decode_opt_String(SseDeserializer deserializer); + + @protected + TaskDto sse_decode_task_dto(SseDeserializer deserializer); + + @protected + TaskListDto sse_decode_task_list_dto(SseDeserializer deserializer); + + @protected + int sse_decode_u_32(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + WorkspaceEntry sse_decode_workspace_entry(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_app_config_dto(AppConfigDto self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); + + @protected + void sse_encode_box_autoadd_task_dto(TaskDto self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_task_dto(List self, SseSerializer serializer); + + @protected + void sse_encode_list_task_list_dto( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_workspace_entry( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_opt_String(String? self, SseSerializer serializer); + + @protected + void sse_encode_task_dto(TaskDto self, SseSerializer serializer); + + @protected + void sse_encode_task_list_dto(TaskListDto self, SseSerializer serializer); + + @protected + void sse_encode_u_32(int self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_workspace_entry( + WorkspaceEntry self, + SseSerializer serializer, + ); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); +} + +// Section: wire_class + +class RustLibWire implements BaseWire { + factory RustLibWire.fromExternalLibrary(ExternalLibrary lib) => + RustLibWire(lib.ffiDynamicLibrary); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + RustLibWire(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; +} diff --git a/apps/flutter/lib/src/rust/frb_generated.web.dart b/apps/flutter/lib/src/rust/frb_generated.web.dart new file mode 100644 index 0000000..19a95b9 --- /dev/null +++ b/apps/flutter/lib/src/rust/frb_generated.web.dart @@ -0,0 +1,190 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field + +// Static analysis wrongly picks the IO variant, thus ignore this +// ignore_for_file: argument_type_not_assignable + +import 'api.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; + +abstract class RustLibApiImplPlatform extends BaseApiImpl { + RustLibApiImplPlatform({ + required super.handler, + required super.wire, + required super.generalizedFrbRustBinding, + required super.portManager, + }); + + @protected + String dco_decode_String(dynamic raw); + + @protected + AppConfigDto dco_decode_app_config_dto(dynamic raw); + + @protected + bool dco_decode_bool(dynamic raw); + + @protected + TaskDto dco_decode_box_autoadd_task_dto(dynamic raw); + + @protected + Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); + + @protected + List dco_decode_list_task_dto(dynamic raw); + + @protected + List dco_decode_list_task_list_dto(dynamic raw); + + @protected + List dco_decode_list_workspace_entry(dynamic raw); + + @protected + String? dco_decode_opt_String(dynamic raw); + + @protected + TaskDto dco_decode_task_dto(dynamic raw); + + @protected + TaskListDto dco_decode_task_list_dto(dynamic raw); + + @protected + int dco_decode_u_32(dynamic raw); + + @protected + int dco_decode_u_8(dynamic raw); + + @protected + void dco_decode_unit(dynamic raw); + + @protected + WorkspaceEntry dco_decode_workspace_entry(dynamic raw); + + @protected + String sse_decode_String(SseDeserializer deserializer); + + @protected + AppConfigDto sse_decode_app_config_dto(SseDeserializer deserializer); + + @protected + bool sse_decode_bool(SseDeserializer deserializer); + + @protected + TaskDto sse_decode_box_autoadd_task_dto(SseDeserializer deserializer); + + @protected + Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); + + @protected + List sse_decode_list_task_dto(SseDeserializer deserializer); + + @protected + List sse_decode_list_task_list_dto(SseDeserializer deserializer); + + @protected + List sse_decode_list_workspace_entry( + SseDeserializer deserializer, + ); + + @protected + String? sse_decode_opt_String(SseDeserializer deserializer); + + @protected + TaskDto sse_decode_task_dto(SseDeserializer deserializer); + + @protected + TaskListDto sse_decode_task_list_dto(SseDeserializer deserializer); + + @protected + int sse_decode_u_32(SseDeserializer deserializer); + + @protected + int sse_decode_u_8(SseDeserializer deserializer); + + @protected + void sse_decode_unit(SseDeserializer deserializer); + + @protected + WorkspaceEntry sse_decode_workspace_entry(SseDeserializer deserializer); + + @protected + int sse_decode_i_32(SseDeserializer deserializer); + + @protected + void sse_encode_String(String self, SseSerializer serializer); + + @protected + void sse_encode_app_config_dto(AppConfigDto self, SseSerializer serializer); + + @protected + void sse_encode_bool(bool self, SseSerializer serializer); + + @protected + void sse_encode_box_autoadd_task_dto(TaskDto self, SseSerializer serializer); + + @protected + void sse_encode_list_prim_u_8_strict( + Uint8List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_task_dto(List self, SseSerializer serializer); + + @protected + void sse_encode_list_task_list_dto( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_list_workspace_entry( + List self, + SseSerializer serializer, + ); + + @protected + void sse_encode_opt_String(String? self, SseSerializer serializer); + + @protected + void sse_encode_task_dto(TaskDto self, SseSerializer serializer); + + @protected + void sse_encode_task_list_dto(TaskListDto self, SseSerializer serializer); + + @protected + void sse_encode_u_32(int self, SseSerializer serializer); + + @protected + void sse_encode_u_8(int self, SseSerializer serializer); + + @protected + void sse_encode_unit(void self, SseSerializer serializer); + + @protected + void sse_encode_workspace_entry( + WorkspaceEntry self, + SseSerializer serializer, + ); + + @protected + void sse_encode_i_32(int self, SseSerializer serializer); +} + +// Section: wire_class + +class RustLibWire implements BaseWire { + RustLibWire.fromExternalLibrary(ExternalLibrary lib); +} + +@JS('wasm_bindgen') +external RustLibWasmModule get wasmModule; + +@JS() +@anonymous +extension type RustLibWasmModule._(JSObject _) implements JSObject {} diff --git a/apps/flutter/rust/Cargo.lock b/apps/flutter/rust/Cargo.lock index 08f76e0..cd7a59c 100644 --- a/apps/flutter/rust/Cargo.lock +++ b/apps/flutter/rust/Cargo.lock @@ -126,15 +126,13 @@ dependencies = [ ] [[package]] -name = "bevy-tasks-flutter-bridge" +name = "bevy-tasks-flutter" version = "0.1.0" dependencies = [ "bevy-tasks-core", "chrono", "flutter_rust_bridge", - "serde", - "serde_json", - "tokio", + "once_cell", "uuid", ] diff --git a/apps/flutter/rust/Cargo.toml b/apps/flutter/rust/Cargo.toml new file mode 100644 index 0000000..4b60646 --- /dev/null +++ b/apps/flutter/rust/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bevy-tasks-flutter" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "staticlib"] + +[dependencies] +flutter_rust_bridge = "=2.11.1" +bevy-tasks-core = { path = "../../../crates/bevy-tasks-core" } +uuid = { version = "1", features = ["serde", "v4"] } +chrono = { version = "0.4", features = ["serde"] } +once_cell = "1" diff --git a/apps/flutter/rust/src/api.rs b/apps/flutter/rust/src/api.rs new file mode 100644 index 0000000..ea22a54 --- /dev/null +++ b/apps/flutter/rust/src/api.rs @@ -0,0 +1,257 @@ +use std::path::PathBuf; +use std::sync::Mutex; + +use once_cell::sync::Lazy; +use uuid::Uuid; + +use bevy_tasks_core::{ + config::{AppConfig, WorkspaceConfig}, + models::{Task, TaskList, TaskStatus}, + repository::TaskRepository, +}; + +// ── State ─────────────────────────────────────────────────────────── + +struct AppState { + config: AppConfig, + repo: Option, +} + +static STATE: Lazy> = Lazy::new(|| { + let config_path = AppConfig::get_config_path(); + let config = AppConfig::load_from_file(&config_path).unwrap_or_default(); + Mutex::new(AppState { config, repo: None }) +}); + +fn ensure_repo(state: &mut AppState) -> Result<(), String> { + if state.repo.is_some() { + return Ok(()); + } + let (_name, ws) = state.config.get_current_workspace().map_err(|e| e.to_string())?; + let repo = TaskRepository::new(ws.path.clone()).map_err(|e| e.to_string())?; + state.repo = Some(repo); + Ok(()) +} + +// ── DTOs ──────────────────────────────────────────────────────────── + +pub struct TaskDto { + pub id: String, + pub title: String, + pub description: String, + pub status: String, + pub due_date: Option, + pub created_at: String, + pub updated_at: String, + pub parent_id: Option, +} + +pub struct TaskListDto { + pub id: String, + pub title: String, + pub created_at: String, + pub updated_at: String, + pub group_by_due_date: bool, +} + +pub struct WorkspaceEntry { + pub name: String, + pub path: String, + pub webdav_url: Option, + pub last_sync: Option, +} + +pub struct AppConfigDto { + pub workspaces: Vec, + pub current_workspace: Option, +} + +fn task_to_dto(t: &Task) -> TaskDto { + TaskDto { + id: t.id.to_string(), + title: t.title.clone(), + description: t.description.clone(), + status: match t.status { + TaskStatus::Backlog => "backlog".into(), + TaskStatus::Completed => "completed".into(), + }, + due_date: t.due_date.map(|d| d.to_rfc3339()), + created_at: t.created_at.to_rfc3339(), + updated_at: t.updated_at.to_rfc3339(), + parent_id: t.parent_id.map(|id| id.to_string()), + } +} + +fn config_to_dto(c: &AppConfig) -> AppConfigDto { + AppConfigDto { + workspaces: c + .workspaces + .iter() + .map(|(name, ws)| WorkspaceEntry { + name: name.clone(), + path: ws.path.to_string_lossy().into_owned(), + webdav_url: ws.webdav_url.clone(), + last_sync: ws.last_sync.map(|d| d.to_rfc3339()), + }) + .collect(), + current_workspace: c.current_workspace.clone(), + } +} + +// ── Config commands ───────────────────────────────────────────────── + +pub fn get_config() -> Result { + let s = STATE.lock().unwrap(); + Ok(config_to_dto(&s.config)) +} + +pub fn init_workspace(path: String) -> Result<(), String> { + TaskRepository::init(PathBuf::from(path)) + .map(|_| ()) + .map_err(|e| e.to_string()) +} + +pub fn add_workspace(name: String, path: String) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + let ws = WorkspaceConfig::new(PathBuf::from(&path)); + s.config.add_workspace(name.clone(), ws); + s.config.set_current_workspace(name).map_err(|e| e.to_string())?; + s.repo = None; + let config_path = AppConfig::get_config_path(); + s.config.save_to_file(&config_path).map_err(|e| e.to_string()) +} + +pub fn set_current_workspace(name: String) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + s.config.set_current_workspace(name).map_err(|e| e.to_string())?; + s.repo = None; + let config_path = AppConfig::get_config_path(); + s.config.save_to_file(&config_path).map_err(|e| e.to_string()) +} + +pub fn remove_workspace(name: String) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + s.config.remove_workspace(&name); + s.repo = None; + let config_path = AppConfig::get_config_path(); + s.config.save_to_file(&config_path).map_err(|e| e.to_string()) +} + +// ── List commands ─────────────────────────────────────────────────── + +pub fn get_lists() -> Result, String> { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let lists = s.repo.as_ref().unwrap().get_lists().map_err(|e| e.to_string())?; + Ok(lists + .iter() + .map(|l| TaskListDto { + id: l.id.to_string(), + title: l.title.clone(), + created_at: l.created_at.to_rfc3339(), + updated_at: l.updated_at.to_rfc3339(), + group_by_due_date: l.group_by_due_date, + }) + .collect()) +} + +pub fn create_list(name: String) -> Result { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let list = s.repo.as_mut().unwrap().create_list(name).map_err(|e| e.to_string())?; + Ok(TaskListDto { + id: list.id.to_string(), + title: list.title.clone(), + created_at: list.created_at.to_rfc3339(), + updated_at: list.updated_at.to_rfc3339(), + group_by_due_date: list.group_by_due_date, + }) +} + +pub fn delete_list(list_id: String) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let id = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + s.repo.as_mut().unwrap().delete_list(id).map_err(|e| e.to_string()) +} + +// ── Task commands ─────────────────────────────────────────────────── + +pub fn list_tasks(list_id: String) -> Result, String> { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let id = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + let tasks = s.repo.as_ref().unwrap().list_tasks(id).map_err(|e| e.to_string())?; + Ok(tasks.iter().map(|t| task_to_dto(t)).collect()) +} + +pub fn create_task(list_id: String, title: String, description: String) -> Result { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let id = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + let mut task = Task::new(title); + if !description.is_empty() { + task.description = description; + } + let created = s.repo.as_mut().unwrap().create_task(id, task).map_err(|e| e.to_string())?; + Ok(task_to_dto(&created)) +} + +pub fn update_task(list_id: String, task: TaskDto) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let lid = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + let tid = Uuid::parse_str(&task.id).map_err(|e| e.to_string())?; + + let mut existing = s.repo.as_ref().unwrap().get_task(lid, tid).map_err(|e| e.to_string())?; + existing.title = task.title; + existing.description = task.description; + existing.due_date = task + .due_date + .as_deref() + .and_then(|d| chrono::DateTime::parse_from_rfc3339(d).ok()) + .map(|d| d.with_timezone(&chrono::Utc)); + + s.repo.as_mut().unwrap().update_task(lid, existing).map_err(|e| e.to_string()) +} + +pub fn delete_task(list_id: String, task_id: String) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let lid = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + let tid = Uuid::parse_str(&task_id).map_err(|e| e.to_string())?; + s.repo.as_mut().unwrap().delete_task(lid, tid).map_err(|e| e.to_string()) +} + +pub fn toggle_task(list_id: String, task_id: String) -> Result { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let lid = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + let tid = Uuid::parse_str(&task_id).map_err(|e| e.to_string())?; + let repo = s.repo.as_mut().unwrap(); + let mut task = repo.get_task(lid, tid).map_err(|e| e.to_string())?; + match task.status { + TaskStatus::Backlog => task.complete(), + TaskStatus::Completed => task.uncomplete(), + } + repo.update_task(lid, task.clone()).map_err(|e| e.to_string())?; + Ok(task_to_dto(&task)) +} + +pub fn reorder_task(list_id: String, task_id: String, new_position: u32) -> Result<(), String> { + let mut s = STATE.lock().unwrap(); + ensure_repo(&mut s)?; + let lid = Uuid::parse_str(&list_id).map_err(|e| e.to_string())?; + let tid = Uuid::parse_str(&task_id).map_err(|e| e.to_string())?; + s.repo + .as_mut() + .unwrap() + .reorder_task(lid, tid, new_position as usize) + .map_err(|e| e.to_string()) +} + +// ── Test function ─────────────────────────────────────────────────── + +pub fn greet(name: String) -> String { + format!("Hello, {name}! From Rust via flutter_rust_bridge.") +} diff --git a/apps/flutter/rust/src/frb_generated.rs b/apps/flutter/rust/src/frb_generated.rs new file mode 100644 index 0000000..15d71c3 --- /dev/null +++ b/apps/flutter/rust/src/frb_generated.rs @@ -0,0 +1,1018 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +#![allow( + non_camel_case_types, + unused, + non_snake_case, + clippy::needless_return, + clippy::redundant_closure_call, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::unused_unit, + clippy::double_parens, + clippy::let_and_return, + clippy::too_many_arguments, + clippy::match_single_binding, + clippy::clone_on_copy, + clippy::let_unit_value, + clippy::deref_addrof, + clippy::explicit_auto_deref, + clippy::borrow_deref_ref, + clippy::needless_borrow +)] + +// Section: imports + +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; +use flutter_rust_bridge::{Handler, IntoIntoDart}; + +// Section: boilerplate + +flutter_rust_bridge::frb_generated_boilerplate!( + default_stream_sink_codec = SseCodec, + default_rust_opaque = RustOpaqueMoi, + default_rust_auto_opaque = RustAutoOpaqueMoi, +); +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1"; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1511441297; + +// Section: executor + +flutter_rust_bridge::frb_generated_default_handler!(); + +// Section: wire_funcs + +fn wire__crate__api__add_workspace_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "add_workspace", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_name = ::sse_decode(&mut deserializer); + let api_path = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::add_workspace(api_name, api_path)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__create_list_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "create_list", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_name = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::create_list(api_name)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__create_task_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "create_task", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + let api_title = ::sse_decode(&mut deserializer); + let api_description = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = + crate::api::create_task(api_list_id, api_title, api_description)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__delete_list_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "delete_list", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::delete_list(api_list_id)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__delete_task_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "delete_task", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + let api_task_id = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::delete_task(api_list_id, api_task_id)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__get_config_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_config", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::get_config()?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__get_lists_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_lists", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::get_lists()?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__greet_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "greet", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_name = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::greet(api_name))?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__init_workspace_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "init_workspace", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_path = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::init_workspace(api_path)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__list_tasks_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "list_tasks", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::list_tasks(api_list_id)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__remove_workspace_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "remove_workspace", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_name = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::remove_workspace(api_name)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__reorder_task_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "reorder_task", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + let api_task_id = ::sse_decode(&mut deserializer); + let api_new_position = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = + crate::api::reorder_task(api_list_id, api_task_id, api_new_position)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__set_current_workspace_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "set_current_workspace", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_name = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::set_current_workspace(api_name)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__toggle_task_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "toggle_task", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + let api_task_id = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::toggle_task(api_list_id, api_task_id)?; + Ok(output_ok) + })()) + } + }, + ) +} +fn wire__crate__api__update_task_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "update_task", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_list_id = ::sse_decode(&mut deserializer); + let api_task = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::update_task(api_list_id, api_task)?; + Ok(output_ok) + })()) + } + }, + ) +} + +// Section: dart2rust + +impl SseDecode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = >::sse_decode(deserializer); + return String::from_utf8(inner).unwrap(); + } +} + +impl SseDecode for crate::api::AppConfigDto { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_workspaces = >::sse_decode(deserializer); + let mut var_currentWorkspace = >::sse_decode(deserializer); + return crate::api::AppConfigDto { + workspaces: var_workspaces, + current_workspace: var_currentWorkspace, + }; + } +} + +impl SseDecode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() != 0 + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(::sse_decode(deserializer)); + } else { + return None; + } + } +} + +impl SseDecode for crate::api::TaskDto { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_id = ::sse_decode(deserializer); + let mut var_title = ::sse_decode(deserializer); + let mut var_description = ::sse_decode(deserializer); + let mut var_status = ::sse_decode(deserializer); + let mut var_dueDate = >::sse_decode(deserializer); + let mut var_createdAt = ::sse_decode(deserializer); + let mut var_updatedAt = ::sse_decode(deserializer); + let mut var_parentId = >::sse_decode(deserializer); + return crate::api::TaskDto { + id: var_id, + title: var_title, + description: var_description, + status: var_status, + due_date: var_dueDate, + created_at: var_createdAt, + updated_at: var_updatedAt, + parent_id: var_parentId, + }; + } +} + +impl SseDecode for crate::api::TaskListDto { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_id = ::sse_decode(deserializer); + let mut var_title = ::sse_decode(deserializer); + let mut var_createdAt = ::sse_decode(deserializer); + let mut var_updatedAt = ::sse_decode(deserializer); + let mut var_groupByDueDate = ::sse_decode(deserializer); + return crate::api::TaskListDto { + id: var_id, + title: var_title, + created_at: var_createdAt, + updated_at: var_updatedAt, + group_by_due_date: var_groupByDueDate, + }; + } +} + +impl SseDecode for u32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u32::().unwrap() + } +} + +impl SseDecode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() + } +} + +impl SseDecode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} +} + +impl SseDecode for crate::api::WorkspaceEntry { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_name = ::sse_decode(deserializer); + let mut var_path = ::sse_decode(deserializer); + let mut var_webdavUrl = >::sse_decode(deserializer); + let mut var_lastSync = >::sse_decode(deserializer); + return crate::api::WorkspaceEntry { + name: var_name, + path: var_path, + webdav_url: var_webdavUrl, + last_sync: var_lastSync, + }; + } +} + +impl SseDecode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i32::().unwrap() + } +} + +fn pde_ffi_dispatcher_primary_impl( + func_id: i32, + port: flutter_rust_bridge::for_generated::MessagePort, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + 1 => wire__crate__api__add_workspace_impl(port, ptr, rust_vec_len, data_len), + 2 => wire__crate__api__create_list_impl(port, ptr, rust_vec_len, data_len), + 3 => wire__crate__api__create_task_impl(port, ptr, rust_vec_len, data_len), + 4 => wire__crate__api__delete_list_impl(port, ptr, rust_vec_len, data_len), + 5 => wire__crate__api__delete_task_impl(port, ptr, rust_vec_len, data_len), + 6 => wire__crate__api__get_config_impl(port, ptr, rust_vec_len, data_len), + 7 => wire__crate__api__get_lists_impl(port, ptr, rust_vec_len, data_len), + 8 => wire__crate__api__greet_impl(port, ptr, rust_vec_len, data_len), + 9 => wire__crate__api__init_workspace_impl(port, ptr, rust_vec_len, data_len), + 10 => wire__crate__api__list_tasks_impl(port, ptr, rust_vec_len, data_len), + 11 => wire__crate__api__remove_workspace_impl(port, ptr, rust_vec_len, data_len), + 12 => wire__crate__api__reorder_task_impl(port, ptr, rust_vec_len, data_len), + 13 => wire__crate__api__set_current_workspace_impl(port, ptr, rust_vec_len, data_len), + 14 => wire__crate__api__toggle_task_impl(port, ptr, rust_vec_len, data_len), + 15 => wire__crate__api__update_task_impl(port, ptr, rust_vec_len, data_len), + _ => unreachable!(), + } +} + +fn pde_ffi_dispatcher_sync_impl( + func_id: i32, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + _ => unreachable!(), + } +} + +// Section: rust2dart + +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::api::AppConfigDto { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.workspaces.into_into_dart().into_dart(), + self.current_workspace.into_into_dart().into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::AppConfigDto {} +impl flutter_rust_bridge::IntoIntoDart for crate::api::AppConfigDto { + fn into_into_dart(self) -> crate::api::AppConfigDto { + self + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::api::TaskDto { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.id.into_into_dart().into_dart(), + self.title.into_into_dart().into_dart(), + self.description.into_into_dart().into_dart(), + self.status.into_into_dart().into_dart(), + self.due_date.into_into_dart().into_dart(), + self.created_at.into_into_dart().into_dart(), + self.updated_at.into_into_dart().into_dart(), + self.parent_id.into_into_dart().into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::TaskDto {} +impl flutter_rust_bridge::IntoIntoDart for crate::api::TaskDto { + fn into_into_dart(self) -> crate::api::TaskDto { + self + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::api::TaskListDto { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.id.into_into_dart().into_dart(), + self.title.into_into_dart().into_dart(), + self.created_at.into_into_dart().into_dart(), + self.updated_at.into_into_dart().into_dart(), + self.group_by_due_date.into_into_dart().into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::TaskListDto {} +impl flutter_rust_bridge::IntoIntoDart for crate::api::TaskListDto { + fn into_into_dart(self) -> crate::api::TaskListDto { + self + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::api::WorkspaceEntry { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.name.into_into_dart().into_dart(), + self.path.into_into_dart().into_dart(), + self.webdav_url.into_into_dart().into_dart(), + self.last_sync.into_into_dart().into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::WorkspaceEntry {} +impl flutter_rust_bridge::IntoIntoDart for crate::api::WorkspaceEntry { + fn into_into_dart(self) -> crate::api::WorkspaceEntry { + self + } +} + +impl SseEncode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.into_bytes(), serializer); + } +} + +impl SseEncode for crate::api::AppConfigDto { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.workspaces, serializer); + >::sse_encode(self.current_workspace, serializer); + } +} + +impl SseEncode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self as _).unwrap(); + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); + } + } +} + +impl SseEncode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + ::sse_encode(value, serializer); + } + } +} + +impl SseEncode for crate::api::TaskDto { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.id, serializer); + ::sse_encode(self.title, serializer); + ::sse_encode(self.description, serializer); + ::sse_encode(self.status, serializer); + >::sse_encode(self.due_date, serializer); + ::sse_encode(self.created_at, serializer); + ::sse_encode(self.updated_at, serializer); + >::sse_encode(self.parent_id, serializer); + } +} + +impl SseEncode for crate::api::TaskListDto { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.id, serializer); + ::sse_encode(self.title, serializer); + ::sse_encode(self.created_at, serializer); + ::sse_encode(self.updated_at, serializer); + ::sse_encode(self.group_by_due_date, serializer); + } +} + +impl SseEncode for u32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u32::(self).unwrap(); + } +} + +impl SseEncode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self).unwrap(); + } +} + +impl SseEncode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} +} + +impl SseEncode for crate::api::WorkspaceEntry { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.name, serializer); + ::sse_encode(self.path, serializer); + >::sse_encode(self.webdav_url, serializer); + >::sse_encode(self.last_sync, serializer); + } +} + +impl SseEncode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i32::(self).unwrap(); + } +} + +#[cfg(not(target_family = "wasm"))] +mod io { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.11.1. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_io!(); +} +#[cfg(not(target_family = "wasm"))] +pub use io::*; + +/// cbindgen:ignore +#[cfg(target_family = "wasm")] +mod web { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.11.1. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::wasm_bindgen; + use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_web!(); +} +#[cfg(target_family = "wasm")] +pub use web::*; diff --git a/apps/flutter/rust/src/lib.rs b/apps/flutter/rust/src/lib.rs new file mode 100644 index 0000000..25448a4 --- /dev/null +++ b/apps/flutter/rust/src/lib.rs @@ -0,0 +1,2 @@ +mod frb_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */ +pub mod api;