Skip to content

Instantly share code, notes, and snippets.

@tolo
Last active May 18, 2022 21:42
Show Gist options
  • Save tolo/cd4486cee11e0c799a1f11c2f9b9dbd4 to your computer and use it in GitHub Desktop.
Save tolo/cd4486cee11e0c799a1f11c2f9b9dbd4 to your computer and use it in GitHub Desktop.
RxNumPad (Flutter)
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(RxNumPadApp());
}
const TheCorrectCode = '1234';
class ReactiveNumPad {
// TODO: --- REPAIR AREA BEGIN ---
Stream<int> setupSlowButton1(Stream<int> button1Stream) {
return button1Stream
// TODO: "Fix" slow button 1, by changing throttling window "edge" to leading instead of trailing
.throttleTime(Duration(milliseconds: 1000), leading: false, trailing: true);
//.throttleTime(Duration(milliseconds: 500), leading: true, trailing: false);
}
Stream<int> setupJitteryButton2(Stream<int> button2Stream) {
return button2Stream;
// TODO: "Fix" jittery button 2, by adding a debounceTime:
//return button2Stream.debounceTime(Duration(milliseconds: 100));
}
// TODO: --- REPAIR AREA END ---
void setupCodeValidator(Stream<int> tapStream) {
Stream<List<int>> tmp = tapStream.scan((acc, value, i) { // tapStream.bufferCount(4) also works
List<int> arr = [...acc, value];
if (arr.length > 4) arr.removeAt(0);
return arr;
}, []);
enteredCode = tmp.share();
correctCode = enteredCode.map((code) => code.join() == TheCorrectCode);
}
PublishSubject<void> btn1Wire = PublishSubject();
PublishSubject<void> btn2Wire = PublishSubject();
PublishSubject<void> btn3Wire = PublishSubject();
PublishSubject<void> btn4Wire = PublishSubject();
late Stream<List<int>> enteredCode;
late Stream<bool> correctCode;
ReactiveNumPad() {
Stream<int> taps = MergeStream([
setupSlowButton1(btn1Wire.map((e) => 1)),
setupJitteryButton2(
btn2Wire.map((e) => 2)
// Create some "jitter":
.flatMap((num) => Stream.periodic(Duration(milliseconds: 50)).take(3).map((e) => num))
),
btn3Wire.map((e) => 3),
btn4Wire.map((e) => 4),
]);
setupCodeValidator(taps);
}
void dispose() {
btn1Wire.close();
btn2Wire.close();
btn3Wire.close();
btn4Wire.close();
}
}
class RxNumPad extends StatefulWidget {
@override
_RxLabState createState() => _RxLabState();
}
class _RxLabState extends State<RxNumPad> {
final pad = ReactiveNumPad();
@override
void initState() {
super.initState();
}
@override
void dispose() {
pad.dispose();
super.dispose();
}
Widget body(BuildContext context) {
return Container(padding: EdgeInsets.all(16), child:
Column(children: [
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
ElevatedButton(onPressed: () => pad.btn1Wire.add(null), child: Text('1')),
SizedBox(width: 16),
ElevatedButton(onPressed: () => pad.btn2Wire.add(null), child: Text('2')),
]),
SizedBox(height: 8),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
ElevatedButton(onPressed: () => pad.btn3Wire.add(null), child: Text('3')),
SizedBox(width: 16),
ElevatedButton(onPressed: () => pad.btn4Wire.add(null), child: Text('4')),
]),
SizedBox(height: 24),
Text('RESULT:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 32)),
SizedBox(height: 8),
StreamBuilder<List<int>>(stream: pad.enteredCode, builder: (ctx, snapshot) {
final result = snapshot.data ?? [];
return
Column(children: [
Text('Entered code: ${result.join()}')
]);
}),
SizedBox(height: 8),
StreamBuilder<bool>(stream: pad.correctCode, builder: (ctx, snapshot) {
final correct = snapshot.data ?? false;
return
Column(children: [
if (correct) Text('CORRECT CODE', style: TextStyle(color: Colors.green, fontWeight: FontWeight.w900, fontSize: 24)),
if (!correct) Text('INCORRECT CODE! 🤬🤬🤬', style: TextStyle(color: Colors.redAccent, fontWeight: FontWeight.w900, fontSize: 24)),
]);
}),
])
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RxNumPad'),
),
body: Container(
alignment: Alignment.center,
color: Colors.deepPurpleAccent,
child:
DefaultTextStyle(
style: Theme.of(context).textTheme.bodyText1!.copyWith(color: Colors.white),
child: body(context),
)
),
);
}
}
class RxNumPadApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'RxNumPad',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RxNumPad(),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment