Add ValueTabController – generic feature!

pull/88/head
Kevin Moore 5 years ago
parent f87c2bb577
commit 62ffd22505

@ -12,6 +12,7 @@ import 'flutter.dart';
import 'puzzle_flow_delegate.dart';
import 'shared_theme.dart';
import 'themes.dart';
import 'value_tab_controller.dart';
class PuzzleHomeState extends State with TickerProviderStateMixin, AppState {
@override
@ -163,7 +164,8 @@ Widget _updateConstraints(
Widget _doBuild(BuildContext _, BoxConstraints constraints) =>
_updateConstraints(constraints, _doBuildCore);
Widget _doBuildCore(bool small) => PuzzleThemeTabController(
Widget _doBuildCore(bool small) => ValueTabController<SharedTheme>(
values: themes,
child: Consumer<SharedTheme>(
builder: (_, theme, __) => AnimatedContainer(
duration: puzzleAnimationDuration,
@ -190,8 +192,7 @@ Widget _doBuildCore(bool small) => PuzzleThemeTabController(
margin:
const EdgeInsets.symmetric(horizontal: 20),
child: TabBar(
controller:
PuzzleThemeTabController.of(context),
controller: ValueTabController.of(context),
labelPadding:
const EdgeInsets.fromLTRB(0, 20, 0, 12),
labelColor: theme.puzzleAccentColor,

@ -1,7 +1,3 @@
import 'package:flutter_web/material.dart';
import 'package:provider/provider.dart';
import 'shared_theme.dart';
import 'theme_plaster.dart';
import 'theme_seattle.dart';
import 'theme_simple.dart';
@ -11,86 +7,3 @@ const themes = [
ThemeSeattle(),
ThemePlaster(),
];
class PuzzleThemeTabController extends StatefulWidget {
/// Creates a default tab controller for the given [child] widget.
const PuzzleThemeTabController({
Key key,
@required this.child,
}) : super(key: key);
/// The widget below this widget in the tree.
///
/// Typically a [Scaffold] whose [AppBar] includes a [TabBar].
///
/// {@macro flutter.widgets.child}
final Widget child;
/// The closest instance of this class that encloses the given context.
///
/// Typical usage:
///
/// ```dart
/// TabController controller = DefaultTabBarController.of(context);
/// ```
static TabController of(BuildContext context) {
final scope =
context.inheritFromWidgetOfExactType(_PuzzleThemeTabControllerScope)
as _PuzzleThemeTabControllerScope;
return scope?.controller;
}
@override
_PuzzleThemeTabControllerState createState() =>
_PuzzleThemeTabControllerState();
}
class _PuzzleThemeTabControllerState extends State<PuzzleThemeTabController>
with SingleTickerProviderStateMixin {
final _notifier = ValueNotifier<SharedTheme>(themes.first);
TabController _controller;
@override
void initState() {
super.initState();
_controller = TabController(
vsync: this,
length: themes.length,
initialIndex: 0,
);
_controller.addListener(() {
_notifier.value = themes[_controller.index];
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => _PuzzleThemeTabControllerScope(
controller: _controller,
enabled: TickerMode.of(context),
child: ValueListenableProvider.value(
valueListenable: _notifier,
child: widget.child,
),
);
}
class _PuzzleThemeTabControllerScope extends InheritedWidget {
const _PuzzleThemeTabControllerScope(
{Key key, this.controller, this.enabled, Widget child})
: super(key: key, child: child);
final TabController controller;
final bool enabled;
@override
bool updateShouldNotify(_PuzzleThemeTabControllerScope old) =>
enabled != old.enabled || controller != old.controller;
}

@ -0,0 +1,88 @@
import 'package:flutter_web/material.dart';
import 'package:provider/provider.dart';
class ValueTabController<T> extends StatefulWidget {
/// Creates a default tab controller for the given [child] widget.
const ValueTabController({
Key key,
@required this.child,
@required this.values,
}) : super(key: key);
/// The widget below this widget in the tree.
///
/// Typically a [Scaffold] whose [AppBar] includes a [TabBar].
///
/// {@macro flutter.widgets.child}
final Widget child;
final List<T> values;
/// The closest instance of this class that encloses the given context.
///
/// Typical usage:
///
/// ```dart
/// TabController controller = DefaultTabBarController.of(context);
/// ```
static TabController of(BuildContext context) {
final scope = context.inheritFromWidgetOfExactType(_ValueTabControllerScope)
as _ValueTabControllerScope;
return scope?.controller;
}
@override
_ValueTabControllerState<T> createState() => _ValueTabControllerState<T>();
}
class _ValueTabControllerState<T> extends State<ValueTabController<T>>
with SingleTickerProviderStateMixin {
final _notifier = ValueNotifier<T>(null);
TabController _controller;
@override
void initState() {
super.initState();
_controller = TabController(
vsync: this,
length: widget.values.length,
initialIndex: 0,
);
_notifier.value = widget.values.first;
_controller.addListener(() {
_notifier.value = widget.values[_controller.index];
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => _ValueTabControllerScope(
controller: _controller,
enabled: TickerMode.of(context),
child: ValueListenableProvider.value(
valueListenable: _notifier,
child: widget.child,
),
);
}
class _ValueTabControllerScope extends InheritedWidget {
const _ValueTabControllerScope(
{Key key, this.controller, this.enabled, Widget child})
: super(key: key, child: child);
final TabController controller;
final bool enabled;
@override
bool updateShouldNotify(_ValueTabControllerScope old) =>
enabled != old.enabled || controller != old.controller;
}
Loading…
Cancel
Save