feat: add update and delete functionality to tags and improve report screen

This commit is contained in:
Patryk Hegenberg 2025-04-16 16:08:45 +02:00
parent 2df0390ae2
commit ebc4cdf754
12 changed files with 464 additions and 43 deletions

View file

@ -68,15 +68,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: 'Flutter Rust Time Tracker', title: 'Flutter Rust Time Tracker',
theme: ThemeData( theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
primarySwatch: Colors.blue,
useMaterial3: true,
// Optional: Theme für BottomNavigationBar anpassen
// bottomNavigationBarTheme: const BottomNavigationBarThemeData(
// selectedItemColor: Colors.deepPurple,
// unselectedItemColor: Colors.grey,
// ),
),
home: const InitializerWidget(), home: const InitializerWidget(),
); );
} }

View file

@ -3,6 +3,7 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:timetracker/screens/home_screen.dart'; import 'package:timetracker/screens/home_screen.dart';
import 'package:timetracker/screens/tags_screen.dart'; import 'package:timetracker/screens/tags_screen.dart';
import 'package:timetracker/screens/report_screen.dart'; import 'package:timetracker/screens/report_screen.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class MainScreen extends StatefulWidget { class MainScreen extends StatefulWidget {
const MainScreen({super.key}); const MainScreen({super.key});
@ -37,8 +38,8 @@ class _MainScreenState extends State<MainScreen> {
items: [ items: [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(context.platformIcons.clockSolid), icon: FaIcon(FontAwesomeIcons.clock),
activeIcon: Icon(context.platformIcons.clockSolid), activeIcon: FaIcon(FontAwesomeIcons.solidClock),
label: 'Tracking', label: 'Tracking',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
@ -47,8 +48,12 @@ class _MainScreenState extends State<MainScreen> {
label: 'Tags', label: 'Tags',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(context.platformIcons.bookmarkOutline), icon: FaIcon(
activeIcon: Icon(context.platformIcons.bookmarkSolid), FontAwesomeIcons.chartBar,
), //Icon(context.platformIcons.bookmarkOutline),
activeIcon: FaIcon(
FontAwesomeIcons.solidChartBar,
), //Icon(context.platformIcons.bookmarkSolid),
label: 'Reports', label: 'Reports',
), ),
], ],

View file

