Skip to content

Commit

Permalink
Refactor data and notifier
Browse files Browse the repository at this point in the history
  • Loading branch information
sunarya-thito committed Oct 25, 2024
1 parent 728cfdf commit ad36500
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 121 deletions.
48 changes: 6 additions & 42 deletions lib/src/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -309,46 +309,6 @@ class DataNotifier<T> extends StatelessWidget implements MultiDataItem {
Type get dataType => T;
}

class DataStream<T> extends StatelessWidget implements MultiDataItem {
final Stream<T> stream;
final Widget? child;

const DataStream(this.stream, {super.key, this.child});

const DataStream.inherit({
super.key,
required this.stream,
required this.child,
});

@override
Widget wrapWidget(Widget child) {
return DataStream<T>.inherit(
stream: stream,
child: child,
);
}

@override
Widget build(BuildContext context) {
return StreamBuilder<T>(
stream: stream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const SizedBox();
}
return Data<T>.inherit(
data: snapshot.data!,
child: child,
);
},
);
}

@override
Type get dataType => T;
}

/// A widget builder that receives the data from the ancestor Data widget.
typedef DataWidgetBuilder<T> = Widget Function(
BuildContext context, T data, Widget? child);
Expand Down Expand Up @@ -748,8 +708,12 @@ class _CaptureAllData extends StatelessWidget {
}
}

mixin MultiModelItem {
Model<Object?> get normalized;
}

/// A mixin for all kinds of Model properties.
mixin ModelProperty<T> {
mixin ModelProperty<T> implements MultiModelItem {
/// The data key of the model.
Symbol get dataKey;

Expand Down Expand Up @@ -1139,7 +1103,7 @@ class ModelKey<T> {
/// A widget that provides multiple models to its descendants.
class MultiModel extends StatelessWidget {
/// The list of models that will be provided to the descendants.
final List<ModelProperty> data;
final List<MultiModelItem> data;

/// The child widget.
final Widget child;
Expand Down
62 changes: 7 additions & 55 deletions lib/src/notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,20 @@ import 'package:flutter/foundation.dart';
import '../data_widget.dart';

/// A notifier class that allows mutable updates and notifies listeners of changes.
class MutableNotifier<T> implements ValueListenable<T> {
final EventNotifier _notifier = EventNotifier();

@override
final T value;

class MutableNotifier<T> extends ValueNotifier<T> {
/// Constructs a [MutableNotifier] with an initial value.
MutableNotifier(this.value);
MutableNotifier(super.value);

/// Updates the value using the provided [updater] function.
/// If the [updater] returns `null` or `true`, listeners are notified.
void setValue(bool? Function(T) updater) {
void mutate(Function(T value) updater) {
var result = updater(value);
if (result == null || result) {
_notifier.notify();
if (result is T && result != value) {
value = result;
} else if (result == null || result == true) {
notifyListeners();
}
}

@override
void addListener(VoidCallback listener) {
_notifier.addListener(listener);
}

@override
void removeListener(VoidCallback listener) {
_notifier.removeListener(listener);
}
}

/// A notifier class that extends [ChangeNotifier] to provide custom notification logic.
class EventNotifier extends ChangeNotifier {
/// Notifies all registered listeners.
void notify() {
notifyListeners();
}

/// Creates a [ValueListenable] that hooks into the current notifier and provides a value.
ValueListenable<T> hookWithValue<T>(T Function() getValue) {
return _ValueHookListenable(getValue, this);
}
}

/// Extension on [ValueNotifier] to provide a read-only view.
Expand Down Expand Up @@ -79,25 +53,3 @@ class ValueNotifierUnmodifiableView<T> extends ValueListenable<T> {
_notifier.removeListener(listener);
}
}

/// A [ValueListenable] that hooks into an [EventNotifier] and provides a value.
class _ValueHookListenable<T> extends ValueListenable<T> {
final T Function() _getValue;
final EventNotifier _notifier;

/// Constructs a [_ValueHookListenable] with the given value getter and notifier.
_ValueHookListenable(this._getValue, this._notifier);

@override
T get value => _getValue();

@override
void addListener(VoidCallback listener) {
_notifier.addListener(listener);
}

@override
void removeListener(VoidCallback listener) {
_notifier.removeListener(listener);
}
}
27 changes: 3 additions & 24 deletions test/notifier_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ void main() {
list.addListener(() {
listenerCalled = true;
});
list.setValue((value) {
list.mutate((value) => value.add(12));
list.mutate((value) {
value.add(4);
return true;
});
Expand All @@ -22,23 +23,13 @@ void main() {
list.addListener(() {
listenerCalled = true;
});
list.setValue((value) {
list.mutate((value) {
value.add(4);
return false;
});
expect(listenerCalled, false);
});

test('EventNotifier test', () {
EventNotifier notifier = EventNotifier();
bool listenerCalled = false;
notifier.addListener(() {
listenerCalled = true;
});
notifier.notify();
expect(listenerCalled, true);
});

test('ValueNotifierExtension test', () {
ValueChangeNotifier<int> valueNotifier = ValueChangeNotifier(1);
ValueListenable<int> readOnly = valueNotifier.readOnly();
Expand All @@ -50,16 +41,4 @@ void main() {
valueNotifier.value = 2;
expect(listenerCalled, true);
});

test('EventNotifier hookWithValue test', () {
EventNotifier notifier = EventNotifier();
ValueListenable<int> valueListenable = notifier.hookWithValue(() => 1);
expect(valueListenable.value, 1);
bool listenerCalled = false;
valueListenable.addListener(() {
listenerCalled = true;
});
notifier.notify();
expect(listenerCalled, true);
});
}

0 comments on commit ad36500

Please sign in to comment.