feat: Implement note encryption and synchronization features
- Added NoteEncryption class for encrypting and decrypting note content using AES-GCM. - Updated NoteRepository to handle synchronization of notes and categories with the server, including encryption of note data before sending. - Introduced SyncRequest and SyncResponse models for managing synchronization data. - Enhanced LocalVaultService to store and retrieve the encryption key. - Modified HomeScreen and SettingsScreen to trigger synchronization after note operations and manage API endpoint settings. - Added SyncStatusIndicator to provide visual feedback on synchronization status in the app title bar. - Created Category model to manage note categories with encryption support. - Updated note model to include UUID, server version, deletion status, and category ID. - Added necessary UI elements for displaying and managing the encryption key in SettingsScreen. - Updated dependencies in pubspec.yaml for cryptography and HTTP handling.
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:notas/platform/app_platform.dart';
|
||||
import 'package:notas/widgets/sync_status_indicator.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class AppTitleBar extends StatelessWidget {
|
||||
const AppTitleBar({super.key});
|
||||
const AppTitleBar({
|
||||
this.syncStatus = SyncStatus.idle,
|
||||
this.syncErrorMessage,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final SyncStatus syncStatus;
|
||||
final String? syncErrorMessage;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -12,33 +20,62 @@ class AppTitleBar extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (isMacOS) {
|
||||
return const SizedBox(
|
||||
return SizedBox(
|
||||
height: 28,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Mis Notas',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 13),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'Mis Notas',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 13),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
SyncStatusIndicator(
|
||||
status: syncStatus,
|
||||
errorMessage: syncErrorMessage,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isLinux) {
|
||||
return const _KdeTitleBar();
|
||||
return _KdeTitleBar(
|
||||
syncStatus: syncStatus,
|
||||
syncErrorMessage: syncErrorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox(
|
||||
return SizedBox(
|
||||
height: 40,
|
||||
child: WindowCaption(
|
||||
brightness: Brightness.dark,
|
||||
title: Text('Mis Notas', style: TextStyle(color: Colors.white)),
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Mis Notas', style: TextStyle(color: Colors.white)),
|
||||
const SizedBox(width: 8),
|
||||
SyncStatusIndicator(
|
||||
status: syncStatus,
|
||||
errorMessage: syncErrorMessage,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _KdeTitleBar extends StatefulWidget {
|
||||
const _KdeTitleBar();
|
||||
const _KdeTitleBar({
|
||||
this.syncStatus = SyncStatus.idle,
|
||||
this.syncErrorMessage,
|
||||
});
|
||||
|
||||
final SyncStatus syncStatus;
|
||||
final String? syncErrorMessage;
|
||||
|
||||
@override
|
||||
State<_KdeTitleBar> createState() => _KdeTitleBarState();
|
||||
@@ -130,12 +167,33 @@ class _KdeTitleBarState extends State<_KdeTitleBar> with WindowListener {
|
||||
),
|
||||
const IgnorePointer(
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Mis Notas',
|
||||
style: TextStyle(
|
||||
color: Color.fromARGB(255, 163, 163, 163),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Mis Notas',
|
||||
style: TextStyle(
|
||||
color: Color.fromARGB(255, 163, 163, 163),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: IgnorePointer(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Center(
|
||||
child: SyncStatusIndicator(
|
||||
status: widget.syncStatus,
|
||||
errorMessage: widget.syncErrorMessage,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:notas/widgets/sync_status_indicator.dart';
|
||||
|
||||
class AppTitleBar extends StatelessWidget {
|
||||
const AppTitleBar({super.key});
|
||||
const AppTitleBar({
|
||||
this.syncStatus = SyncStatus.idle,
|
||||
this.syncErrorMessage,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final SyncStatus syncStatus;
|
||||
final String? syncErrorMessage;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum SyncStatus {
|
||||
idle,
|
||||
syncing,
|
||||
synced,
|
||||
error,
|
||||
}
|
||||
|
||||
class SyncStatusIndicator extends StatelessWidget {
|
||||
const SyncStatusIndicator({
|
||||
required this.status,
|
||||
this.errorMessage,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final SyncStatus status;
|
||||
final String? errorMessage;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (status) {
|
||||
case SyncStatus.idle:
|
||||
return const SizedBox.shrink();
|
||||
|
||||
case SyncStatus.syncing:
|
||||
return const Tooltip(
|
||||
message: 'Sincronizando...',
|
||||
child: SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Color.fromARGB(255, 150, 150, 150),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
case SyncStatus.synced:
|
||||
return const Tooltip(
|
||||
message: 'Sincronizado',
|
||||
child: Icon(
|
||||
Icons.check_circle,
|
||||
size: 16,
|
||||
color: Colors.green,
|
||||
),
|
||||
);
|
||||
|
||||
case SyncStatus.error:
|
||||
return Tooltip(
|
||||
message: errorMessage ?? 'Error al sincronizar',
|
||||
child: const Icon(
|
||||
Icons.error,
|
||||
size: 16,
|
||||
color: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user