@ -487,8 +487,8 @@ class _ReportScreenState extends State<ReportScreen> {
), ),
), ),
), ),
SizedBox(height: 250, child: _buildPieChart(_reportData!)), // SizedBox(height: 250, child: _buildPieChart(_reportData!)),
const Divider(), // const Divider(),
SizedBox( SizedBox(
height: 250, height: 250,
child: _buildBarChart(_reportData!, startDate, endDate), child: _buildBarChart(_reportData!, startDate, endDate),
@ -507,7 +507,7 @@ class _ReportScreenState extends State<ReportScreen> {
), ),
), ),
), ),
SizedBox(height: 300, child: _buildReportList(_reportData!.entries)), SizedBox(height: 600, child: _buildReportList(_reportData!.entries)),
], ],
); );
} }
@ -649,8 +649,8 @@ class _ReportScreenState extends State<ReportScreen> {
Widget _buildReportList(List<TimeEntry> entries) { Widget _buildReportList(List<TimeEntry> entries) {
return ListView.builder( return ListView.builder(
shrinkWrap: true, // shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), // physics: const NeverScrollableScrollPhysics(),
itemCount: entries.length, itemCount: entries.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final entry = entries[index]; final entry = entries[index];

View file

@ -1,8 +1,10 @@
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:flutter/cupertino.dart' show CupertinoIcons; import 'package:flutter/cupertino.dart' show CupertinoIcons;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:timetracker/src/rust/api.dart';
import 'package:timetracker/time_tracking_service.dart'; import 'package:timetracker/time_tracking_service.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class TagsScreen extends StatefulWidget { class TagsScreen extends StatefulWidget {
const TagsScreen({super.key}); const TagsScreen({super.key});
@ -40,6 +42,129 @@ class _TagsScreenState extends State<TagsScreen> {
} }
} }
void _showEditTagDialog(BuildContext context, Tag tag) {
final TextEditingController editController = TextEditingController(
text: tag.name,
);
showPlatformDialog(
context: context,
builder:
(dialogContext) => PlatformAlertDialog(
title: PlatformText('Tag bearbeiten'),
content: PlatformTextField(
controller: editController,
autofocus: true,
hintText: 'Neuer Tag-Name',
material:
(_, __) => MaterialTextFieldData(
decoration: const InputDecoration(
labelText: 'Neuer Tag-Name',
),
),
cupertino:
(_, __) =>
CupertinoTextFieldData(placeholder: 'Neuer Tag-Name'),
),
actions: [
PlatformDialogAction(
child: PlatformText('Abbrechen'),
onPressed: () => Navigator.pop(dialogContext),
),
PlatformDialogAction(
child: PlatformText('Speichern'),
onPressed: () async {
final newName = editController.text.trim();
if (newName.isEmpty) {
_showPlatformFeedbackDialog(
context,
'Fehler',
'Tag-Name darf nicht leer sein.',
);
return;
}
if (newName == tag.name) {
Navigator.pop(dialogContext);
return;
}
final success = await context
.read<TimeTrackingService>()
.flUpdateTag(tag.id.toInt(), newName);
if (!mounted) return;
Navigator.pop(dialogContext);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
if (success) {
_showPlatformFeedbackDialog(
context,
'Erfolg',
'Tag aktualisiert.',
);
} else {
_showPlatformFeedbackDialog(
context,
'Fehler',
'Tag konnte nicht aktualisiert werden (Name evtl. vergeben?).',
);
}
});
},
),
],
),
);
}
void _confirmAndDeleteTag(BuildContext context, Tag tag) {
showPlatformDialog(
context: context,
builder:
(dialogContext) => PlatformAlertDialog(
title: PlatformText('Tag löschen?'),
content: PlatformText(
'Möchtest du den Tag "${tag.name}" wirklich löschen? Zugeordnete Zeiteinträge verlieren ihre Tag-Zuweisung.',
),
actions: <Widget>[
PlatformDialogAction(
child: PlatformText('Abbrechen'),
onPressed: () => Navigator.pop(dialogContext),
),
PlatformDialogAction(
child: PlatformText('Löschen'),
cupertino:
(_, __) =>
CupertinoDialogActionData(isDestructiveAction: true),
onPressed: () async {
Navigator.pop(dialogContext);
final success = await context
.read<TimeTrackingService>()
.flDeleteTag(tag.id.toInt());
if (!mounted) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
if (success) {
} else {
_showPlatformFeedbackDialog(
context,
'Fehler',
'Tag konnte nicht gelöscht werden.',
);
}
});
},
),
],
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final tags = context.watch<TimeTrackingService>().tags; final tags = context.watch<TimeTrackingService>().tags;
@ -51,6 +176,7 @@ class _TagsScreenState extends State<TagsScreen> {
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Expanded( Expanded(
child: PlatformTextField( child: PlatformTextField(
@ -85,9 +211,36 @@ class _TagsScreenState extends State<TagsScreen> {
itemCount: tags.length, itemCount: tags.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final tag = tags[index]; final tag = tags[index];
return ListTile( return Slidable(
key: ValueKey(tag.id.toInt()),
endActionPane: ActionPane(
motion: const StretchMotion(),
children: [
SlidableAction(
onPressed: (context) {
_showEditTagDialog(this.context, tag);
},
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
icon: PlatformIcons(context).edit,
label: 'Bearbeiten',
),
SlidableAction(
onPressed: (context) {
_confirmAndDeleteTag(this.context, tag);
},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: PlatformIcons(context).delete,
label: 'Löschen',
),
],
),
child: ListTile(
title: PlatformText(tag.name), title: PlatformText(tag.name),
trailing: PlatformText('ID: ${tag.id}'), trailing: PlatformText('ID: ${tag.id.toInt()}'),
),
); );
}, },
), ),

View file

@ -14,6 +14,12 @@ Future<void> initApp({required String dbDirectoryPath}) =>
Future<PlatformInt64> createTag({required String name}) => Future<PlatformInt64> createTag({required String name}) =>
RustLib.instance.api.crateApiCreateTag(name: name); RustLib.instance.api.crateApiCreateTag(name: name);
Future<void> updateTag({required PlatformInt64 id, required String newName}) =>
RustLib.instance.api.crateApiUpdateTag(id: id, newName: newName);
Future<void> deleteTag({required PlatformInt64 id}) =>
RustLib.instance.api.crateApiDeleteTag(id: id);
Future<List<Tag>> getTags() => RustLib.instance.api.crateApiGetTags(); Future<List<Tag>> getTags() => RustLib.instance.api.crateApiGetTags();
Future<PlatformInt64> startTracking({ Future<PlatformInt64> startTracking({

View file

@ -62,7 +62,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.9.0'; String get codegenVersion => '2.9.0';
@override @override
int get rustContentHash => -79634774; int get rustContentHash => 350676645;
static const kDefaultExternalLibraryLoaderConfig = static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig( ExternalLibraryLoaderConfig(
@ -75,6 +75,8 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
abstract class RustLibApi extends BaseApi { abstract class RustLibApi extends BaseApi {
Future<PlatformInt64> crateApiCreateTag({required String name}); Future<PlatformInt64> crateApiCreateTag({required String name});
Future<void> crateApiDeleteTag({required PlatformInt64 id});
Future<void> crateApiDeleteTimeEntry({required PlatformInt64 id}); Future<void> crateApiDeleteTimeEntry({required PlatformInt64 id});
Future<ReportData> crateApiGenerateReport({ Future<ReportData> crateApiGenerateReport({
@ -99,6 +101,11 @@ abstract class RustLibApi extends BaseApi {
required PlatformInt64 endTimeUnixTs, required PlatformInt64 endTimeUnixTs,
}); });
Future<void> crateApiUpdateTag({
required PlatformInt64 id,
required String newName,
});
Future<void> crateApiUpdateTimeEntry({ Future<void> crateApiUpdateTimeEntry({
required PlatformInt64 entryId, required PlatformInt64 entryId,
PlatformInt64? newTagId, PlatformInt64? newTagId,
@ -144,7 +151,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
const TaskConstMeta(debugName: "create_tag", argNames: ["name"]); const TaskConstMeta(debugName: "create_tag", argNames: ["name"]);
@override @override
Future<void> crateApiDeleteTimeEntry({required PlatformInt64 id}) { Future<void> crateApiDeleteTag({required PlatformInt64 id}) {
return handler.executeNormal( return handler.executeNormal(
NormalTask( NormalTask(
callFfi: (port_) { callFfi: (port_) {
@ -161,6 +168,34 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
decodeErrorData: sse_decode_AnyhowException, decodeErrorData: sse_decode_AnyhowException,
), ),
constMeta: kCrateApiDeleteTagConstMeta,
argValues: [id],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiDeleteTagConstMeta =>
const TaskConstMeta(debugName: "delete_tag", argNames: ["id"]);
@override
Future<void> crateApiDeleteTimeEntry({required PlatformInt64 id}) {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_i_64(id, serializer);
pdeCallFfi(
generalizedFrbRustBinding,
serializer,
funcId: 3,
port: port_,
);
},
codec: SseCodec(
decodeSuccessData: sse_decode_unit,
decodeErrorData: sse_decode_AnyhowException,
),
constMeta: kCrateApiDeleteTimeEntryConstMeta, constMeta: kCrateApiDeleteTimeEntryConstMeta,
argValues: [id], argValues: [id],
apiImpl: this, apiImpl: this,
@ -187,7 +222,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 3, funcId: 4,
port: port_, port: port_,
); );
}, },
@ -216,7 +251,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 4, funcId: 5,
port: port_, port: port_,
); );
}, },
@ -246,7 +281,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 5, funcId: 6,
port: port_, port: port_,
); );
}, },
@ -274,7 +309,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 6, funcId: 7,
port: port_, port: port_,
); );
}, },
@ -306,7 +341,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 7, funcId: 8,
port: port_, port: port_,
); );
}, },
@ -340,7 +375,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 8, funcId: 9,
port: port_, port: port_,
); );
}, },
@ -360,6 +395,38 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ["entryId", "endTimeUnixTs"], argNames: ["entryId", "endTimeUnixTs"],
); );
@override
Future<void> crateApiUpdateTag({
required PlatformInt64 id,
required String newName,
}) {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_i_64(id, serializer);
sse_encode_String(newName, serializer);
pdeCallFfi(
generalizedFrbRustBinding,
serializer,
funcId: 10,
port: port_,
);
},
codec: SseCodec(
decodeSuccessData: sse_decode_unit,
decodeErrorData: sse_decode_AnyhowException,
),
constMeta: kCrateApiUpdateTagConstMeta,
argValues: [id, newName],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiUpdateTagConstMeta =>
const TaskConstMeta(debugName: "update_tag", argNames: ["id", "newName"]);
@override @override
Future<void> crateApiUpdateTimeEntry({ Future<void> crateApiUpdateTimeEntry({
required PlatformInt64 entryId, required PlatformInt64 entryId,
@ -378,7 +445,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
funcId: 9, funcId: 11,
port: port_, port: port_,
); );
}, },

