Last active
August 31, 2025 02:15
-
-
Save dickermoshe/f9012c440e2dc1457e3e7b04b4888ac3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_solidart/flutter_solidart.dart'; | |
class SignalInputController extends Signal<TextEditingValue> | |
implements TextEditingController { | |
late final TextEditingController _controller; | |
late final Effect _effect; | |
SignalInputController({String? text}) | |
: super(TextEditingValue(text: text ?? "")) { | |
_controller = TextEditingController(text: text); | |
// Bind the internal controller to the signal and vice versa | |
_controller.addListener(() { | |
super.value = _controller.value; | |
}); | |
_effect = Effect(() { | |
_controller.value = super.value; | |
}); | |
} | |
// Ensure both listeners are disposed when the controller is disposed | |
@override | |
void dispose() { | |
_effect.dispose(); | |
super.dispose(); | |
} | |
// Read methods should register listeners by reading the value from the signal | |
@override | |
TextSelection get selection => super.value.selection; | |
@override | |
// Register listeners by reading the value from the signal | |
String get text => super.value.text; | |
@override | |
// This will always return true because the signal is always listening | |
// The ValueNotifier does not expose how many listeners it has | |
// It's a shame, becuase we could have done: _controller.listenerCount > 1 || super.listenerCount > 0; | |
bool get hasListeners => _controller.hasListeners; | |
@override | |
TextSpan buildTextSpan({ | |
required BuildContext context, | |
TextStyle? style, | |
required bool withComposing, | |
}) { | |
return _controller.buildTextSpan( | |
context: context, | |
style: style, | |
withComposing: withComposing, | |
); | |
} | |
@override | |
void addListener(VoidCallback listener) => _controller.addListener(listener); | |
@override | |
void clear() => _controller.clear(); | |
@override | |
void clearComposing() => _controller.clearComposing(); | |
@override | |
void notifyListeners() => _controller.notifyListeners(); | |
@override | |
void removeListener(VoidCallback listener) => | |
_controller.removeListener(listener); | |
@override | |
set selection(TextSelection newSelection) { | |
_controller.selection = newSelection; | |
} | |
@override | |
set text(String newText) { | |
_controller.text = newText; | |
} | |
} | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatefulWidget { | |
const MyApp({super.key}); | |
@override | |
State<MyApp> createState() => _MyAppState(); | |
} | |
class _MyAppState extends State<MyApp> { | |
late final SignalInputController _controller; | |
late final Computed<String> _computed; | |
@override | |
void initState() { | |
_controller = SignalInputController(text: 'Hello, World!'); | |
_computed = Computed(() => '${_controller.text} => I am computed!'); | |
super.initState(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
home: Scaffold( | |
body: Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
TextField(controller: _controller), | |
SignalBuilder( | |
builder: (context, child) { | |
return Text(_controller.text); | |
}, | |
), | |
SignalBuilder( | |
builder: (context, child) { | |
return Text(_computed.value); | |
}, | |
), | |
ElevatedButton( | |
onPressed: () { | |
_controller.text = 'Hello, World!'; | |
}, | |
child: const Text('Reset'), | |
), | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment