Last active
May 18, 2022 21:42
-
-
Save tolo/cd4486cee11e0c799a1f11c2f9b9dbd4 to your computer and use it in GitHub Desktop.
RxNumPad (Flutter)
This file contains 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: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