View file

@ -105,16 +105,13 @@ class TimeTrackingService extends ChangeNotifier {
Future<bool> flCreateTag(String name) async { Future<bool> flCreateTag(String name) async {
if (name.trim().isEmpty) { if (name.trim().isEmpty) {
log("Cannot create tag: Name is empty.");
return false; return false;
} }
final trimmedName = name.trim(); final trimmedName = name.trim();
try { try {
final tagId = await createTag(name: trimmedName); final tagId = await createTag(name: trimmedName);
log("Tag created with ID: $tagId"); log("Tag created with ID: $tagId");
_tags = await getTags(); await _loadUpdatedTags();
notifyListeners();
return true; return true;
} on FrbException catch (e) { } on FrbException catch (e) {
log("Error creating tag: $e"); log("Error creating tag: $e");
@ -124,6 +121,27 @@ class TimeTrackingService extends ChangeNotifier {
return false; return false;
} }
} }
// Future<bool> flCreateTag(String name) async {
// if (name.trim().isEmpty) {
// log("Cannot create tag: Name is empty.");
// return false;
// }
// final trimmedName = name.trim();
// try {
// final tagId = await createTag(name: trimmedName);
// log("Tag created with ID: $tagId");
// _tags = await getTags();
// notifyListeners();
// return true;
// } on FrbException catch (e) {
// log("Error creating tag: $e");
// return false;
// } catch (e) {
// log("Unexpected error creating tag: $e");
// return false;
// }
// }
Future<ReportData?> flGetReport( Future<ReportData?> flGetReport(
int? tagId, int? tagId,
@ -184,4 +202,50 @@ class TimeTrackingService extends ChangeNotifier {
return false; return false;
} }
} }
Future<bool> flUpdateTag(int tagId, String newName) async {
if (newName.trim().isEmpty) {
log('Service: Cannot update tag $tagId: New name is empty.');
return false;
}
final trimmedName = newName.trim();
log('Service: Attempting to update tag $tagId to "$trimmedName"');
try {
await updateTag(id: tagId.toInt(), newName: trimmedName);
log('Service: Successfully updated tag $tagId');
await _loadUpdatedTags();
return true; // Erfolg
} on FrbException catch (e, s) {
log('Service: Error updating tag $tagId: $e\n$s');
return false;
} catch (e, s) {
log('Service: Unexpected error updating tag $tagId: $e\n$s');
return false;
}
}
Future<bool> flDeleteTag(int tagId) async {
log('Service: Attempting to delete tag $tagId');
try {
await deleteTag(id: tagId.toInt());
log('Service: Successfully deleted tag $tagId');
await _loadUpdatedTags();
return true;
} on FrbException catch (e, s) {
log('Service: Error deleting tag $tagId: $e\n$s');
return false;
} catch (e, s) {
log('Service: Unexpected error deleting tag $tagId: $e\n$s');
return false;
}
}
Future<void> _loadUpdatedTags() async {
try {
_tags = await getTags();
notifyListeners();
} catch (e) {
log("Error refreshing tags after CUD operation: $e");
}
}
} }

