Skip to content

Commit 17b3b2b

Browse files
client+server: big refactoring+fixing+database migration WIP
1 parent 7ad6185 commit 17b3b2b

46 files changed

Lines changed: 15054 additions & 1501 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

school_data_hub_client/lib/src/protocol/_features/books/models/pupil_book_lending.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ abstract class PupilBookLending implements _i1.SerializableModel {
2020
required this.lendingId,
2121
this.status,
2222
required this.score,
23+
this.bookScore,
2324
required this.lentAt,
2425
required this.lentBy,
2526
this.returnedAt,
@@ -37,6 +38,7 @@ abstract class PupilBookLending implements _i1.SerializableModel {
3738
required String lendingId,
3839
String? status,
3940
required int score,
41+
int? bookScore,
4042
required DateTime lentAt,
4143
required String lentBy,
4244
DateTime? returnedAt,
@@ -55,6 +57,7 @@ abstract class PupilBookLending implements _i1.SerializableModel {
5557
lendingId: jsonSerialization['lendingId'] as String,
5658
status: jsonSerialization['status'] as String?,
5759
score: jsonSerialization['score'] as int,
60+
bookScore: jsonSerialization['bookScore'] as int?,
5861
lentAt: _i1.DateTimeJsonExtension.fromJson(jsonSerialization['lentAt']),
5962
lentBy: jsonSerialization['lentBy'] as String,
6063
returnedAt: jsonSerialization['returnedAt'] == null
@@ -90,6 +93,8 @@ abstract class PupilBookLending implements _i1.SerializableModel {
9093

9194
int score;
9295

96+
int? bookScore;
97+
9398
DateTime lentAt;
9499

95100
String lentBy;
@@ -118,6 +123,7 @@ abstract class PupilBookLending implements _i1.SerializableModel {
118123
String? lendingId,
119124
String? status,
120125
int? score,
126+
int? bookScore,
121127
DateTime? lentAt,
122128
String? lentBy,
123129
DateTime? returnedAt,
@@ -136,6 +142,7 @@ abstract class PupilBookLending implements _i1.SerializableModel {
136142
'lendingId': lendingId,
137143
if (status != null) 'status': status,
138144
'score': score,
145+
if (bookScore != null) 'bookScore': bookScore,
139146
'lentAt': lentAt.toJson(),
140147
'lentBy': lentBy,
141148
if (returnedAt != null) 'returnedAt': returnedAt?.toJson(),
@@ -165,6 +172,7 @@ class _PupilBookLendingImpl extends PupilBookLending {
165172
required String lendingId,
166173
String? status,
167174
required int score,
175+
int? bookScore,
168176
required DateTime lentAt,
169177
required String lentBy,
170178
DateTime? returnedAt,
@@ -180,6 +188,7 @@ class _PupilBookLendingImpl extends PupilBookLending {
180188
lendingId: lendingId,
181189
status: status,
182190
score: score,
191+
bookScore: bookScore,
183192
lentAt: lentAt,
184193
lentBy: lentBy,
185194
returnedAt: returnedAt,
@@ -201,6 +210,7 @@ class _PupilBookLendingImpl extends PupilBookLending {
201210
String? lendingId,
202211
Object? status = _Undefined,
203212
int? score,
213+
Object? bookScore = _Undefined,
204214
DateTime? lentAt,
205215
String? lentBy,
206216
Object? returnedAt = _Undefined,
@@ -217,6 +227,7 @@ class _PupilBookLendingImpl extends PupilBookLending {
217227
lendingId: lendingId ?? this.lendingId,
218228
status: status is String? ? status : this.status,
219229
score: score ?? this.score,
230+
bookScore: bookScore is int? ? bookScore : this.bookScore,
220231
lentAt: lentAt ?? this.lentAt,
221232
lentBy: lentBy ?? this.lentBy,
222233
returnedAt: returnedAt is DateTime? ? returnedAt : this.returnedAt,
54.7 KB
Binary file not shown.

school_data_hub_flutter/lib/app_utils/logger/domain/log_service.dart

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,65 @@
11
// lib/services/log_service.dart
2+
import 'package:flutter/foundation.dart';
23
import 'package:logging/logging.dart';
3-
import 'package:signals/signals.dart';
44

55
import '../model/app_log.dart';
66

7-
// Service to manage the list of logs backed by signals
7+
// Service to manage the list of logs backed by ValueNotifiers
88
class LogService {
99
// Define a max number of logs to keep in memory
1010
static const int _maxLogs = 1000;
1111

12-
final Signal<List<AppLog>> _logs = signal(
13-
<AppLog>[],
14-
debugLabel: 'LogService._logs',
15-
);
16-
final Signal<String> _searchQuery = signal(
17-
'',
18-
debugLabel: 'LogService._searchQuery',
19-
);
20-
final Signal<Map<Level, bool>> _levelVisibility = signal(
21-
{},
22-
debugLabel: 'LogService._levelVisibility',
23-
);
24-
final Signal<Set<String>> _loggerNames = signal(
12+
final ValueNotifier<List<AppLog>> _logs = ValueNotifier(<AppLog>[]);
13+
final ValueNotifier<String> _searchQuery = ValueNotifier('');
14+
final ValueNotifier<Map<Level, bool>> _levelVisibility = ValueNotifier({});
15+
final ValueNotifier<Set<String>> _loggerNames = ValueNotifier(<String>{});
16+
final ValueNotifier<Set<String>> _selectedLoggerFilters = ValueNotifier(
2517
<String>{},
26-
debugLabel: 'LogService._loggerNames',
2718
);
28-
final Signal<Set<String>> _selectedLoggerFilters = signal(
19+
20+
// Derived state (replaces Computed signals)
21+
final ValueNotifier<List<AppLog>> filteredLogs = ValueNotifier(<AppLog>[]);
22+
final ValueNotifier<bool> showInfo = ValueNotifier(true);
23+
final ValueNotifier<bool> showWarning = ValueNotifier(true);
24+
final ValueNotifier<bool> showSevere = ValueNotifier(true);
25+
final ValueNotifier<bool> showShout = ValueNotifier(true);
26+
final ValueNotifier<bool> showFine = ValueNotifier(true);
27+
final ValueNotifier<List<String>> loggerNamesSorted = ValueNotifier(
28+
<String>[],
29+
);
30+
final ValueNotifier<Set<String>> selectedLoggerFilters = ValueNotifier(
2931
<String>{},
30-
debugLabel: 'LogService._selectedLoggerFilters',
3132
);
33+
final ValueNotifier<bool> filtersActive = ValueNotifier(false);
34+
35+
ValueNotifier<String> get searchQuery => _searchQuery;
36+
ValueNotifier<Set<String>> get loggerNames => _loggerNames;
37+
38+
LogService() {
39+
// Wire up derived state updates
40+
_logs.addListener(_recompute);
41+
_searchQuery.addListener(_recompute);
42+
_levelVisibility.addListener(_recompute);
43+
_selectedLoggerFilters.addListener(_recompute);
44+
_loggerNames.addListener(_recomputeLoggerNames);
45+
}
46+
47+
void _recompute() {
48+
filteredLogs.value = _computeFilteredLogs();
49+
showInfo.value = _isLevelVisible(Level.INFO);
50+
showWarning.value = _isLevelVisible(Level.WARNING);
51+
showSevere.value = _isLevelVisible(Level.SEVERE);
52+
showShout.value = _isLevelVisible(Level.SHOUT);
53+
showFine.value = _isLevelVisible(Level.FINE);
54+
selectedLoggerFilters.value = _selectedLoggerFilters.value;
55+
filtersActive.value =
56+
_selectedLoggerFilters.value.isNotEmpty ||
57+
_levelVisibility.value.values.any((isVisible) => !isVisible);
58+
}
59+
60+
void _recomputeLoggerNames() {
61+
loggerNamesSorted.value = _loggerNames.value.toList()..sort();
62+
}
3263

3364
void addLogString({
3465
required String message,
@@ -42,40 +73,6 @@ class LogService {
4273
addLog(AppLog(level, message, loggerName));
4374
}
4475

45-
late final Computed<List<AppLog>> filteredLogs = computed(
46-
_computeFilteredLogs,
47-
);
48-
49-
late final Computed<bool> showInfo = computed(
50-
() => _isLevelVisible(Level.INFO),
51-
);
52-
late final Computed<bool> showWarning = computed(
53-
() => _isLevelVisible(Level.WARNING),
54-
);
55-
late final Computed<bool> showSevere = computed(
56-
() => _isLevelVisible(Level.SEVERE),
57-
);
58-
late final Computed<bool> showShout = computed(
59-
() => _isLevelVisible(Level.SHOUT),
60-
);
61-
late final Computed<bool> showFine = computed(
62-
() => _isLevelVisible(Level.FINE),
63-
);
64-
late final Computed<List<String>> loggerNamesSorted = computed(
65-
() => _loggerNames.value.toList()..sort(),
66-
);
67-
late final Computed<Set<String>> selectedLoggerFilters = computed(
68-
() => _selectedLoggerFilters.value,
69-
);
70-
late final Computed<bool> filtersActive = computed(
71-
() =>
72-
_selectedLoggerFilters.value.isNotEmpty ||
73-
_levelVisibility.value.values.any((isVisible) => !isVisible),
74-
);
75-
76-
Signal<String> get searchQuery => _searchQuery;
77-
Signal<Set<String>> get loggerNames => _loggerNames;
78-
7976
/// Ingest a [LogRecord] and fan out aggregated console strings into
8077
/// individual app logs when needed.
8178
void ingestRecord(LogRecord record) {

school_data_hub_flutter/lib/app_utils/logger/domain/signals_logger.dart

Lines changed: 0 additions & 57 deletions
This file was deleted.

school_data_hub_flutter/lib/app_utils/logger/presentation/logs_page/logs_page.dart

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
11
// lib/log_viewer_page.dart
22
import 'package:flutter/material.dart';
3-
import 'package:flutter_hooks/flutter_hooks.dart';
3+
import 'package:flutter_it/flutter_it.dart';
44
import 'package:school_data_hub_flutter/common/theme/app_colors.dart';
55
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_app_bar.dart';
66
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_sliver_list.dart';
77
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_sliver_search_app_bar.dart';
8-
import 'package:signals_hooks/signals_hooks.dart';
9-
import 'package:flutter_it/flutter_it.dart';
108

119
import '../../domain/log_service.dart';
1210
import '../../model/app_log.dart';
1311
import 'widgets/log_entry_card.dart';
1412
import 'widgets/logs_filter_bottom_sheet.dart';
1513

16-
class LogsPage extends HookWidget {
14+
class LogsPage extends WatchingWidget {
1715
const LogsPage({super.key});
1816

1917
@override
2018
Widget build(BuildContext context) {
2119
final logService = di<LogService>();
22-
final searchQuery = useSignalValue(logService.searchQuery);
23-
final logs = useSignalValue(logService.filteredLogs);
24-
final filtersActive = useSignalValue(logService.filtersActive);
25-
final searchController = useTextEditingController(text: searchQuery);
20+
final searchQuery = watch(logService.searchQuery).value;
21+
final logs = watch(logService.filteredLogs).value;
22+
final filtersActive = watch(logService.filtersActive).value;
23+
final searchController = createOnce(
24+
() => TextEditingController(text: searchQuery),
25+
);
2626

27-
useEffect(() {
28-
if (searchController.text != searchQuery) {
29-
searchController.value = TextEditingValue(
30-
text: searchQuery,
31-
selection: TextSelection.collapsed(offset: searchQuery.length),
32-
);
33-
}
34-
return null;
35-
}, [searchQuery, searchController]);
27+
// Sync controller text when searchQuery changes externally
28+
registerHandler(
29+
target: logService.searchQuery,
30+
handler: (BuildContext context, String query, void Function() cancel) {
31+
if (searchController.text != query) {
32+
searchController.value = TextEditingValue(
33+
text: query,
34+
selection: TextSelection.collapsed(offset: query.length),
35+
);
36+
}
37+
},
38+
);
3639

3740
return Scaffold(
3841
backgroundColor: AppColors.canvasColor,

school_data_hub_flutter/lib/app_utils/logger/presentation/logs_page/widgets/logs_filter_bottom_sheet.dart

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import 'package:flutter/material.dart';
2-
import 'package:flutter_hooks/flutter_hooks.dart';
2+
import 'package:flutter_it/flutter_it.dart';
33
import 'package:gap/gap.dart';
44
import 'package:logging/logging.dart';
55
import 'package:school_data_hub_flutter/app_utils/logger/domain/log_service.dart';
66
import 'package:school_data_hub_flutter/common/theme/app_colors.dart';
77
import 'package:school_data_hub_flutter/common/theme/styles.dart';
8-
import 'package:signals_hooks/signals_hooks.dart';
9-
import 'package:flutter_it/flutter_it.dart';
108

119
Future<void> showLogsFilterBottomSheet(BuildContext context) {
1210
return showModalBottomSheet<void>(
@@ -22,20 +20,20 @@ Future<void> showLogsFilterBottomSheet(BuildContext context) {
2220
);
2321
}
2422

25-
class LogsFilterBottomSheet extends HookWidget {
23+
class LogsFilterBottomSheet extends WatchingWidget {
2624
const LogsFilterBottomSheet({super.key});
2725

2826
@override
2927
Widget build(BuildContext context) {
3028
final logService = di<LogService>();
31-
final showFine = useSignalValue(logService.showFine);
32-
final showInfo = useSignalValue(logService.showInfo);
33-
final showWarning = useSignalValue(logService.showWarning);
34-
final showSevere = useSignalValue(logService.showSevere);
35-
final showShout = useSignalValue(logService.showShout);
36-
final loggerNames = useSignalValue(logService.loggerNamesSorted);
37-
final selectedLoggers = useSignalValue(logService.selectedLoggerFilters);
38-
final filtersActive = useSignalValue(logService.filtersActive);
29+
final showFine = watch(logService.showFine).value;
30+
final showInfo = watch(logService.showInfo).value;
31+
final showWarning = watch(logService.showWarning).value;
32+
final showSevere = watch(logService.showSevere).value;
33+
final showShout = watch(logService.showShout).value;
34+
final loggerNames = watch(logService.loggerNamesSorted).value;
35+
final selectedLoggers = watch(logService.selectedLoggerFilters).value;
36+
final filtersActive = watch(logService.filtersActive).value;
3937

4038
return SafeArea(
4139
child: Padding(

0 commit comments

Comments
 (0)