-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jzecm wal local sync 958 #1010
Jzecm wal local sync 958 #1010
Conversation
WalkthroughThis update introduces local synchronization capabilities, internet connection status monitoring, and a new time format conversion utility. It also includes UI enhancements for managing the local sync feature and modifies the WebSocket service pool's start method. Changes
Uplevel your code reviews with Entelligence.AI ProEntelligence.AI ProIf you like this project, please support us by purchasing the Pro version. The Pro version has advanced context, superior noise reduction and several proprietary improvements compared to the open source version. Moreover, Entelligence.AI Pro is free for open source projects. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Files selected (9)
- app/lib/backend/preferences.dart (1)
- app/lib/main.dart (2)
- app/lib/pages/memories/page.dart (3)
- app/lib/pages/memories/widgets/local_sync.dart (1)
- app/lib/pages/settings/developer.dart (1)
- app/lib/providers/capture_provider.dart (8)
- app/lib/providers/developer_mode_provider.dart (3)
- app/lib/services/sockets.dart (1)
- app/lib/utils/other/string_utils.dart (1)
Files skipped from review due to trivial changes (3)
- app/lib/pages/settings/developer.dart
- app/lib/services/sockets.dart
- app/lib/utils/other/string_utils.dart
Review comments generated (22)
- Review: 17
- LGTM: 5
Tips
Chat with Entelligence.AI Bot (@Entelligence.AI
)
- Reply on review comments left by this bot to ask follow-up questions. A review comment is a comment on a diff or a file.
- Invite the bot into a review comment chain by tagging
@Entelligence.AI
in a reply.
Code suggestions
- The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
- You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.
Pausing incremental reviews
- Add
@Entelligence.AI: ignore
anywhere in the PR description to pause further reviews from the bot.
bool localSyncEnabled = false; | ||
|
||
void initialize() { | ||
gcpCredentialsController.text = SharedPreferencesUtil().gcpCredentials; | ||
gcpBucketNameController.text = SharedPreferencesUtil().gcpBucketName; | ||
webhookOnMemoryCreated.text = SharedPreferencesUtil().webhookOnMemoryCreated; | ||
webhookOnTranscriptReceived.text = SharedPreferencesUtil().webhookOnTranscriptReceived; | ||
localSyncEnabled = SharedPreferencesUtil().localSyncEnabled; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initialize()
method is not asynchronous, but it's calling SharedPreferencesUtil() which might involve disk I/O operations. This could potentially block the main thread and degrade the app performance. Consider making this method asynchronous and use await with SharedPreferencesUtil() calls.
- void initialize() {
+ Future<void> initialize() async {
gcpCredentialsController.text = SharedPreferencesUtil().gcpCredentials;
gcpBucketNameController.text = SharedPreferencesUtil().gcpBucketName;
webhookOnMemoryCreated.text = SharedPreferencesUtil().webhookOnMemoryCreated;
webhookOnTranscriptReceived.text = SharedPreferencesUtil().webhookOnTranscriptReceived;
localSyncEnabled = await SharedPreferencesUtil().localSyncEnabled;
notifyListeners();
}
void onLocalSyncEnabledChanged(var value) { | ||
localSyncEnabled = value; | ||
notifyListeners(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The onLocalSyncEnabledChanged
method does not validate the input value before assigning it to localSyncEnabled
. It's a good practice to validate inputs in setter methods to prevent potential issues. If value
is expected to be a boolean, consider adding a type check.
- void onLocalSyncEnabledChanged(var value) {
+ void onLocalSyncEnabledChanged(bool value) {
if (value is bool) {
localSyncEnabled = value;
notifyListeners();
} else {
throw ArgumentError('Expected a boolean value');
}
}
set wals(List<Wal> wals) { | ||
final List<String> value = wals.map((e) => jsonEncode(e.toJson())).toList(); | ||
saveStringList('v3/wals', value); | ||
saveStringList('wals', value); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setter for wals
is missing null safety checks. If a null list is passed, it will cause a NullPointerException
at the map function.
- set wals(List<Wal> wals) {
- final List<String> value = wals.map((e) => jsonEncode(e.toJson())).toList();
- saveStringList('wals', value);
- }
+ set wals(List<Wal> wals) {
+ if (wals != null) {
+ final List<String> value = wals.map((e) => jsonEncode(e.toJson())).toList();
+ saveStringList('wals', value);
+ } else {
+ saveStringList('wals', null);
+ }
+ }
final List<String> value = getStringList('wals') ?? []; | ||
return Wal.fromJsonList(value.map((e) => jsonDecode(e)).toList()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the setter, the getter for wals
should also have null safety checks. If getStringList('wals')
returns null, it will cause a NullPointerException
at the map function.
- List<Wal> get wals {
- final List<String> value = getStringList('wals') ?? [];
- return Wal.fromJsonList(value.map((e) => jsonDecode(e)).toList());
- }
+ List<Wal> get wals {
+ final List<String> value = getStringList('wals');
+ if (value != null) {
+ return Wal.fromJsonList(value.map((e) => jsonDecode(e)).toList());
+ } else {
+ return null;
+ }
+ }
@@ -67,7 +68,7 @@ class _MemoriesPageState extends State<MemoriesPage> with AutomaticKeepAliveClie | |||
|
|||
@override | |||
Widget build(BuildContext context) { | |||
print('building memories page'); | |||
debugPrint('building memories page'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of debugPrint
instead of print
is a good practice in Flutter, especially for logging during development. It allows you to turn off these logs in production by simply setting debugPrint = null;
. However, it's important to note that this change doesn't affect the functionality of the code.
- print('building memories page');
+ debugPrint('building memories page');
@@ -295,6 +311,7 @@ class CaptureProvider extends ChangeNotifier | |||
_bleBytesStream?.cancel(); | |||
_socket?.unsubscribe(this); | |||
_keepAliveTimer?.cancel(); | |||
_internetStatusListener?.cancel(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void onInternetSatusChanged(InternetStatus status) { | ||
debugPrint("[SocketService] Internet connection changed $status"); | ||
_internetStatus = status; | ||
notifyListeners(); | ||
} | ||
|
||
void setIsWalSupported(bool value) { | ||
_isWalSupported = value; | ||
notifyListeners(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New methods onInternetSatusChanged
and setIsWalSupported
have been added. These methods update the respective variables and notify listeners of the changes. This is a good practice as it ensures that any changes to these variables are propagated throughout the application. However, there's a typo in onInternetSatusChanged
- it should be onInternetStatusChanged
. Here's the corrected code:
- void onInternetSatusChanged(InternetStatus status) {
+ void onInternetStatusChanged(InternetStatus status) {
debugPrint("[SocketService] Internet connection changed $status");
_internetStatus = status;
notifyListeners();
}
const LocalSyncWidget({super.key}); | ||
|
||
@override | ||
State<LocalSyncWidget> createState() => _LocalSyncWidgetState(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@override | ||
void dispose() { | ||
_missSecondsInEstTimer?.cancel(); | ||
super.dispose(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@override | ||
Widget build(BuildContext context) { | ||
return Consumer3<MemoryProvider, CaptureProvider, DeveloperModeProvider>( | ||
builder: (context, provider, captureProvider, devModeProvider, child) { | ||
if (provider.missingWalsInSeconds > 120) { | ||
_status = LocalSyncStatus.flush; | ||
_missSeconds = max(_missSeconds, provider.missingWalsInSeconds); // est. good for ux | ||
} else if (!captureProvider.isWalSupported) { | ||
_status = LocalSyncStatus.disabled; | ||
_missSecondsInEstTimer?.cancel(); | ||
} else if ((!captureProvider.transcriptServiceReady && captureProvider.recordingDeviceServiceReady) || | ||
provider.missingWalsInSeconds > 0) { | ||
var previousStatus = _status; | ||
_status = LocalSyncStatus.inProgress; | ||
|
||
// Change state to in progress | ||
if (previousStatus != LocalSyncStatus.inProgress) { | ||
_missSecondsInEstTimer?.cancel(); | ||
_missSeconds = provider.missingWalsInSeconds; | ||
_missSecondsInEstTimer = Timer.periodic(const Duration(seconds: 1), (t) { | ||
setState(() { | ||
_missSeconds++; | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
// in progress | ||
if (_status == LocalSyncStatus.inProgress) { | ||
return Container( | ||
decoration: BoxDecoration( | ||
color: Colors.grey.shade900, | ||
borderRadius: const BorderRadius.all(Radius.circular(12)), | ||
), | ||
margin: const EdgeInsets.fromLTRB(16, 16, 16, 16), | ||
padding: const EdgeInsets.all(16), | ||
child: Text( | ||
'${convertToHHMMSS(_missSeconds)} of conversation locally', | ||
style: const TextStyle(color: Colors.white, fontSize: 16), | ||
textAlign: TextAlign.center, | ||
), | ||
); | ||
} | ||
|
||
// ready to sync | ||
if (_status == LocalSyncStatus.flush) { | ||
return GestureDetector( | ||
onTap: () { | ||
routeToPage(context, const SyncPage()); | ||
}, | ||
child: Container( | ||
decoration: BoxDecoration( | ||
color: Colors.grey.shade900, | ||
borderRadius: const BorderRadius.all(Radius.circular(12)), | ||
), | ||
margin: const EdgeInsets.fromLTRB(16, 16, 16, 16), | ||
padding: const EdgeInsets.all(16), | ||
child: Row( | ||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||
children: [ | ||
Expanded( | ||
child: Row( | ||
children: [ | ||
const Icon(Icons.download_rounded), | ||
const SizedBox(width: 16), | ||
Text( | ||
'${secondsToHumanReadable(_missSeconds)} available. Sync now?', | ||
style: const TextStyle(color: Colors.white, fontSize: 16), | ||
), | ||
], | ||
), | ||
), | ||
], | ||
), | ||
), | ||
); | ||
} | ||
|
||
return const SizedBox.shrink(); | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic inside the build
method seems complex and hard to follow. Consider breaking it down into smaller, more manageable functions. This will improve readability and maintainability. For example, you could create separate methods for each LocalSyncStatus
case.
Also, there's no handling for when _status
is null. You should add a default case to handle this scenario.
- Widget build(BuildContext context) {
- return Consumer3<MemoryProvider, CaptureProvider, DeveloperModeProvider>(
- builder: (context, provider, captureProvider, devModeProvider, child) {
- if (provider.missingWalsInSeconds > 120) {
- _status = LocalSyncStatus.flush;
- _missSeconds = max(_missSeconds, provider.missingWalsInSeconds); // est. good for ux
- } else if (!captureProvider.isWalSupported) {
- _status = LocalSyncStatus.disabled;
- _missSecondsInEstTimer?.cancel();
- } else if ((!captureProvider.transcriptServiceReady && captureProvider.recordingDeviceServiceReady) ||
- provider.missingWalsInSeconds > 0) {
- var previousStatus = _status;
- _status = LocalSyncStatus.inProgress;
-
- // Change state to in progress
- if (previousStatus != LocalSyncStatus.inProgress) {
- _missSecondsInEstTimer?.cancel();
- _missSeconds = provider.missingWalsInSeconds;
- _missSecondsInEstTimer = Timer.periodic(const Duration(seconds: 1), (t) {
- setState(() {
- _missSeconds++;
- });
- });
- }
- }
-
- // in progress
- if (_status == LocalSyncStatus.inProgress) {
- return Container(
- decoration: BoxDecoration(
- color: Colors.grey.shade900,
- borderRadius: const BorderRadius.all(Radius.circular(12)),
- ),
- margin: const EdgeInsets.fromLTRB(16, 16, 16, 16),
- padding: const EdgeInsets.all(16),
- child: Text(
- '${convertToHHMMSS(_missSeconds)} of conversation locally',
- style: const TextStyle(color: Colors.white, fontSize: 16),
- textAlign: TextAlign.center,
- ),
- );
- }
-
- // ready to sync
- if (_status == LocalSyncStatus.flush) {
- return GestureDetector(
- onTap: () {
- routeToPage(context, const SyncPage());
- },
- child: Container(
- decoration: BoxDecoration(
- color: Colors.grey.shade900,
- borderRadius: const BorderRadius.all(Radius.circular(12)),
- ),
- margin: const EdgeInsets.fromLTRB(16, 16, 16, 16),
- padding: const EdgeInsets.all(16),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Expanded(
- child: Row(
- children: [
- const Icon(Icons.download_rounded),
- const SizedBox(width: 16),
- Text(
- '${secondsToHumanReadable(_missSeconds)} available. Sync now?',
- style: const TextStyle(color: Colors.white, fontSize: 16),
- ),
- ],
- ),
- ),
- ],
- ),
- ),
- );
- }
-
- return const SizedBox.shrink();
- });
- }
+ Widget build(BuildContext context) {
+ return Consumer3<MemoryProvider, CaptureProvider, DeveloperModeProvider>(
+ builder: (context, provider, captureProvider, devModeProvider, child) {
+ _updateStatus(provider, captureProvider);
+
+ switch (_status) {
+ case LocalSyncStatus.inProgress:
+ return _buildInProgressWidget();
+ case LocalSyncStatus.flush:
+ return _buildFlushWidget(context);
+ case LocalSyncStatus.disabled:
+ default:
+ return const SizedBox.shrink();
+ }
+ });
+ }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Files selected (1)
- app/lib/pages/memories/widgets/local_sync.dart (1)
Review comments generated (3)
- Review: 1
- LGTM: 2
Tips
Chat with Entelligence.AI Bot (@Entelligence.AI
)
- Reply on review comments left by this bot to ask follow-up questions. A review comment is a comment on a diff or a file.
- Invite the bot into a review comment chain by tagging
@Entelligence.AI
in a reply.
Code suggestions
- The bot may make code suggestions, but please review them carefully before committing since the line number ranges may be misaligned.
- You can edit the comment made by the bot and manually tweak the suggestion if it is slightly off.
Pausing incremental reviews
- Add
@Entelligence.AI: ignore
anywhere in the PR description to pause further reviews from the bot.
return Consumer2<MemoryProvider, CaptureProvider>(builder: (context, provider, captureProvider, child) { | ||
if (provider.missingWalsInSeconds > 120) { | ||
_status = LocalSyncStatus.flush; | ||
_missSeconds = max(_missSeconds, provider.missingWalsInSeconds); // est. good for ux | ||
} else if (!captureProvider.isWalSupported) { | ||
_status = LocalSyncStatus.disabled; | ||
_missSecondsInEstTimer?.cancel(); | ||
} else if ((!captureProvider.transcriptServiceReady && captureProvider.recordingDeviceServiceReady) || | ||
provider.missingWalsInSeconds > 0) { | ||
var previousStatus = _status; | ||
_status = LocalSyncStatus.inProgress; | ||
|
||
// Change state to in progress | ||
if (previousStatus != LocalSyncStatus.inProgress) { | ||
_missSecondsInEstTimer?.cancel(); | ||
_missSeconds = provider.missingWalsInSeconds; | ||
_missSecondsInEstTimer = Timer.periodic(const Duration(seconds: 1), (t) { | ||
setState(() { | ||
_missSeconds++; | ||
}); | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for setting _status
and _missSeconds
seems to be a bit convoluted. It might be more maintainable if you encapsulate this logic into separate methods, each responsible for determining a specific status. This would make the code easier to read and test.
- if (provider.missingWalsInSeconds > 120) {
- _status = LocalSyncStatus.flush;
- _missSeconds = max(_missSeconds, provider.missingWalsInSeconds); // est. good for ux
- } else if (!captureProvider.isWalSupported) {
- _status = LocalSyncStatus.disabled;
- _missSecondsInEstTimer?.cancel();
- } else if ((!captureProvider.transcriptServiceReady && captureProvider.recordingDeviceServiceReady) ||
- provider.missingWalsInSeconds > 0) {
- var previousStatus = _status;
- _status = LocalSyncStatus.inProgress;
-
- // Change state to in progress
- if (previousStatus != LocalSyncStatus.inProgress) {
- _missSecondsInEstTimer?.cancel();
- _missSeconds = provider.missingWalsInSeconds;
- _missSecondsInEstTimer = Timer.periodic(const Duration(seconds: 1), (t) {
- setState(() {
- _missSeconds++;
- });
- });
- }
- }
+ _updateStatus(provider, captureProvider);
And then define _updateStatus
method like:
void _updateStatus(MemoryProvider provider, CaptureProvider captureProvider) {
if (provider.missingWalsInSeconds > 120) {
_status = LocalSyncStatus.flush;
_missSeconds = max(_missSeconds, provider.missingWalsInSeconds); // est. good for ux
} else if (!captureProvider.isWalSupported) {
_status = LocalSyncStatus.disabled;
_missSecondsInEstTimer?.cancel();
} else if ((!captureProvider.transcriptServiceReady && captureProvider.recordingDeviceServiceReady) ||
provider.missingWalsInSeconds > 0) {
var previousStatus = _status;
_status = LocalSyncStatus.inProgress;
// Change state to in progress
if (previousStatus != LocalSyncStatus.inProgress) {
_missSecondsInEstTimer?.cancel();
_missSeconds = provider.missingWalsInSeconds;
_startMissSecondsTimer();
}
}
}
void _startMissSecondsTimer() {
_missSecondsInEstTimer = Timer.periodic(const Duration(seconds: 1), (t) {
setState(() {
_missSeconds++;
});
});
}
Summary by Entelligence.AI