View file

@ -152,6 +152,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
font_awesome_flutter:
dependency: "direct main"
description:
name: font_awesome_flutter
sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a
url: "https://pub.dev"
source: hosted
version: "10.8.0"
fuchsia_remote_debug_protocol: fuchsia_remote_debug_protocol:
dependency: transitive dependency: transitive
description: flutter description: flutter

View file

@ -22,6 +22,7 @@ dependencies:
fl_chart: ^0.70.2 fl_chart: ^0.70.2
flutter_platform_widgets: ^8.0.0 flutter_platform_widgets: ^8.0.0
flutter_slidable: ^4.0.0 flutter_slidable: ^4.0.0
font_awesome_flutter: ^10.8.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -45,6 +45,20 @@ pub fn create_tag(name: String) -> Result<i64> {
database::create_tag_internal(name.trim()) database::create_tag_internal(name.trim())
} }
pub fn update_tag(id: i64, new_name: String) -> Result<()> {
log::debug!(
"API: update_tag called for id {} with name '{}'",
id,
new_name
);
database::update_tag_internal(id, &new_name)
}
pub fn delete_tag(id: i64) -> Result<()> {
log::debug!("API: delete_tag called for id {}", id);
database::delete_tag_internal(id)
}
pub fn get_tags() -> Result<Vec<Tag>> { pub fn get_tags() -> Result<Vec<Tag>> {
log::debug!("API: get_tags called"); log::debug!("API: get_tags called");
database::get_tags_internal() database::get_tags_internal()

View file

@ -106,6 +106,44 @@ pub(super) fn get_tags_internal() -> Result<Vec<TagInternal>> {
}) })
} }
pub(super) fn update_tag_internal(id: i64, new_name: &str) -> Result<()> {
log::debug!(
"RUST_DB: Attempting to update tag_id {} to name '{}'",
id,
new_name
);
ensure!(!new_name.trim().is_empty(), "New tag name cannot be empty");
let name = new_name.trim();
with_db_connection(|conn| {
let rows_affected = conn
.execute("UPDATE tags SET name = ?1 WHERE id = ?2", params![name, id])
.context("Failed to execute update tag SQL")?;
ensure!(rows_affected > 0, "Tag {} not found for update", id);
log::info!("RUST_DB: Successfully updated tag {}", id);
Ok(())
})
.with_context(|| format!("Failed operation for updating tag_id {}", id))
}
pub(super) fn delete_tag_internal(id: i64) -> Result<()> {
log::debug!("RUST_DB: Attempting to delete tag_id {}", id);
with_db_connection(|conn| {
let rows_affected = conn
.execute("DELETE FROM tags WHERE id = ?1", params![id])
.context("Failed to execute delete tag SQL")?;
ensure!(rows_affected > 0, "Tag {} not found for deletion", id);
log::info!("RUST_DB: Successfully deleted tag {}", id);
Ok(())
})
.with_context(|| format!("Failed operation for deleting tag_id {}", id))
}
pub(super) fn start_tracking_internal(tag_id: Option<i64>, start_time_unix_ts: i64) -> Result<i64> { pub(super) fn start_tracking_internal(tag_id: Option<i64>, start_time_unix_ts: i64) -> Result<i64> {
with_db_connection(|conn| { with_db_connection(|conn| {
conn.execute( conn.execute(

View file

@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
default_rust_auto_opaque = RustAutoOpaqueMoi, default_rust_auto_opaque = RustAutoOpaqueMoi,
); );
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.9.0"; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.9.0";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -79634774; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 350676645;
// Section: executor // Section: executor
@ -80,6 +80,41 @@ fn wire__crate__api__create_tag_impl(
}, },
) )
} }
fn wire__crate__api__delete_tag_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::SseCodec, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "delete_tag",
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_id = <i64>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
(move || {
let output_ok = crate::api::delete_tag(api_id)?;
Ok(output_ok)
})(),
)
}
},
)
}
fn wire__crate__api__delete_time_entry_impl( fn wire__crate__api__delete_time_entry_impl(
port_: flutter_rust_bridge::for_generated::MessagePort, port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
@ -333,6 +368,42 @@ fn wire__crate__api__stop_tracking_impl(
}, },
) )
} }
fn wire__crate__api__update_tag_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::SseCodec, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "update_tag",
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_id = <i64>::sse_decode(&mut deserializer);
let api_new_name = <String>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
(move || {
let output_ok = crate::api::update_tag(api_id, api_new_name)?;
Ok(output_ok)
})(),
)
}
},
)
}
fn wire__crate__api__update_time_entry_impl( fn wire__crate__api__update_time_entry_impl(
port_: flutter_rust_bridge::for_generated::MessagePort, port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
@ -551,14 +622,16 @@ fn pde_ffi_dispatcher_primary_impl(
// Codec=Pde (Serialization + dispatch), see doc to use other codecs // Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id { match func_id {
1 => wire__crate__api__create_tag_impl(port, ptr, rust_vec_len, data_len), 1 => wire__crate__api__create_tag_impl(port, ptr, rust_vec_len, data_len),
2 => wire__crate__api__delete_time_entry_impl(port, ptr, rust_vec_len, data_len), 2 => wire__crate__api__delete_tag_impl(port, ptr, rust_vec_len, data_len),
3 => wire__crate__api__generate_report_impl(port, ptr, rust_vec_len, data_len), 3 => wire__crate__api__delete_time_entry_impl(port, ptr, rust_vec_len, data_len),
4 => wire__crate__api__get_last_unfinished_tracking_impl(port, ptr, rust_vec_len, data_len), 4 => wire__crate__api__generate_report_impl(port, ptr, rust_vec_len, data_len),
5 => wire__crate__api__get_tags_impl(port, ptr, rust_vec_len, data_len), 5 => wire__crate__api__get_last_unfinished_tracking_impl(port, ptr, rust_vec_len, data_len),
6 => wire__crate__api__init_app_impl(port, ptr, rust_vec_len, data_len), 6 => wire__crate__api__get_tags_impl(port, ptr, rust_vec_len, data_len),
7 => wire__crate__api__start_tracking_impl(port, ptr, rust_vec_len, data_len), 7 => wire__crate__api__init_app_impl(port, ptr, rust_vec_len, data_len),
8 => wire__crate__api__stop_tracking_impl(port, ptr, rust_vec_len, data_len), 8 => wire__crate__api__start_tracking_impl(port, ptr, rust_vec_len, data_len),
9 => wire__crate__api__update_time_entry_impl(port, ptr, rust_vec_len, data_len), 9 => wire__crate__api__stop_tracking_impl(port, ptr, rust_vec_len, data_len),
10 => wire__crate__api__update_tag_impl(port, ptr, rust_vec_len, data_len),
11 => wire__crate__api__update_time_entry_impl(port, ptr, rust_vec_len, data_len),
_ => unreachable!(), _ => unreachable!(),
} }
} }