import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:mnemo_cards/main.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:shared_preferences/shared_preferences.dart'; class SharedPrefButton extends StatefulWidget { final Function(T)? onClick; final String spKey; final T Function(T? current)? setOnTap; final bool Function(T? current)? shouldRebuild; final Widget Function(T? value, ValueSetter setValue)? builder; SharedPrefButton({ this.builder, required this.spKey, this.setOnTap, this.onClick, this.shouldRebuild, }); SharedPrefButton.builder({ this.builder, required this.spKey, this.setOnTap, this.onClick, this.shouldRebuild, }); @override State createState() => _SharedPrefButtonState(); } class _SharedPrefButtonState extends State> { SharedPreferences? _sp; T? value; StreamSubscription? _streamSubscription; @override void dispose() { _streamSubscription?.cancel(); _streamSubscription = null; super.dispose(); } @override void initState() { super.initState(); _sp = globalSharedPreferences; value = valueFromSp; _streamSubscription = Stream.periodic(const Duration(milliseconds: 500), (_) => valueFromSp) .distinct() .listen((v) { if (value != v) { value = v; if (mounted && widget.shouldRebuild?.call(value) != false) { setState(() {}); } } }); } T? get valueFromSp { if (T == bool) { return (_sp?.getBool(widget.spKey) ?? false).as(); } else if (T == int) { return _sp?.getInt(widget.spKey).as(); } else if (T == num || T == double) { return _sp?.getDouble(widget.spKey).as(); } else if (T == String) { return _sp?.getString(widget.spKey).as(); } else if (T == Iterable) { return _sp?.getStringList(widget.spKey).as(); } return null; } Future setValue(T value) async { if (T == bool) { _sp?.setBool(widget.spKey, value as bool); } else if (T == int) { _sp?.setInt(widget.spKey, value as int); } else if (T == num || T == double) { _sp?.setDouble(widget.spKey, value as double); } else if (T == String) { _sp?.setString(widget.spKey, value as String); } else if (T == Iterable) { _sp?.setStringList(widget.spKey, (value as Iterable).toList()); } } @override Widget build(BuildContext context) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: widget.setOnTap != null ? () async { value = widget.setOnTap!.call(value); if (value != null) { _setValue(value!); } } : null, child: widget.builder?.call(value, _setValue), ); } Future _setValue(T value) async { await setValue(value!); if (widget.shouldRebuild?.call(value) != false) { setState(() {}); } } }