Skip to content

Commit

Permalink
WAL Sync UI (#993)
Browse files Browse the repository at this point in the history
<!-- This is an auto-generated comment: release notes by OSS
Entelligence.AI -->
### Summary by Entelligence.AI

- New Feature: Introduced new UI components for managing and displaying
memories and synchronization processes, enhancing user interaction.
- New Feature: Added functionality to track the progress of memory
syncing operations, providing real-time feedback to users.
- Refactor: Updated `syncLocalFiles` and `syncAll` functions in backend
services to return more detailed results, improving error handling and
debugging capabilities.
<!-- end of auto-generated comment: release notes by OSS Entelligence.AI
-->
  • Loading branch information
josancamon19 authored Oct 7, 2024
2 parents df05175 + 8252b7a commit c6f2e61
Show file tree
Hide file tree
Showing 7 changed files with 448 additions and 27 deletions.
4 changes: 2 additions & 2 deletions app/lib/backend/http/api/memories.dart
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ Future<List<ServerMemory>> sendStorageToBackend(File file, String sdCardDateTime
}
}

Future<bool> syncLocalFiles(List<File> files) async {
Future<(Map<String, dynamic>?, bool)> syncLocalFiles(List<File> files) async {
var request = http.MultipartRequest(
'POST',
Uri.parse('${Env.apiBaseUrl}v1/sync-local-files'),
Expand All @@ -268,7 +268,7 @@ Future<bool> syncLocalFiles(List<File> files) async {

if (response.statusCode == 200) {
debugPrint('syncLocalFile Response body: ${jsonDecode(response.body)}');
return true;
return (jsonDecode(response.body) as Map<String, dynamic>, true);
} else {
debugPrint('Failed to upload sample. Status code: ${response.statusCode}');
throw Exception('Failed to upload sample. Status code: ${response.statusCode}');
Expand Down
72 changes: 56 additions & 16 deletions app/lib/pages/memories/page.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
import 'package:flutter/material.dart';
import 'package:friend_private/backend/schema/memory.dart';
import 'package:friend_private/pages/capture/widgets/widgets.dart';
import 'package:friend_private/pages/memories/sync_page.dart';
import 'package:friend_private/pages/memories/widgets/date_list_item.dart';
import 'package:friend_private/pages/memories/widgets/processing_capture.dart';
import 'package:friend_private/providers/memory_provider.dart';
import 'package:friend_private/utils/other/temp.dart';
import 'package:provider/provider.dart';
import 'package:visibility_detector/visibility_detector.dart';

import 'widgets/empty_memories.dart';
import 'widgets/memory_list_item.dart';

String secondsToHumanReadable(int seconds) {
if (seconds < 60) {
return '$seconds secs';
} else if (seconds < 3600) {
var minutes = (seconds / 60).floor();
var remainingSeconds = seconds % 60;
if (remainingSeconds == 0) {
return '$minutes mins';
} else {
return '$minutes mins $remainingSeconds secs';
}
} else if (seconds < 86400) {
var hours = (seconds / 3600).floor();
var remainingMinutes = (seconds % 3600 / 60).floor();
if (remainingMinutes == 0) {
return '$hours hours';
} else {
return '$hours hours $remainingMinutes mins';
}
} else {
var days = (seconds / 86400).floor();
var remainingHours = (seconds % 86400 / 3600).floor();
if (remainingHours == 0) {
return '$days days';
} else {
return '$days days $remainingHours hours';
}
}
}

class MemoriesPage extends StatefulWidget {
const MemoriesPage({super.key});

Expand Down Expand Up @@ -46,25 +78,32 @@ class _MemoriesPageState extends State<MemoriesPage> with AutomaticKeepAliveClie
},
child: CustomScrollView(
slivers: [
// TODO: FIXME
SliverToBoxAdapter(
child: memoryProvider.missingWals.isNotEmpty
? Padding(
padding: const EdgeInsets.all(32.0),
child: Center(
child: GestureDetector(
onTap: () {
memoryProvider.syncWals();
},
child: memoryProvider.walsSyncedProgress == 0.0
? Text(
"You have ${memoryProvider.missingWals.map((val) => val.seconds).reduce((a, b) => a + b)}s stereo localy, sync now?")
: Text("${(memoryProvider.walsSyncedProgress * 100).toInt()}%"),
child: memoryProvider.missingWals.isNotEmpty
? GestureDetector(
onTap: () {
routeToPage(context, const SyncPage());
},
child: Container(
width: double.maxFinite,
decoration: BoxDecoration(
color: Colors.grey.shade900,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.fromLTRB(16, 18, 16, 0),
padding: const EdgeInsets.all(16),
child: ListTile(
leading: const Icon(Icons.record_voice_over_rounded),
title: Text(
'You have ${secondsToHumanReadable(memoryProvider.missingWals.map((val) => val.seconds).reduce((a, b) => a + b))} of conversation locally, sync now?',
style: const TextStyle(color: Colors.white, fontSize: 16),
),
),
)
: SizedBox.shrink()),
const SliverToBoxAdapter(child: SizedBox(height: 32)),
),
)
: const SizedBox.shrink(),
),
const SliverToBoxAdapter(child: SizedBox(height: 26)),
const SliverToBoxAdapter(child: SpeechProfileCardWidget()),
const SliverToBoxAdapter(child: UpdateFirmwareCardWidget()),
const SliverToBoxAdapter(child: MemoryCaptureWidget()),
Expand Down Expand Up @@ -95,6 +134,7 @@ class _MemoriesPageState extends State<MemoriesPage> with AutomaticKeepAliveClie
childCount: memoryProvider.groupedMemories.length + 1,
(context, index) {
if (index == memoryProvider.groupedMemories.length) {
print('loading more memories');
if (memoryProvider.isLoadingMemories) {
return const Center(
child: Padding(
Expand Down
142 changes: 142 additions & 0 deletions app/lib/pages/memories/sync_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import 'package:flutter/material.dart';
import 'package:friend_private/pages/memories/widgets/sync_animation.dart';
import 'package:friend_private/providers/memory_provider.dart';
import 'package:friend_private/utils/other/temp.dart';
import 'package:gradient_borders/box_borders/gradient_box_border.dart';
import 'package:provider/provider.dart';

import 'synced_memories_page.dart';

class SyncPage extends StatefulWidget {
const SyncPage({super.key});

@override
State<SyncPage> createState() => _SyncPageState();
}

class _SyncPageState extends State<SyncPage> {
bool _isAnimating = false;

void _toggleAnimation() {
setState(() {
_isAnimating = !_isAnimating;
});
}

@override
Widget build(BuildContext context) {
return PopScope(
onPopInvoked: (didPop) {
Provider.of<MemoryProvider>(context, listen: false).clearSyncResult();
},
child: Scaffold(
appBar: AppBar(
title: const Text('Sync Memories'),
backgroundColor: Theme.of(context).colorScheme.primary,
),
backgroundColor: Theme.of(context).colorScheme.primary,
body: Consumer<MemoryProvider>(
builder: (context, memoryProvider, child) {
return Center(
child: Column(
children: [
const SizedBox(height: 80),
child!,
const SizedBox(height: 80),
memoryProvider.isSyncing || memoryProvider.syncCompleted
? const SizedBox()
: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
decoration: BoxDecoration(
border: const GradientBoxBorder(
gradient: LinearGradient(colors: [
Color.fromARGB(127, 208, 208, 208),
Color.fromARGB(127, 188, 99, 121),
Color.fromARGB(127, 86, 101, 182),
Color.fromARGB(127, 126, 190, 236)
]),
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
child: TextButton(
onPressed: () async {
_toggleAnimation();
await memoryProvider.syncWals();
_toggleAnimation();
},
child: const Text(
'Sync Now',
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
const SizedBox(
height: 10,
),
memoryProvider.isSyncing
? Text(
'${memoryProvider.walsSyncedProgress}% synced',
style: const TextStyle(color: Colors.white, fontSize: 16),
)
: const SizedBox.shrink(),
const SizedBox(
height: 10,
),
memoryProvider.syncCompleted && memoryProvider.syncResult != null
? Column(
children: [
const Text(
'Memories Synced Successfully 🎉',
style: TextStyle(color: Colors.white, fontSize: 16),
),
const SizedBox(
height: 18,
),
(memoryProvider.syncResult!['new_memories'].isNotEmpty ||
memoryProvider.syncResult!['updated_memories'].isNotEmpty)
? Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
decoration: BoxDecoration(
border: const GradientBoxBorder(
gradient: LinearGradient(colors: [
Color.fromARGB(127, 208, 208, 208),
Color.fromARGB(127, 188, 99, 121),
Color.fromARGB(127, 86, 101, 182),
Color.fromARGB(127, 126, 190, 236)
]),
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
child: TextButton(
onPressed: () {
routeToPage(context, const SyncedMemoriesPage());
},
child: const Text(
'View Synced Memories',
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
)
: const SizedBox.shrink(),
],
)
: const SizedBox.shrink(),
],
),
);
},
child: RepaintBoundary(
child: SyncAnimation(
isAnimating: _isAnimating,
onStart: () {},
onStop: () {},
dotsPerRing: 12,
),
),
),
),
);
}
}
60 changes: 60 additions & 0 deletions app/lib/pages/memories/synced_memories_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:friend_private/providers/memory_provider.dart';
import 'package:provider/provider.dart';

class SyncedMemoriesPage extends StatelessWidget {
final Map<String, dynamic>? res;
const SyncedMemoriesPage({super.key, this.res});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Synced Memories'),
backgroundColor: Theme.of(context).colorScheme.primary,
),
backgroundColor: Theme.of(context).colorScheme.primary,
body: Consumer<MemoryProvider>(
builder: (context, memoryProvider, child) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Updated Memories",
style: TextStyle(color: Colors.white),
),
ListView.separated(
shrinkWrap: true,
itemBuilder: (ctx, i) {
return Container();
},
separatorBuilder: (ctx, i) {
return const SizedBox(
height: 10,
);
},
itemCount: memoryProvider.syncResult!['updated_memories'].length,
),
const Text(
"New Memories",
style: TextStyle(color: Colors.white),
),
ListView.separated(
shrinkWrap: true,
itemBuilder: (ctx, i) {
return Container();
},
separatorBuilder: (ctx, i) {
return const SizedBox(
height: 10,
);
},
itemCount: memoryProvider.syncResult!['new_memories'].length,
),
],
);
},
),
);
}
}
Loading

0 comments on commit c6f2e61

Please sign in to comment.