Skip to content

Instantly share code, notes, and snippets.

@SuperPenguin
Created January 7, 2023 13:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SuperPenguin/ae58b2cd2fd3d4a95c82ba512b72cfd2 to your computer and use it in GitHub Desktop.
Save SuperPenguin/ae58b2cd2fd3d4a95c82ba512b72cfd2 to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
late final TextEditingController _textController;
late final ValidateController _validateController;
@override
void initState() {
super.initState();
_textController = TextEditingController();
_validateController = ValidateController(textController: _textController);
}
@override
void dispose() {
_textController.dispose();
_validateController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
minimum: const EdgeInsets.all(8.0),
child: Column(
children: [
AnimatedBuilder(
animation: _validateController,
builder: (context, child) {
final snapshot = _validateController.errorTextSnapshot;
final errorText = snapshot.data;
return TextField(
controller: _textController,
decoration: InputDecoration(
errorText: errorText,
),
);
},
),
SizedBox(height: 8.0),
AnimatedBuilder(
animation: _validateController,
builder: (context, child) {
final snapshot = _validateController.errorTextSnapshot;
final isWaiting =
snapshot.connectionState != ConnectionState.done;
final hasError = snapshot.data != null;
if (isWaiting) {
return const CircularProgressIndicator.adaptive();
}
return ElevatedButton(
onPressed: !hasError ? () {} : null,
child: Text('Submit'),
);
},
),
],
),
),
);
}
}
class ValidateController with ChangeNotifier {
ValidateController({
required TextEditingController textController,
}) : _mounted = true,
_textController = textController {
_textController.addListener(_onTextChanged);
_validate();
}
bool _mounted;
bool get mounted => _mounted;
Timer? _timer;
void _onTextChanged() {
_timer?.cancel();
if (_errorTextSnapshot.connectionState != ConnectionState.waiting) {
_errorTextSnapshot = const AsyncSnapshot.waiting();
notifyListeners();
}
_timer = Timer(const Duration(milliseconds: 500), _validate);
}
Future<void> _validate() async {
final text = _textController.text;
final String? validateResult = await Future.delayed(
const Duration(seconds: 1),
() => text.length.isOdd ? 'Error!!!' : null,
);
print(validateResult);
final currentText = _textController.text;
if (!mounted || currentText != text) return;
_errorTextSnapshot =
AsyncSnapshot.withData(ConnectionState.done, validateResult);
notifyListeners();
}
final TextEditingController _textController;
AsyncSnapshot<String?> _errorTextSnapshot = const AsyncSnapshot.nothing();
AsyncSnapshot<String?> get errorTextSnapshot => _errorTextSnapshot;
@override
void dispose() {
_timer?.cancel();
_textController.removeListener(_onTextChanged);
_mounted = false;
super.dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment