Skip to content

Commit c160e66

Browse files
committed
Merge branch 'dev'
2 parents 34a5a62 + c54524d commit c160e66

32 files changed

+1410
-225
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ GoogleService-Info.plist
5454

5555
*.patch
5656
/lib/license.dart
57+
firebase.json

assets/translations/de.json

+8-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
"activate": "Activ",
5151
"stop": "Stoppen",
5252
"start": "Starten",
53-
"repeat": "Wiederholen"
53+
"repeat": "Wiederholen",
54+
"load_more": "Mehr laden",
55+
"archived": "Archiviert"
5456
},
5557
"pages": {
5658
"dashboard": {
@@ -396,13 +398,14 @@
396398
"read_only": "Webcam ist schreibgeschützt"
397399
},
398400
"macros": {
401+
"default_grp": "Standard",
399402
"new_macro_grp": "Neue Makro - Gruppe",
400403
"no_macros_available": "Keine Makros verfügbar!",
401404
"no_macros_found": "Keine Makros gefunden!",
402405
"no_macros_in_grp": "Keine Makros in der Gruppe!",
403406
"deleted_grp": "Gruppe {} gelöscht",
404407
"macros": "Makros",
405-
"default_name": "Neuer Makro",
408+
"default_name": "Neue Makro Gruppe",
406409
"macros_to_default": {
407410
"one": "Ein Makro in die Standardgruppe verschoben!",
408411
"two": "Zwei Makro in die Standardgruppe verschoben!",
@@ -597,7 +600,9 @@
597600
},
598601
"spoolman": {
599602
"title": "Spoolman",
600-
"not_available": "Spoolman ist für diesen Drucker nicht verfügbar. Bitte stellen Sie sicher, dass Spoolman auf Ihrem Drucker installiert und aktiviert ist.",
603+
"not_available": "Spoolman ist für diesen Drucker nicht verfügbar.\nBitte stellen Sie sicher, dass Spoolman auf Ihrem Drucker installiert und aktiviert ist.",
604+
"learn_more": "Um mehr über Spoolman zu erfahren und wie Sie ihn installieren können, besuchen Sie die ",
605+
"learn_more_link": "GitHub Seite.",
601606
"no_spools": "Keine Spulen gefunden!",
602607
"no_filaments": "Keine Filamente gefunden!",
603608
"no_vendors": "Keine Anbieter gefunden!",

assets/translations/en.json

+8-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050
"activate": "Activate",
5151
"stop": "Stop",
5252
"start": "Start",
53-
"repeat": "Repeat"
53+
"repeat": "Repeat",
54+
"load_more": "Load more",
55+
"archived": "Archived"
5456
},
5557
"pages": {
5658
"dashboard": {
@@ -396,13 +398,14 @@
396398
"read_only": "Webcam is read-only"
397399
},
398400
"macros": {
401+
"default_grp": "Default",
399402
"new_macro_grp": "New Macro - Group",
400403
"no_macros_available": "No Macros available!",
401404
"no_macros_found": "No Macros found!",
402405
"no_macros_in_grp": "No macros in the group!",
403406
"deleted_grp": "Deleted group {}",
404407
"macros": "Macros",
405-
"default_name": "New Macro",
408+
"default_name": "New Macro Group",
406409
"macros_to_default": {
407410
"one": "Moved one macro to default group!",
408411
"two": "Moved two macro to default group!",
@@ -597,7 +600,9 @@
597600
},
598601
"spoolman": {
599602
"title": "Spoolman",
600-
"not_available": "Spoolman is not available for this printer. Please make sure that Spoolman is installed and enabled on your printer.",
603+
"not_available": "Spoolman is not available for this printer. \nPlease make sure that Spoolman is installed and enabled on your printer.",
604+
"learn_more": "To learn more about Spoolman and how to install it, visit the project's",
605+
"learn_more_link": "GitHub page.",
601606
"no_spools": "No spools found!",
602607
"no_filaments": "No filaments found!",
603608
"no_vendors": "No vendors found!",

common/lib/service/app_router.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
99
part 'app_router.g.dart';
1010

1111
mixin RouteDefinitionMixin {
12-
String? get name;
12+
// String get name;
1313
}
1414

1515
@riverpod

common/lib/service/machine_service.dart

+39-45
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import 'package:common/util/extensions/logging_extension.dart';
2626
import 'package:common/util/extensions/ref_extension.dart';
2727
import 'package:common/util/extensions/uri_extension.dart';
2828
import 'package:common/util/logger.dart';
29+
import 'package:easy_localization/easy_localization.dart';
2930
import 'package:firebase_analytics/firebase_analytics.dart';
3031
import 'package:flutter/foundation.dart';
3132
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -134,50 +135,24 @@ Future<List<Machine>> hiddenMachines(HiddenMachinesRef ref) async {
134135
}
135136

136137
@riverpod
137-
Stream<MachineSettings> machineSettings(MachineSettingsRef ref, String machineUUID) {
138+
Stream<MachineSettings> machineSettings(MachineSettingsRef ref, String machineUUID) async* {
138139
ref.keepAliveFor();
139140

140-
ref.listenSelf((previous, next) {
141-
logger.wtf('machineSettings updated to isLoading: ${next.isLoading}, $next');
142-
});
141+
// We listen to macro count changes to trigger a provider rebuild, allowing us to migrate the setting's macros
142+
var macroCnt = await ref.watch(printerProvider(machineUUID).selectAsync((data) => data.gcodeMacros.length));
143143

144-
StreamController<MachineSettings> streamController = StreamController();
145-
ref.onDispose(() {
146-
streamController.close();
147-
});
144+
// Converts Klippy ready state to a stream of settings -> Emits new settings each time the Klippy state is transitioning to ready
145+
yield* ref
146+
.watchAsSubject(klipperProvider(machineUUID))
147+
.where((event) => event.klippyState == KlipperState.ready)
148+
.distinct()
149+
.asyncMap((event) async {
150+
var printerData = await ref.read(printerProvider(machineUUID).future);
148151

149-
ref.listen(
150-
klipperProvider(machineUUID),
151-
(previous, next) async {
152-
switch (next) {
153-
// Normal data
154-
case AsyncValue(
155-
hasValue: true,
156-
hasError: false,
157-
isLoading: false,
158-
value: KlipperInstance(klippyState: KlipperState.ready)
159-
):
160-
try {
161-
var fetchSettings = await ref.read(machineServiceProvider).fetchSettings(machineUUID: machineUUID);
162-
streamController.add(fetchSettings);
163-
} catch (e) {
164-
logger.e('Error while fetching settings', e);
165-
streamController.addError(e);
166-
}
167-
break;
168-
// We have an error
169-
case AsyncValue(hasError: true, isLoading: false, error: var err, stackTrace: var trace):
170-
if (err != null) {
171-
streamController.addError(err, trace);
172-
}
173-
174-
case AsyncValue(isLoading: true) when previous != null:
175-
ref.invalidateSelf();
176-
}
177-
},
178-
fireImmediately: true,
179-
);
180-
return streamController.stream.distinct();
152+
return await ref
153+
.read(machineServiceProvider)
154+
.fetchSettingsAndAdjustDefaultMacros(machineUUID, printerData.gcodeMacros);
155+
});
181156
}
182157

183158
@riverpod
@@ -531,13 +506,30 @@ class MachineService {
531506
return i;
532507
}
533508

534-
Future<void> updateMacrosInSettings(String machineUUID, List<String> macros) async {
509+
/// Fetches the settings for a machine and adjusts the default macros.
510+
///
511+
/// This method fetches the settings for a machine with the provided UUID.
512+
/// It then adjusts the default macros based on the provided list of macros.
513+
/// If a macro already exists in the default group, it is not added again.
514+
/// If a macro does not exist in the default group, it is added.
515+
/// If a macro exists in the default group but not in the provided list, it is removed.
516+
///
517+
/// This method is useful for keeping the default macros up to date with the actual macros
518+
/// that are available on the machine.
519+
///
520+
/// [machineUUID] is the UUID of the machine to fetch the settings for.
521+
/// [macros] is the list of macros to adjust the default macros with.
522+
///
523+
/// Throws a [MobilerakerException] if the machine with the provided UUID does not exist.
524+
///
525+
/// Returns the updated [MachineSettings] for the machine.
526+
Future<MachineSettings> fetchSettingsAndAdjustDefaultMacros(String machineUUID, List<String> macros) async {
535527
// Get the machine with the provided UUID
536528
final machine = await _machineRepo.get(uuid: machineUUID);
537529

538530
if (machine == null) {
539531
logger.e('Could not update macros, machine $machineUUID not found!');
540-
return;
532+
return throw const MobilerakerException('Machine not found');
541533
}
542534

543535
// Log the machine information
@@ -572,14 +564,15 @@ class MachineService {
572564
logger.i('Found legacy default group, migrating it to the new default group format!');
573565
modifiableMacroGrps.remove(legacyDefaultGrp);
574566

575-
return MacroGroup.defaultGroup(name: 'Default', macros: legacyDefaultGrp.macros);
567+
return MacroGroup.defaultGroup(
568+
name: tr('pages.printer_edit.macros.default_grp'), macros: legacyDefaultGrp.macros);
576569
}
577570

578-
return MacroGroup.defaultGroup(name: 'Default');
571+
return MacroGroup.defaultGroup(name: tr('pages.printer_edit.macros.default_grp'));
579572
});
580573

581574
// If there's no legacy group and no new macros to add, return early
582-
if (!hasLegacyDefaultGroup && !hasUnavailableMacro && filteredRawMacros.isEmpty) return;
575+
if (!hasLegacyDefaultGroup && !hasUnavailableMacro && filteredRawMacros.isEmpty) return machineSettings;
583576

584577
if (hasUnavailableMacro) {
585578
logger.i('Found some unavailable macros, will update all groups without the unavailable macros!');
@@ -603,6 +596,7 @@ class MachineService {
603596
// Update the machine settings and save
604597
machineSettings.macroGroups = modifiableMacroGrps;
605598
await ref.read(machineSettingsRepositoryProvider(machine.uuid)).update(machineSettings);
599+
return machineSettings;
606600
}
607601

608602
/// Links the machine to the octoEverywhere service

common/lib/service/moonraker/printer_service.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ class PrinterService {
230230
if (disposed) return;
231231
// I need this temp variable since in some edge cases the updateSettings otherwise throws?
232232
var printerObj = printerBuilder.build();
233-
_machineService.updateMacrosInSettings(ownerUUID, printerObj.gcodeMacros).ignore();
233+
// _machineService.updateMacrosInSettings(ownerUUID, printerObj.gcodeMacros).ignore();
234234
_registerJrpcHandlers();
235235
_makeSubscribeRequest(printerObj.queryableObjects);
236236
current = printerObj;

lib/ui/components/connection/klippy_state_widget.dart common/lib/ui/components/connection/klippy_provider_guard.dart

+22-12
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,26 @@ import 'package:flutter/material.dart';
1414
import 'package:flutter_hooks/flutter_hooks.dart';
1515
import 'package:flutter_icons/flutter_icons.dart';
1616
import 'package:hooks_riverpod/hooks_riverpod.dart';
17-
import 'package:mobileraker/ui/components/connection/connection_state_controller.dart';
18-
import 'package:mobileraker/ui/components/power_api_card.dart';
1917

20-
import 'connection_state_view.dart';
18+
import '../../../service/app_router.dart';
19+
import '../../../service/machine_service.dart';
2120

22-
class KlippyStateWidget extends HookConsumerWidget {
23-
const KlippyStateWidget({
21+
class KlippyProviderGuard extends HookConsumerWidget {
22+
const KlippyProviderGuard({
2423
super.key,
2524
required this.machineUUID,
2625
required this.onConnected,
2726
this.skipKlipperReady = false,
27+
this.klippyErrorChildren,
2828
});
2929

3030
final String machineUUID;
31-
final OnConnectedBuilder onConnected;
31+
final Widget Function(BuildContext context, String machineUUID) onConnected;
3232
final bool skipKlipperReady;
3333

34+
// Additional children to show when klippy is in error state
35+
final List<Widget>? klippyErrorChildren;
36+
3437
@override
3538
Widget build(BuildContext context, WidgetRef ref) {
3639
// If we had a AsyncData previously, the dashboard should take care of showing KLIPPY errors
@@ -56,7 +59,7 @@ class KlippyStateWidget extends HookConsumerWidget {
5659
// The `when !wasFetched` ensures to skip the state error if we had a AsyncData before -> the dashboard should take care of showing errors
5760
)
5861
when !skipKlipperReady && !wasFetched =>
59-
_StateError(data: kInstance, machineUUID: machineUUID),
62+
_StateError(data: kInstance, machineUUID: machineUUID, onErrorChildren: klippyErrorChildren),
6063
AsyncData(value: KlipperInstance(klippyState: KlipperState.unauthorized)) => const _StateUnauthorized(),
6164
AsyncError(:final error) => _ProviderError(machineUUID: machineUUID, error: error),
6265
_ => onConnected(context, machineUUID),
@@ -66,10 +69,11 @@ class KlippyStateWidget extends HookConsumerWidget {
6669
}
6770

6871
class _StateError extends ConsumerWidget {
69-
const _StateError({super.key, required this.data, required this.machineUUID});
72+
const _StateError({super.key, required this.data, required this.machineUUID, this.onErrorChildren});
7073

7174
final KlipperInstance data;
7275
final String machineUUID;
76+
final List<Widget>? onErrorChildren;
7377

7478
@override
7579
Widget build(BuildContext context, WidgetRef ref) {
@@ -102,14 +106,18 @@ class _StateError extends ConsumerWidget {
102106
mainAxisAlignment: data.klippyConnected ? MainAxisAlignment.spaceBetween : MainAxisAlignment.center,
103107
children: [
104108
ElevatedButton(
105-
onPressed: ref.read(connectionStateControllerProvider.notifier).onRestartKlipperPressed,
109+
onPressed: () {
110+
ref.read(klipperServiceProvider(machineUUID)).restartKlipper();
111+
},
106112
child: const Text(
107113
'pages.dashboard.general.restart_klipper',
108114
).tr(),
109115
),
110116
if (data.klippyConnected)
111117
ElevatedButton(
112-
onPressed: ref.read(connectionStateControllerProvider.notifier).onRestartMCUPressed,
118+
onPressed: () {
119+
ref.read(klipperServiceProvider(machineUUID)).restartMCUs();
120+
},
113121
child: const Text(
114122
'pages.dashboard.general.restart_mcu',
115123
).tr(),
@@ -121,7 +129,7 @@ class _StateError extends ConsumerWidget {
121129
),
122130
),
123131
),
124-
if (data.hasPowerComponent) PowerApiCard(machineUUID: machineUUID),
132+
if (onErrorChildren != null) ...onErrorChildren!,
125133
],
126134
);
127135
}
@@ -142,7 +150,9 @@ class _StateUnauthorized extends ConsumerWidget {
142150
textAlign: TextAlign.center,
143151
),
144152
TextButton(
145-
onPressed: ref.read(connectionStateControllerProvider.notifier).onEditPrinter,
153+
onPressed: () {
154+
ref.read(goRouterProvider).pushNamed('printerEdit', extra: machine);
155+
},
146156
child: Text('components.nav_drawer.printer_settings'.tr()),
147157
),
148158
],

0 commit comments

Comments
 (0)