From 8bbe4a3f48a32014f3cfcad2efab75f9e57346c8 Mon Sep 17 00:00:00 2001 From: Niels Gorter Date: Tue, 29 Nov 2022 15:12:55 +0100 Subject: [PATCH] feat: changed input from specific to inputs from flutter_input_library --- CHANGELOG.md | 5 + example/pubspec.lock | 13 +- lib/flutter_form.dart | 2 + .../input_carousel/carousel_controller.dart | 150 ------- .../input_carousel/carousel_form.dart | 43 -- .../input_carousel/carousel_options.dart | 220 ----------- .../input_carousel/carousel_slider.dart | 358 ----------------- .../input_carousel/carousel_state.dart | 45 --- .../input_carousel/carousel_utils.dart | 27 -- .../input_carousel/input_carousel.dart | 5 +- .../input_date_picker/date_picker.dart | 150 ------- .../input_date_picker/input_date_picker.dart | 21 +- .../input/input_types/input_email.dart | 3 +- .../decimal_numberpicker.dart | 116 ------ .../infinite_listview.dart | 366 ------------------ .../input_number_picker.dart | 39 +- .../input_number_picker/numberpicker.dart | 309 --------------- .../input_password/input_password.dart | 15 +- .../input_types/input_password/password.dart | 54 --- .../input/input_types/input_plain_text.dart | 42 +- .../input_slider/input_slider.dart | 4 +- .../input_types/input_slider/slider.dart | 30 -- .../input_switch/input_switch.dart | 8 +- .../input_switch/input_switch_field.dart | 63 --- pubspec.yaml | 6 +- 25 files changed, 67 insertions(+), 2027 deletions(-) delete mode 100644 lib/src/widgets/input/input_types/input_carousel/carousel_controller.dart delete mode 100644 lib/src/widgets/input/input_types/input_carousel/carousel_form.dart delete mode 100644 lib/src/widgets/input/input_types/input_carousel/carousel_options.dart delete mode 100644 lib/src/widgets/input/input_types/input_carousel/carousel_slider.dart delete mode 100644 lib/src/widgets/input/input_types/input_carousel/carousel_state.dart delete mode 100644 lib/src/widgets/input/input_types/input_carousel/carousel_utils.dart delete mode 100644 lib/src/widgets/input/input_types/input_date_picker/date_picker.dart delete mode 100644 lib/src/widgets/input/input_types/input_number_picker/decimal_numberpicker.dart delete mode 100644 lib/src/widgets/input/input_types/input_number_picker/infinite_listview.dart delete mode 100644 lib/src/widgets/input/input_types/input_number_picker/numberpicker.dart delete mode 100644 lib/src/widgets/input/input_types/input_password/password.dart delete mode 100644 lib/src/widgets/input/input_types/input_slider/slider.dart delete mode 100644 lib/src/widgets/input/input_types/input_switch/input_switch_field.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c00ec2..e7cc80b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,3 +38,8 @@ ## 4.0.2 - November 29th 2022 - Name change to flutter_form_wizard + + +## 4.0.3 - November 29th 2022 + +- Change from input to `flutter_input_library` diff --git a/example/pubspec.lock b/example/pubspec.lock index 5347512..87f2829 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -61,7 +61,16 @@ packages: path: ".." relative: true source: path - version: "4.0.2" + version: "4.0.3" + flutter_input_library: + dependency: transitive + description: + path: "." + ref: "0.0.3" + resolved-ref: "739198b0b8b6fb80fa71dff8a2a11bdda67dcdd7" + url: "https://github.com/Iconica-Development/flutter_input_library" + source: git + version: "0.0.1" flutter_lints: dependency: "direct dev" description: @@ -204,5 +213,5 @@ packages: source: hosted version: "2.1.2" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=2.18.2 <3.0.0" flutter: ">=3.0.0" diff --git a/lib/flutter_form.dart b/lib/flutter_form.dart index 3b2a645..5e586a6 100644 --- a/lib/flutter_form.dart +++ b/lib/flutter_form.dart @@ -5,4 +5,6 @@ export 'src/form.dart'; export 'src/widgets/input/abstractions.dart'; export 'src/widgets/input/input_types/input_types.dart'; +export 'package:flutter_input_library/flutter_input_library.dart' + show FlutterFormDateTimeType; export 'utils/form.dart'; diff --git a/lib/src/widgets/input/input_types/input_carousel/carousel_controller.dart b/lib/src/widgets/input/input_types/input_carousel/carousel_controller.dart deleted file mode 100644 index e0e4c9f..0000000 --- a/lib/src/widgets/input/input_types/input_carousel/carousel_controller.dart +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import 'carousel_utils.dart'; -import 'carousel_options.dart'; -import 'carousel_state.dart'; - -abstract class CarouselController { - bool get ready; - - Future get onReady; - - Future nextPage({Duration? duration, Curve? curve}); - - Future previousPage({Duration? duration, Curve? curve}); - - void jumpToPage(int page); - - Future animateToPage(int page, {Duration? duration, Curve? curve}); - - void startAutoPlay(); - - void stopAutoPlay(); - - factory CarouselController() => CarouselControllerImpl(); -} - -class CarouselControllerImpl implements CarouselController { - final Completer _readyCompleter = Completer(); - - CarouselState? _state; - - set state(CarouselState? state) { - _state = state; - if (!_readyCompleter.isCompleted) { - _readyCompleter.complete(); - } - } - - void _setModeController() => - _state!.changeMode(CarouselPageChangedReason.controller); - - @override - bool get ready => _state != null; - - @override - Future get onReady => _readyCompleter.future; - - /// Animates the controlled [CarouselSlider] to the next page. - /// - /// The animation lasts for the given duration and follows the given curve. - /// The returned [Future] resolves when the animation completes. - @override - Future nextPage( - {Duration? duration = const Duration(milliseconds: 300), - Curve? curve = Curves.linear}) async { - final bool isNeedResetTimer = _state!.options.pauseAutoPlayOnManualNavigate; - if (isNeedResetTimer) { - _state!.onResetTimer(); - } - _setModeController(); - await _state!.pageController!.nextPage(duration: duration!, curve: curve!); - if (isNeedResetTimer) { - _state!.onResumeTimer(); - } - } - - /// Animates the controlled [CarouselSlider] to the previous page. - /// - /// The animation lasts for the given duration and follows the given curve. - /// The returned [Future] resolves when the animation completes. - @override - Future previousPage( - {Duration? duration = const Duration(milliseconds: 300), - Curve? curve = Curves.linear}) async { - final bool isNeedResetTimer = _state!.options.pauseAutoPlayOnManualNavigate; - if (isNeedResetTimer) { - _state!.onResetTimer(); - } - _setModeController(); - await _state!.pageController! - .previousPage(duration: duration!, curve: curve!); - if (isNeedResetTimer) { - _state!.onResumeTimer(); - } - } - - /// Changes which page is displayed in the controlled [CarouselSlider]. - /// - /// Jumps the page position from its current value to the given value, - /// without animation, and without checking if the new value is in range. - @override - void jumpToPage(int page) { - final index = getRealIndex(_state!.pageController!.page!.toInt(), - _state!.realPage - _state!.initialPage, _state!.itemCount); - - _setModeController(); - final int pageToJump = _state!.pageController!.page!.toInt() + page - index; - return _state!.pageController!.jumpToPage(pageToJump); - } - - /// Animates the controlled [CarouselSlider] from the current page to the - /// given page. - /// - /// The animation lasts for the given duration and follows the given curve. - /// The returned [Future] resolves when the animation completes. - @override - Future animateToPage(int page, - {Duration? duration = const Duration(milliseconds: 300), - Curve? curve = Curves.linear}) async { - final bool isNeedResetTimer = _state!.options.pauseAutoPlayOnManualNavigate; - if (isNeedResetTimer) { - _state!.onResetTimer(); - } - final index = getRealIndex(_state!.pageController!.page!.toInt(), - _state!.realPage - _state!.initialPage, _state!.itemCount); - _setModeController(); - await _state!.pageController!.animateToPage( - _state!.pageController!.page!.toInt() + page - index, - duration: duration!, - curve: curve!); - if (isNeedResetTimer) { - _state!.onResumeTimer(); - } - } - - /// Starts the controlled [CarouselSlider] autoplay. - /// - /// The carousel will only autoPlay if the [autoPlay] parameter - /// in [CarouselOptions] is true. - @override - void startAutoPlay() { - _state!.onResumeTimer(); - } - - /// Stops the controlled [CarouselSlider] from autoplaying. - /// - /// This is a more on-demand way of doing this. Use the [autoPlay] - /// parameter in [CarouselOptions] to specify the autoPlay behaviour of the - /// carousel. - @override - void stopAutoPlay() { - _state!.onResetTimer(); - } -} diff --git a/lib/src/widgets/input/input_types/input_carousel/carousel_form.dart b/lib/src/widgets/input/input_types/input_carousel/carousel_form.dart deleted file mode 100644 index 6bd482d..0000000 --- a/lib/src/widgets/input/input_types/input_carousel/carousel_form.dart +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'carousel_slider.dart'; - -class CarouselFormField extends FormField { - CarouselFormField({ - Key? key, - required FormFieldSetter onSaved, - required FormFieldValidator validator, - void Function(int value)? onChanged, - void Function(int value)? onSubmit, - int initialValue = 0, - bool autovalidate = false, - required List items, - double height = 425, - }) : super( - key: key, - onSaved: onSaved, - validator: validator, - initialValue: initialValue, - builder: (FormFieldState state) { - return CarouselSlider( - options: CarouselOptions( - initialPage: initialValue, - onPageChanged: (index, reason) { - onChanged?.call(index); - - state.didChange(index); - }, - height: height, - aspectRatio: 2.0, - enlargeCenterPage: true, - enableInfiniteScroll: false, - ), - items: items.map((Widget item) { - return item; - }).toList(), - ); - }); -} diff --git a/lib/src/widgets/input/input_types/input_carousel/carousel_options.dart b/lib/src/widgets/input/input_types/input_carousel/carousel_options.dart deleted file mode 100644 index f279d5f..0000000 --- a/lib/src/widgets/input/input_types/input_carousel/carousel_options.dart +++ /dev/null @@ -1,220 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; - -enum CarouselPageChangedReason { timed, manual, controller } - -enum CenterPageEnlargeStrategy { scale, height } - -class CarouselOptions { - /// Set carousel height and overrides any existing [aspectRatio]. - final double? height; - - /// Aspect ratio is used if no height have been declared. - /// - /// Defaults to 16:9 aspect ratio. - final double aspectRatio; - - /// The fraction of the viewport that each page should occupy. - /// - /// Defaults to 0.8, which means each page fills 80% of the carousel. - final double viewportFraction; - - /// The initial page to show when first creating the [CarouselSlider]. - /// - /// Defaults to 0. - final int initialPage; - - ///Determines if carousel should loop infinitely or be limited to item length. - /// - ///Defaults to true, i.e. infinite loop. - final bool enableInfiniteScroll; - - /// Reverse the order of items if set to true. - /// - /// Defaults to false. - final bool reverse; - - /// Enables auto play, sliding one page at a time. - /// - /// Use [autoPlayInterval] to determine the frequency of slides. - /// Defaults to false. - final bool autoPlay; - - /// Sets Duration to determine the frequency of slides when [autoPlay] is set - /// to true. - /// Defaults to 4 seconds. - final Duration autoPlayInterval; - - /// The animation duration between two transitioning pages while in auto - /// playback. - /// - /// Defaults to 800 ms. - final Duration autoPlayAnimationDuration; - - /// Determines the animation curve physics. - /// - /// Defaults to [Curves.fastOutSlowIn]. - final Curve autoPlayCurve; - - /// Determines if current page should be larger than the side images, - /// creating a feeling of depth in the carousel. - /// - /// Defaults to false. - final bool? enlargeCenterPage; - - /// The axis along which the page view scrolls. - /// - /// Defaults to [Axis.horizontal]. - final Axis scrollDirection; - - /// Called whenever the page in the center of the viewport changes. - final Function(int index, CarouselPageChangedReason reason)? onPageChanged; - - /// Called whenever the carousel is scrolled - final ValueChanged? onScrolled; - - /// How the carousel should respond to user input. - /// - /// For example, determines how the items continues to animate after the - /// user stops dragging the page view. - /// - /// The physics are modified to snap to page boundaries using - /// [PageScrollPhysics] prior to being used. - /// - /// Defaults to matching platform conventions. - final ScrollPhysics? scrollPhysics; - - /// Set to false to disable page snapping, useful for custom scroll behavior. - /// - /// Default to `true`. - final bool pageSnapping; - - /// If `true`, the auto play function will be paused when user is interacting - /// with the carousel, and will be resumed when user finish interacting. - /// - /// Default to `true`. - final bool pauseAutoPlayOnTouch; - - /// If `true`, the auto play function will be paused when user is calling - /// [PageController]'s [nextPage] or [previousPage] or [animateToPage] method. - /// And after the animation complete, the auto play will be resumed. - /// - /// Default to `true`. - final bool pauseAutoPlayOnManualNavigate; - - /// If [enableInfiniteScroll] is `false`, and [autoPlay] is `true`, this option - /// decide the carousel should go to the first item when it reach the last item or not. - /// If set to `true`, the auto play will be paused when it reach the last item. - /// If set to `false`, the auto play function will animate to the first item - /// when it was in the last item. - final bool pauseAutoPlayInFiniteScroll; - - /// Pass a [PageStorageKey] if you want to keep the pageview's position when - /// it was recreated. - final PageStorageKey? pageViewKey; - - /// Use [enlargeStrategy] to determine which method to enlarge the center page. - final CenterPageEnlargeStrategy enlargeStrategy; - - /// Whether or not to disable the [Center] widget for each slide. - final bool disableCenter; - - /// Whether to add padding to both ends of the list. - /// If this is set to true and [viewportFraction] < 1.0, padding will be added - /// such that the first and last child slivers will be in the center of the 1 - /// viewport when scrolled all the way to the start or end, respectively. - /// - /// If [viewportFraction] >= 1.0, this property has no effect. - /// This property defaults to true and must not be null. - final bool padEnds; - - /// Exposed [clipBehavior] of [PageView] - final Clip clipBehavior; - - CarouselOptions({ - this.height, - this.aspectRatio = 16 / 9, - this.viewportFraction = 0.8, - this.initialPage = 0, - this.enableInfiniteScroll = true, - this.reverse = false, - this.autoPlay = false, - this.autoPlayInterval = const Duration(seconds: 4), - this.autoPlayAnimationDuration = const Duration(milliseconds: 800), - this.autoPlayCurve = Curves.fastOutSlowIn, - this.enlargeCenterPage = false, - this.onPageChanged, - this.onScrolled, - this.scrollPhysics, - this.pageSnapping = true, - this.scrollDirection = Axis.horizontal, - this.pauseAutoPlayOnTouch = true, - this.pauseAutoPlayOnManualNavigate = true, - this.pauseAutoPlayInFiniteScroll = false, - this.pageViewKey, - this.enlargeStrategy = CenterPageEnlargeStrategy.scale, - this.disableCenter = false, - this.padEnds = true, - this.clipBehavior = Clip.hardEdge, - }); - - ///Generate new [CarouselOptions] based on old ones. - - CarouselOptions copyWith( - {double? height, - double? aspectRatio, - double? viewportFraction, - int? initialPage, - bool? enableInfiniteScroll, - bool? reverse, - bool? autoPlay, - Duration? autoPlayInterval, - Duration? autoPlayAnimationDuration, - Curve? autoPlayCurve, - bool? enlargeCenterPage, - Function(int index, CarouselPageChangedReason reason)? onPageChanged, - ValueChanged? onScrolled, - ScrollPhysics? scrollPhysics, - bool? pageSnapping, - Axis? scrollDirection, - bool? pauseAutoPlayOnTouch, - bool? pauseAutoPlayOnManualNavigate, - bool? pauseAutoPlayInFiniteScroll, - PageStorageKey? pageViewKey, - CenterPageEnlargeStrategy? enlargeStrategy, - bool? disableCenter, - Clip? clipBehavior, - bool? padEnds}) => - CarouselOptions( - height: height ?? this.height, - aspectRatio: aspectRatio ?? this.aspectRatio, - viewportFraction: viewportFraction ?? this.viewportFraction, - initialPage: initialPage ?? this.initialPage, - enableInfiniteScroll: enableInfiniteScroll ?? this.enableInfiniteScroll, - reverse: reverse ?? this.reverse, - autoPlay: autoPlay ?? this.autoPlay, - autoPlayInterval: autoPlayInterval ?? this.autoPlayInterval, - autoPlayAnimationDuration: - autoPlayAnimationDuration ?? this.autoPlayAnimationDuration, - autoPlayCurve: autoPlayCurve ?? this.autoPlayCurve, - enlargeCenterPage: enlargeCenterPage ?? this.enlargeCenterPage, - onPageChanged: onPageChanged ?? this.onPageChanged, - onScrolled: onScrolled ?? this.onScrolled, - scrollPhysics: scrollPhysics ?? this.scrollPhysics, - pageSnapping: pageSnapping ?? this.pageSnapping, - scrollDirection: scrollDirection ?? this.scrollDirection, - pauseAutoPlayOnTouch: pauseAutoPlayOnTouch ?? this.pauseAutoPlayOnTouch, - pauseAutoPlayOnManualNavigate: - pauseAutoPlayOnManualNavigate ?? this.pauseAutoPlayOnManualNavigate, - pauseAutoPlayInFiniteScroll: - pauseAutoPlayInFiniteScroll ?? this.pauseAutoPlayInFiniteScroll, - pageViewKey: pageViewKey ?? this.pageViewKey, - enlargeStrategy: enlargeStrategy ?? this.enlargeStrategy, - disableCenter: disableCenter ?? this.disableCenter, - clipBehavior: clipBehavior ?? this.clipBehavior, - padEnds: padEnds ?? this.padEnds, - ); -} diff --git a/lib/src/widgets/input/input_types/input_carousel/carousel_slider.dart b/lib/src/widgets/input/input_types/input_carousel/carousel_slider.dart deleted file mode 100644 index 209a899..0000000 --- a/lib/src/widgets/input/input_types/input_carousel/carousel_slider.dart +++ /dev/null @@ -1,358 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -library carousel_slider; - -import 'dart:async'; - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'carousel_state.dart'; -import 'carousel_utils.dart'; - -import 'carousel_controller.dart'; -import 'carousel_options.dart'; - -export 'carousel_controller.dart'; -export 'carousel_options.dart'; - -typedef ExtendedIndexedWidgetBuilder = Widget Function( - BuildContext context, int index, int realIndex); - -class CarouselSlider extends StatefulWidget { - /// [CarouselOptions] to create a [CarouselState] with. - final CarouselOptions options; - - /// The widgets to be shown in the carousel of default constructor. - final List? items; - - /// The widget item builder that will be used to build item on demand - /// The third argument is the [PageView]'s real index, can be used to cooperate - /// with Hero. - final ExtendedIndexedWidgetBuilder? itemBuilder; - - /// A [MapController], used to control the map. - final CarouselControllerImpl _carouselController; - - final int? itemCount; - - CarouselSlider( - {required this.items, - required this.options, - CarouselController? carouselController, - Key? key}) - : itemBuilder = null, - itemCount = items != null ? items.length : 0, - _carouselController = carouselController != null - ? carouselController as CarouselControllerImpl - : CarouselController() as CarouselControllerImpl, - super(key: key); - - /// The on demand item builder constructor/ - CarouselSlider.builder( - {required this.itemCount, - required this.itemBuilder, - required this.options, - CarouselController? carouselController, - Key? key}) - : items = null, - _carouselController = carouselController != null - ? carouselController as CarouselControllerImpl - : CarouselController() as CarouselControllerImpl, - super(key: key); - - @override - CarouselSliderState createState() => CarouselSliderState(); -} - -class CarouselSliderState extends State - with TickerProviderStateMixin { - late CarouselControllerImpl carouselController; - Timer? timer; - - CarouselOptions get options => widget.options; - - CarouselState? carouselState; - - PageController? pageController; - - /// [mode] is related to why the page is being changed. - CarouselPageChangedReason mode = CarouselPageChangedReason.controller; - - CarouselSliderState(); - - void changeMode(CarouselPageChangedReason mode) { - this.mode = mode; - } - - @override - void didUpdateWidget(CarouselSlider oldWidget) { - carouselState!.options = options; - carouselState!.itemCount = widget.itemCount; - - /// [pageController] needs to be re-initialized to respond to state changes. - pageController = PageController( - viewportFraction: options.viewportFraction, - initialPage: carouselState!.realPage, - ); - carouselState!.pageController = pageController; - - /// handle autoplay when state changes - handleAutoPlay(); - - super.didUpdateWidget(oldWidget); - } - - @override - void initState() { - super.initState(); - carouselController = widget._carouselController; - - carouselState = CarouselState(options, clearTimer, resumeTimer, changeMode); - - carouselState!.itemCount = widget.itemCount; - carouselController.state = carouselState; - carouselState!.initialPage = widget.options.initialPage; - carouselState!.realPage = options.enableInfiniteScroll - ? carouselState!.realPage + carouselState!.initialPage - : carouselState!.initialPage; - handleAutoPlay(); - - pageController = PageController( - viewportFraction: options.viewportFraction, - initialPage: carouselState!.realPage, - ); - - carouselState!.pageController = pageController; - } - - Timer? getTimer() { - return widget.options.autoPlay - ? Timer.periodic(widget.options.autoPlayInterval, (_) { - final route = ModalRoute.of(context); - if (route?.isCurrent == false) { - return; - } - - CarouselPageChangedReason previousReason = mode; - changeMode(CarouselPageChangedReason.timed); - int nextPage = carouselState!.pageController!.page!.round() + 1; - int itemCount = widget.itemCount ?? widget.items!.length; - - if (nextPage >= itemCount && - widget.options.enableInfiniteScroll == false) { - if (widget.options.pauseAutoPlayInFiniteScroll) { - clearTimer(); - return; - } - nextPage = 0; - } - - carouselState!.pageController! - .animateToPage(nextPage, - duration: widget.options.autoPlayAnimationDuration, - curve: widget.options.autoPlayCurve) - .then((_) => changeMode(previousReason)); - }) - : null; - } - - void clearTimer() { - if (timer != null) { - timer?.cancel(); - timer = null; - } - } - - void resumeTimer() { - timer ??= getTimer(); - } - - void handleAutoPlay() { - bool autoPlayEnabled = widget.options.autoPlay; - - if (autoPlayEnabled && timer != null) return; - - clearTimer(); - if (autoPlayEnabled) { - resumeTimer(); - } - } - - Widget getGestureWrapper(Widget child) { - Widget wrapper; - if (widget.options.height != null) { - wrapper = SizedBox(height: widget.options.height, child: child); - } else { - wrapper = - AspectRatio(aspectRatio: widget.options.aspectRatio, child: child); - } - - return RawGestureDetector( - gestures: { - _MultipleGestureRecognizer: - GestureRecognizerFactoryWithHandlers<_MultipleGestureRecognizer>( - () => _MultipleGestureRecognizer(), - (_MultipleGestureRecognizer instance) { - instance.onStart = (_) { - onStart(); - }; - instance.onDown = (_) { - onPanDown(); - }; - instance.onEnd = (_) { - onPanUp(); - }; - instance.onCancel = () { - onPanUp(); - }; - }), - }, - child: NotificationListener( - onNotification: (Notification notification) { - if (widget.options.onScrolled != null && - notification is ScrollUpdateNotification) { - widget.options.onScrolled!(carouselState!.pageController!.page); - } - return false; - }, - child: wrapper, - ), - ); - } - - Widget getCenterWrapper(Widget child) { - if (widget.options.disableCenter) { - return Container( - child: child, - ); - } - return Center(child: child); - } - - Widget getEnlargeWrapper(Widget? child, - {double? width, double? height, double? scale}) { - if (widget.options.enlargeStrategy == CenterPageEnlargeStrategy.height) { - return SizedBox(width: width, height: height, child: child); - } - return Transform.scale( - scale: scale!, - child: SizedBox(width: width, height: height, child: child)); - } - - void onStart() { - changeMode(CarouselPageChangedReason.manual); - } - - void onPanDown() { - if (widget.options.pauseAutoPlayOnTouch) { - clearTimer(); - } - - changeMode(CarouselPageChangedReason.manual); - } - - void onPanUp() { - if (widget.options.pauseAutoPlayOnTouch) { - resumeTimer(); - } - } - - @override - void dispose() { - super.dispose(); - clearTimer(); - } - - @override - Widget build(BuildContext context) { - return getGestureWrapper(PageView.builder( - padEnds: widget.options.padEnds, - scrollBehavior: ScrollConfiguration.of(context).copyWith( - scrollbars: false, - overscroll: false, - dragDevices: {PointerDeviceKind.touch, PointerDeviceKind.mouse}, - ), - clipBehavior: widget.options.clipBehavior, - physics: widget.options.scrollPhysics, - scrollDirection: widget.options.scrollDirection, - pageSnapping: widget.options.pageSnapping, - controller: carouselState!.pageController, - reverse: widget.options.reverse, - itemCount: widget.options.enableInfiniteScroll ? null : widget.itemCount, - key: widget.options.pageViewKey, - onPageChanged: (int index) { - int currentPage = getRealIndex(index + carouselState!.initialPage, - carouselState!.realPage, widget.itemCount); - if (widget.options.onPageChanged != null) { - widget.options.onPageChanged!(currentPage, mode); - } - }, - itemBuilder: (BuildContext context, int idx) { - final int index = getRealIndex(idx + carouselState!.initialPage, - carouselState!.realPage, widget.itemCount); - - return AnimatedBuilder( - animation: carouselState!.pageController!, - child: (widget.items != null) - ? (widget.items!.isNotEmpty ? widget.items![index] : Container()) - : widget.itemBuilder!(context, index, idx), - builder: (BuildContext context, child) { - double distortionValue = 1.0; - // if [enlargeCenterPage] is true, we must calculate the carousel item's height - // to display the visual effect - - if (widget.options.enlargeCenterPage != null && - widget.options.enlargeCenterPage == true) { - // [pageController.page] can only be accessed after the first build, - // so in the first build we calculate the [itemOffset] manually - double itemOffset = 0; - var position = carouselState?.pageController?.position; - if (position != null && - position.hasPixels && - position.hasContentDimensions) { - var page = carouselState?.pageController?.page; - if (page != null) { - itemOffset = page - idx; - } - } else { - BuildContext storageContext = carouselState! - .pageController!.position.context.storageContext; - final double? previousSavedPosition = - PageStorage.of(storageContext)?.readState(storageContext) - as double?; - if (previousSavedPosition != null) { - itemOffset = previousSavedPosition - idx.toDouble(); - } else { - itemOffset = - carouselState!.realPage.toDouble() - idx.toDouble(); - } - } - - final num distortionRatio = - (1 - (itemOffset.abs() * 0.3)).clamp(0.0, 1.0); - distortionValue = - Curves.easeOut.transform(distortionRatio as double); - } - - final double height = widget.options.height ?? - MediaQuery.of(context).size.width * - (1 / widget.options.aspectRatio); - - if (widget.options.scrollDirection == Axis.horizontal) { - return getCenterWrapper(getEnlargeWrapper(child, - height: distortionValue * height, scale: distortionValue)); - } else { - return getCenterWrapper(getEnlargeWrapper(child, - width: distortionValue * MediaQuery.of(context).size.width, - scale: distortionValue)); - } - }, - ); - }, - )); - } -} - -class _MultipleGestureRecognizer extends PanGestureRecognizer {} diff --git a/lib/src/widgets/input/input_types/input_carousel/carousel_state.dart b/lib/src/widgets/input/input_types/input_carousel/carousel_state.dart deleted file mode 100644 index 6410931..0000000 --- a/lib/src/widgets/input/input_types/input_carousel/carousel_state.dart +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'carousel_slider.dart'; - -class CarouselState { - /// The [CarouselOptions] to create this state - CarouselOptions options; - - /// [pageController] is created using the properties passed to the constructor - /// and can be used to control the [PageView] it is passed to. - PageController? pageController; - - /// The actual index of the [PageView]. - /// - /// This value can be ignored unless you know the carousel will be scrolled - /// backwards more then 10000 pages. - /// Defaults to 10000 to simulate infinite backwards scrolling. - int realPage = 10000; - - /// The initial index of the [PageView] on [CarouselSlider] init. - /// - int initialPage = 0; - - /// The widgets count that should be shown at carousel - int? itemCount; - - /// Will be called when using [pageController] to go to next page or - /// previous page. It will clear the autoPlay timer. - /// Internal use only - Function onResetTimer; - - /// Will be called when using pageController to go to next page or - /// previous page. It will restart the autoPlay timer. - /// Internal use only - Function onResumeTimer; - - /// The callback to set the Reason Carousel changed - Function(CarouselPageChangedReason) changeMode; - - CarouselState( - this.options, this.onResetTimer, this.onResumeTimer, this.changeMode); -} diff --git a/lib/src/widgets/input/input_types/input_carousel/carousel_utils.dart b/lib/src/widgets/input/input_types/input_carousel/carousel_utils.dart deleted file mode 100644 index 7d96007..0000000 --- a/lib/src/widgets/input/input_types/input_carousel/carousel_utils.dart +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -/// Converts an index of a set size to the corresponding index of a collection of another size -/// as if they were circular. -/// -/// Takes a [position] from collection Foo, a [base] from where Foo's index originated -/// and the [length] of a second collection Baa, for which the correlating index is sought. -/// -/// For example; We have a Carousel of 10000(simulating infinity) but only 6 images. -/// We need to repeat the images to give the illusion of a never ending stream. -/// By calling [getRealIndex] with position and base we get an offset. -/// This offset modulo our length, 6, will return a number between 0 and 5, which represent the image -/// to be placed in the given position. -int getRealIndex(int position, int base, int? length) { - final int offset = position - base; - return remainder(offset, length); -} - -/// Returns the remainder of the modulo operation [input] % [source], and adjust it for -/// negative values. -int remainder(int input, int? source) { - if (source == 0) return 0; - final int result = input % source!; - return result < 0 ? source + result : result; -} diff --git a/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart b/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart index 11ea803..3f5680b 100644 --- a/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart +++ b/lib/src/widgets/input/input_types/input_carousel/input_carousel.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_wizard/utils/translation_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_form_wizard/flutter_form.dart'; - -import 'carousel_form.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; /// Input for a carousel of items used in a [FlutterForm]. /// @@ -35,7 +34,7 @@ class FlutterFormInputCarousel extends FlutterFormInputWidget { super.registerController(context); - return CarouselFormField( + return input.FlutterFormInputCarousel( onSaved: (value) => controller.onSaved(value), validator: (value) => controller.onValidate(value, _), onChanged: controller.onChanged, diff --git a/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart b/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart deleted file mode 100644 index 3419049..0000000 --- a/lib/src/widgets/input/input_types/input_date_picker/date_picker.dart +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_form_wizard/utils/translation_service.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:intl/intl.dart'; -import '../../../../../flutter_form.dart'; - -/// Generates a [DateTimeInputField] for DateTimes/Dates/Times/DateRanges. -/// It requires a [FlutterFormInputController], [inputType], [dateFormat], [firstDate], and [lastDate] -class DateTimeInputField extends ConsumerStatefulWidget { - const DateTimeInputField({ - Key? key, - required this.inputType, - required this.controller, - this.label, - this.showIcon = true, - this.icon, - required this.dateFormat, - required this.firstDate, - required this.lastDate, - this.initialDate, - this.initialDateTimeRange, - }) : super( - key: key, - ); - final FlutterFormDateTimeType inputType; - final FlutterFormInputController controller; - final DateFormat dateFormat; - final bool showIcon; - final DateTime? firstDate; - final DateTime? lastDate; - final DateTime? initialDate; - final DateTimeRange? initialDateTimeRange; - final IconData? icon; - final Widget? label; - @override - ConsumerState createState() => _DateInputFieldState(); -} - -class _DateInputFieldState extends ConsumerState { - late final DateTime firstDate; - late final DateTime lastDate; - late final DateTime initialDate; - late final DateTimeRange initialDateRange; - - @override - void initState() { - firstDate = widget.firstDate ?? - DateTime.now().subtract( - const Duration(days: 1000), - ); - lastDate = widget.lastDate ?? - DateTime.now().add( - const Duration(days: 1000), - ); - initialDate = widget.initialDate ?? DateTime.now(); - initialDateRange = widget.initialDateTimeRange ?? - DateTimeRange( - start: DateTime.now(), - end: DateTime.now().add( - const Duration(days: 7), - ), - ); - - super.initState(); - } - - @override - Widget build(BuildContext context) { - String Function(String, {List? params}) _ = - getTranslator(context, ref); - - Future getInputFromUser(FlutterFormDateTimeType inputType) async { - String userInput = ''; - switch (inputType) { - case FlutterFormDateTimeType.date: - DateTime? unformatted = await showDatePicker( - initialDate: initialDate, - context: context, - firstDate: firstDate, - lastDate: lastDate, - ); - userInput = unformatted != null - ? widget.dateFormat.format(unformatted) - : userInput; - break; - case FlutterFormDateTimeType.dateTime: - await getInputFromUser(FlutterFormDateTimeType.date) - .then((value) async { - if (value != '') { - String secondInput = - await getInputFromUser(FlutterFormDateTimeType.time); - if (secondInput != '') { - userInput = '$value $secondInput'; - } - } - }); - break; - case FlutterFormDateTimeType.range: - userInput = (await showDateRangePicker( - context: context, - firstDate: firstDate, - lastDate: lastDate, - initialDateRange: initialDateRange) - .then((value) { - return value != null - ? '${widget.dateFormat.format(value.start)} - ${widget.dateFormat.format(value.end)}' - : ''; - })) - .toString(); - break; - case FlutterFormDateTimeType.time: - userInput = await showTimePicker( - context: context, initialTime: TimeOfDay.now()) - .then((value) => value == null ? '' : value.format(context)); - } - return userInput; - } - - return TextFormField( - keyboardType: TextInputType.none, - readOnly: true, - key: Key(widget.controller.value.toString()), - initialValue: widget.controller.value, - onSaved: (value) { - widget.controller.onSaved(value); - }, - onTap: () async { - String userInput = await getInputFromUser(widget.inputType); - setState(() { - widget.controller.value = - userInput != '' ? userInput : widget.controller.value; - widget.controller.onChanged - ?.call(userInput != '' ? userInput : widget.controller.value); - }); - }, - validator: (value) => widget.controller.onValidate(value, _), - decoration: InputDecoration( - suffixIcon: widget.showIcon ? Icon(widget.icon) : null, - focusColor: Theme.of(context).primaryColor, - label: widget.label ?? const Text("Date"), - ), - ); - } -} diff --git a/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart b/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart index 7b98e8d..bbb85df 100644 --- a/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart +++ b/lib/src/widgets/input/input_types/input_date_picker/input_date_picker.dart @@ -3,21 +3,13 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; -import 'package:flutter_form_wizard/src/widgets/input/input_types/input_date_picker/date_picker.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_form_wizard/utils/translation_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import '../../../../../flutter_form.dart'; -/// Select Input Types in a [FlutterFormInputDateTime] -enum FlutterFormDateTimeType { - date, - time, - dateTime, - range, -} - /// Input for a dateTime used in a [FlutterForm]. /// /// Standard controller is [FlutterFormInputDateController]. @@ -40,7 +32,7 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget { label: label, ); final bool showIcon; - final FlutterFormDateTimeType inputType; + final input.FlutterFormDateTimeType inputType; final DateFormat dateFormat; final DateTime? initialDate; final DateTimeRange? initialDateTimeRange; @@ -54,13 +46,16 @@ class FlutterFormInputDateTime extends FlutterFormInputWidget { getTranslator(context, ref); super.registerController(context); - return DateTimeInputField( + return input.FlutterFormInputDateTime( label: label, icon: icon, firstDate: firstDate, lastDate: lastDate, inputType: inputType, - controller: controller, + onChanged: (value) => controller.onChanged?.call(value), + onSaved: (value) => controller.onSaved(value), + validator: (value) => controller.onValidate(value, _), + initialValue: controller.value, dateFormat: dateFormat, initialDate: initialDate, initialDateTimeRange: initialDateTimeRange, @@ -89,7 +84,7 @@ class FlutterFormInputDateTimeController final DateTime? initialDate; final DateTimeRange? initialDateTimeRange; final DateFormat dateFormat; - final FlutterFormDateTimeType dateTimeType; + final input.FlutterFormDateTimeType dateTimeType; @override String? id; diff --git a/lib/src/widgets/input/input_types/input_email.dart b/lib/src/widgets/input/input_types/input_email.dart index b49b4d7..1a95943 100644 --- a/lib/src/widgets/input/input_types/input_email.dart +++ b/lib/src/widgets/input/input_types/input_email.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_wizard/utils/translation_service.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../flutter_form.dart'; @@ -29,7 +30,7 @@ class FlutterFormInputEmail extends FlutterFormInputWidget { super.registerController(context); - return TextFormField( + return input.FlutterFormInputPlainText( initialValue: controller.value, onSaved: (value) { controller.onSaved(value); diff --git a/lib/src/widgets/input/input_types/input_number_picker/decimal_numberpicker.dart b/lib/src/widgets/input/input_types/input_number_picker/decimal_numberpicker.dart deleted file mode 100644 index 0421122..0000000 --- a/lib/src/widgets/input/input_types/input_number_picker/decimal_numberpicker.dart +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'dart:math' as math; - -import 'package:flutter/material.dart'; - -import 'numberpicker.dart'; - -class DecimalNumberPicker extends StatelessWidget { - final int minValue; - final int maxValue; - final double value; - final ValueChanged onChanged; - final int itemCount; - final double itemHeight; - final double itemWidth; - final Axis axis; - final TextStyle? textStyle; - final TextStyle? selectedTextStyle; - final bool haptics; - final TextMapper? integerTextMapper; - final TextMapper? decimalTextMapper; - final bool integerZeroPad; - - /// Decoration to apply to central box where the selected integer value is placed - final Decoration? integerDecoration; - - /// Decoration to apply to central box where the selected decimal value is placed - final Decoration? decimalDecoration; - - /// Inidcates how many decimal places to show - /// e.g. 0=>[1,2,3...], 1=>[1.0, 1.1, 1.2...] 2=>[1.00, 1.01, 1.02...] - final int decimalPlaces; - - const DecimalNumberPicker({ - Key? key, - required this.minValue, - required this.maxValue, - required this.value, - required this.onChanged, - this.itemCount = 3, - this.itemHeight = 50, - this.itemWidth = 100, - this.axis = Axis.vertical, - this.textStyle, - this.selectedTextStyle, - this.haptics = false, - this.decimalPlaces = 1, - this.integerTextMapper, - this.decimalTextMapper, - this.integerZeroPad = false, - this.integerDecoration, - this.decimalDecoration, - }) : assert(minValue <= value), - assert(value <= maxValue), - super(key: key); - - @override - Widget build(BuildContext context) { - final isMax = value.floor() == maxValue; - final decimalValue = isMax - ? 0 - : ((value - value.floorToDouble()) * math.pow(10, decimalPlaces)) - .round(); - final doubleMaxValue = isMax ? 0 : math.pow(10, decimalPlaces).toInt() - 1; - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - NumberPicker( - minValue: minValue, - maxValue: maxValue, - value: value.floor(), - onChanged: _onIntChanged, - itemCount: itemCount, - itemHeight: itemHeight, - itemWidth: itemWidth, - textStyle: textStyle, - selectedTextStyle: selectedTextStyle, - haptics: haptics, - zeroPad: integerZeroPad, - textMapper: integerTextMapper, - decoration: integerDecoration, - ), - NumberPicker( - minValue: 0, - maxValue: doubleMaxValue, - value: decimalValue, - onChanged: _onDoubleChanged, - itemCount: itemCount, - itemHeight: itemHeight, - itemWidth: itemWidth, - textStyle: textStyle, - selectedTextStyle: selectedTextStyle, - haptics: haptics, - textMapper: decimalTextMapper, - decoration: decimalDecoration, - ), - ], - ); - } - - void _onIntChanged(int intValue) { - final newValue = - (value - value.floor() + intValue).clamp(minValue, maxValue); - onChanged(newValue.toDouble()); - } - - void _onDoubleChanged(int doubleValue) { - final decimalPart = double.parse( - (doubleValue * math.pow(10, -decimalPlaces)) - .toStringAsFixed(decimalPlaces)); - onChanged(value.floor() + decimalPart); - } -} diff --git a/lib/src/widgets/input/input_types/input_number_picker/infinite_listview.dart b/lib/src/widgets/input/input_types/input_number_picker/infinite_listview.dart deleted file mode 100644 index e505666..0000000 --- a/lib/src/widgets/input/input_types/input_number_picker/infinite_listview.dart +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -library infinite_listview; - -import 'dart:math' as math; - -import 'package:flutter/gestures.dart' show DragStartBehavior; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; - -/// Infinite ListView -/// -/// ListView that builds its children with to an infinite extent. -/// -class InfiniteListView extends StatefulWidget { - /// See [ListView.builder] - const InfiniteListView.builder({ - Key? key, - this.scrollDirection = Axis.vertical, - this.reverse = false, - this.controller, - this.physics, - this.padding, - this.itemExtent, - required this.itemBuilder, - this.itemCount, - this.addAutomaticKeepAlives = true, - this.addRepaintBoundaries = true, - this.addSemanticIndexes = true, - this.cacheExtent, - this.anchor = 0.0, - this.dragStartBehavior = DragStartBehavior.start, - this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, - this.restorationId, - this.clipBehavior = Clip.hardEdge, - }) : separatorBuilder = null, - super(key: key); - - /// See [ListView.separated] - const InfiniteListView.separated({ - Key? key, - this.scrollDirection = Axis.vertical, - this.reverse = false, - this.controller, - this.physics, - this.padding, - required this.itemBuilder, - required this.separatorBuilder, - this.itemCount, - this.addAutomaticKeepAlives = true, - this.addRepaintBoundaries = true, - this.addSemanticIndexes = true, - this.cacheExtent, - this.anchor = 0.0, - this.dragStartBehavior = DragStartBehavior.start, - this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, - this.restorationId, - this.clipBehavior = Clip.hardEdge, - }) : itemExtent = null, - super(key: key); - - /// See: [ScrollView.scrollDirection] - final Axis scrollDirection; - - /// See: [ScrollView.reverse] - final bool reverse; - - /// See: [ScrollView.controller] - final InfiniteScrollController? controller; - - /// See: [ScrollView.physics] - final ScrollPhysics? physics; - - /// See: [BoxScrollView.padding] - final EdgeInsets? padding; - - /// See: [ListView.builder] - final IndexedWidgetBuilder itemBuilder; - - /// See: [ListView.separated] - final IndexedWidgetBuilder? separatorBuilder; - - /// See: [SliverChildBuilderDelegate.childCount] - final int? itemCount; - - /// See: [ListView.itemExtent] - final double? itemExtent; - - /// See: [ScrollView.cacheExtent] - final double? cacheExtent; - - /// See: [ScrollView.anchor] - final double anchor; - - /// See: [SliverChildBuilderDelegate.addAutomaticKeepAlives] - final bool addAutomaticKeepAlives; - - /// See: [SliverChildBuilderDelegate.addRepaintBoundaries] - final bool addRepaintBoundaries; - - /// See: [SliverChildBuilderDelegate.addSemanticIndexes] - final bool addSemanticIndexes; - - /// See: [ScrollView.dragStartBehavior] - final DragStartBehavior dragStartBehavior; - - /// See: [ScrollView.keyboardDismissBehavior] - final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior; - - /// See: [ScrollView.restorationId] - final String? restorationId; - - /// See: [ScrollView.clipBehavior] - final Clip clipBehavior; - - @override - InfiniteListViewState createState() => InfiniteListViewState(); -} - -class InfiniteListViewState extends State { - InfiniteScrollController? _controller; - - InfiniteScrollController get _effectiveController => - widget.controller ?? _controller!; - - @override - void initState() { - super.initState(); - if (widget.controller == null) { - _controller = InfiniteScrollController(); - } - } - - @override - void didUpdateWidget(InfiniteListView oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.controller == null && oldWidget.controller != null) { - _controller = InfiniteScrollController(); - } else if (widget.controller != null && oldWidget.controller == null) { - _controller!.dispose(); - _controller = null; - } - } - - @override - void dispose() { - _controller?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final List slivers = _buildSlivers(context, negative: false); - final List negativeSlivers = _buildSlivers(context, negative: true); - final AxisDirection axisDirection = _getDirection(context); - final scrollPhysics = - widget.physics ?? const AlwaysScrollableScrollPhysics(); - return Scrollable( - axisDirection: axisDirection, - controller: _effectiveController, - physics: scrollPhysics, - viewportBuilder: (BuildContext context, ViewportOffset offset) { - return Builder(builder: (BuildContext context) { - /// Build negative [ScrollPosition] for the negative scrolling [Viewport]. - final state = Scrollable.of(context)!; - final negativeOffset = _InfiniteScrollPosition( - physics: scrollPhysics, - context: state, - initialPixels: -offset.pixels, - keepScrollOffset: _effectiveController.keepScrollOffset, - negativeScroll: true, - ); - - /// Keep the negative scrolling [Viewport] positioned to the [ScrollPosition]. - offset.addListener(() { - negativeOffset._forceNegativePixels(offset.pixels); - }); - - /// Stack the two [Viewport]s on top of each other so they move in sync. - return Stack( - children: [ - Viewport( - axisDirection: flipAxisDirection(axisDirection), - anchor: 1.0 - widget.anchor, - offset: negativeOffset, - slivers: negativeSlivers, - cacheExtent: widget.cacheExtent, - ), - Viewport( - axisDirection: axisDirection, - anchor: widget.anchor, - offset: offset, - slivers: slivers, - cacheExtent: widget.cacheExtent, - ), - ], - ); - }); - }, - ); - } - - AxisDirection _getDirection(BuildContext context) { - return getAxisDirectionFromAxisReverseAndDirectionality( - context, widget.scrollDirection, widget.reverse); - } - - List _buildSlivers(BuildContext context, {bool negative = false}) { - final itemExtent = widget.itemExtent; - final padding = widget.padding ?? EdgeInsets.zero; - return [ - SliverPadding( - padding: negative - ? padding - EdgeInsets.only(bottom: padding.bottom) - : padding - EdgeInsets.only(top: padding.top), - sliver: (itemExtent != null) - ? SliverFixedExtentList( - delegate: negative - ? negativeChildrenDelegate - : positiveChildrenDelegate, - itemExtent: itemExtent, - ) - : SliverList( - delegate: negative - ? negativeChildrenDelegate - : positiveChildrenDelegate, - ), - ) - ]; - } - - SliverChildDelegate get negativeChildrenDelegate { - return SliverChildBuilderDelegate( - (BuildContext context, int index) { - final separatorBuilder = widget.separatorBuilder; - if (separatorBuilder != null) { - final itemIndex = (-1 - index) ~/ 2; - return index.isOdd - ? widget.itemBuilder(context, itemIndex) - : separatorBuilder(context, itemIndex); - } else { - return widget.itemBuilder(context, -1 - index); - } - }, - childCount: widget.itemCount, - addAutomaticKeepAlives: widget.addAutomaticKeepAlives, - addRepaintBoundaries: widget.addRepaintBoundaries, - ); - } - - SliverChildDelegate get positiveChildrenDelegate { - final separatorBuilder = widget.separatorBuilder; - final itemCount = widget.itemCount; - return SliverChildBuilderDelegate( - (separatorBuilder != null) - ? (BuildContext context, int index) { - final itemIndex = index ~/ 2; - return index.isEven - ? widget.itemBuilder(context, itemIndex) - : separatorBuilder(context, itemIndex); - } - : widget.itemBuilder, - childCount: separatorBuilder == null - ? itemCount - : (itemCount != null ? math.max(0, itemCount * 2 - 1) : null), - addAutomaticKeepAlives: widget.addAutomaticKeepAlives, - addRepaintBoundaries: widget.addRepaintBoundaries, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - .add(EnumProperty('scrollDirection', widget.scrollDirection)); - properties.add(FlagProperty('reverse', - value: widget.reverse, ifTrue: 'reversed', showName: true)); - properties.add(DiagnosticsProperty( - 'controller', widget.controller, - showName: false, defaultValue: null)); - properties.add(DiagnosticsProperty('physics', widget.physics, - showName: false, defaultValue: null)); - properties.add(DiagnosticsProperty( - 'padding', widget.padding, - defaultValue: null)); - properties.add( - DoubleProperty('itemExtent', widget.itemExtent, defaultValue: null)); - properties.add( - DoubleProperty('cacheExtent', widget.cacheExtent, defaultValue: null)); - } -} - -/// Same as a [ScrollController] except it provides [ScrollPosition] objects with infinite bounds. -class InfiniteScrollController extends ScrollController { - /// Creates a new [InfiniteScrollController] - InfiniteScrollController({ - double initialScrollOffset = 0.0, - bool keepScrollOffset = true, - String? debugLabel, - }) : super( - initialScrollOffset: initialScrollOffset, - keepScrollOffset: keepScrollOffset, - debugLabel: debugLabel, - ); - - @override - ScrollPosition createScrollPosition(ScrollPhysics physics, - ScrollContext context, ScrollPosition? oldPosition) { - return _InfiniteScrollPosition( - physics: physics, - context: context, - initialPixels: initialScrollOffset, - keepScrollOffset: keepScrollOffset, - oldPosition: oldPosition, - debugLabel: debugLabel, - ); - } -} - -class _InfiniteScrollPosition extends ScrollPositionWithSingleContext { - _InfiniteScrollPosition({ - required ScrollPhysics physics, - required ScrollContext context, - double? initialPixels = 0.0, - bool keepScrollOffset = true, - ScrollPosition? oldPosition, - String? debugLabel, - this.negativeScroll = false, - }) : super( - physics: physics, - context: context, - initialPixels: initialPixels, - keepScrollOffset: keepScrollOffset, - oldPosition: oldPosition, - debugLabel: debugLabel, - ); - - final bool negativeScroll; - - void _forceNegativePixels(double value) { - super.forcePixels(-value); - } - - @override - void saveScrollOffset() { - if (!negativeScroll) { - super.saveScrollOffset(); - } - } - - @override - void restoreScrollOffset() { - if (!negativeScroll) { - super.restoreScrollOffset(); - } - } - - @override - double get minScrollExtent => double.negativeInfinity; - - @override - double get maxScrollExtent => double.infinity; -} diff --git a/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart b/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart index 65965c5..f7b3a1c 100644 --- a/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart +++ b/lib/src/widgets/input/input_types/input_number_picker/input_number_picker.dart @@ -4,11 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_wizard/utils/translation_service.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../../flutter_form.dart'; -import 'numberpicker.dart'; - /// Input for a number used in a [FlutterForm]. /// /// [minValue] sets the minimal value of the picker. @@ -35,7 +34,7 @@ class FlutterFormInputNumberPicker extends FlutterFormInputWidget { super.registerController(context); - return NumberPickerFormField( + return input.FlutterFormInputNumberPicker( minValue: minValue, maxValue: maxValue, onSaved: (value) => controller.onSaved(value), @@ -46,40 +45,6 @@ class FlutterFormInputNumberPicker extends FlutterFormInputWidget { } } -/// Controller for the numberPicker used by a [FlutterFormInputWidget] used in a [FlutterForm]. -/// -/// Mainly used by [FlutterFormInputNumberPicker]. -class NumberPickerFormField extends FormField { - NumberPickerFormField({ - Key? key, - required FormFieldSetter onSaved, - required FormFieldValidator validator, - void Function(int value)? onChanged, - int initialValue = 0, - bool autovalidate = false, - int minValue = 0, - int maxValue = 100, - }) : super( - key: key, - onSaved: onSaved, - validator: validator, - initialValue: initialValue, - builder: (FormFieldState state) { - return NumberPicker( - minValue: minValue, - maxValue: maxValue, - value: initialValue, - onChanged: (int value) { - onChanged?.call(value); - - state.didChange(value); - }, - itemHeight: 35, - itemCount: 5, - ); - }); -} - class FlutterFormInputNumberPickerController implements FlutterFormInputController { FlutterFormInputNumberPickerController({ diff --git a/lib/src/widgets/input/input_types/input_number_picker/numberpicker.dart b/lib/src/widgets/input/input_types/input_number_picker/numberpicker.dart deleted file mode 100644 index 1f207bb..0000000 --- a/lib/src/widgets/input/input_types/input_number_picker/numberpicker.dart +++ /dev/null @@ -1,309 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'infinite_listview.dart'; - -typedef TextMapper = String Function(String numberText); - -class NumberPicker extends StatefulWidget { - /// Min value user can pick - final int minValue; - - /// Max value user can pick - final int maxValue; - - /// Currently selected value - final int value; - - /// Called when selected value changes - final ValueChanged onChanged; - - /// Specifies how many items should be shown - defaults to 3 - final int itemCount; - - /// Step between elements. Only for integer datePicker - /// Examples: - /// if step is 100 the following elements may be 100, 200, 300... - /// if min=0, max=6, step=3, then items will be 0, 3 and 6 - /// if min=0, max=5, step=3, then items will be 0 and 3. - final int step; - - /// height of single item in pixels - final double itemHeight; - - /// width of single item in pixels - final double itemWidth; - - /// Direction of scrolling - final Axis axis; - - /// Style of non-selected numbers. If null, it uses Theme's bodyText2 - final TextStyle? textStyle; - - /// Style of non-selected numbers. If null, it uses Theme's headline5 with accentColor - final TextStyle? selectedTextStyle; - - /// Whether to trigger haptic pulses or not - final bool haptics; - - /// Build the text of each item on the picker - final TextMapper? textMapper; - - /// Pads displayed integer values up to the length of maxValue - final bool zeroPad; - - /// Decoration to apply to central box where the selected value is placed - final Decoration? decoration; - - final bool infiniteLoop; - - const NumberPicker({ - Key? key, - required this.minValue, - required this.maxValue, - required this.value, - required this.onChanged, - this.itemCount = 3, - this.step = 1, - this.itemHeight = 50, - this.itemWidth = 100, - this.axis = Axis.vertical, - this.textStyle, - this.selectedTextStyle, - this.haptics = false, - this.decoration, - this.zeroPad = false, - this.textMapper, - this.infiniteLoop = false, - }) : assert(minValue <= value), - assert(value <= maxValue), - super(key: key); - - @override - NumberPickerState createState() => NumberPickerState(); -} - -class NumberPickerState extends State { - late ScrollController _scrollController; - - late int value; - - @override - void initState() { - super.initState(); - - value = widget.value; - - final initialOffset = (value - widget.minValue) ~/ widget.step * itemExtent; - if (widget.infiniteLoop) { - _scrollController = - InfiniteScrollController(initialScrollOffset: initialOffset); - } else { - _scrollController = ScrollController(initialScrollOffset: initialOffset); - } - _scrollController.addListener(_scrollListener); - } - - void _scrollListener() { - var indexOfMiddleElement = (_scrollController.offset / itemExtent).round(); - if (widget.infiniteLoop) { - indexOfMiddleElement %= itemCount; - } else { - indexOfMiddleElement = indexOfMiddleElement.clamp(0, itemCount - 1); - } - final intValueInTheMiddle = - _intValueFromIndex(indexOfMiddleElement + additionalItemsOnEachSide); - - if (value != intValueInTheMiddle) { - setState(() { - value = intValueInTheMiddle; - }); - - widget.onChanged(intValueInTheMiddle); - if (widget.haptics) { - HapticFeedback.selectionClick(); - } - } - Future.delayed( - const Duration(milliseconds: 100), - () => _maybeCenterValue(), - ); - } - - @override - void didUpdateWidget(NumberPicker oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.value != value) { - _maybeCenterValue(); - } - } - - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } - - bool get isScrolling => _scrollController.position.isScrollingNotifier.value; - - double get itemExtent => - widget.axis == Axis.vertical ? widget.itemHeight : widget.itemWidth; - - int get itemCount => (widget.maxValue - widget.minValue) ~/ widget.step + 1; - - int get listItemsCount => itemCount + 2 * additionalItemsOnEachSide; - - int get additionalItemsOnEachSide => (widget.itemCount - 1) ~/ 2; - - @override - Widget build(BuildContext context) { - return SizedBox( - width: widget.axis == Axis.vertical - ? widget.itemWidth - : widget.itemCount * widget.itemWidth, - height: widget.axis == Axis.vertical - ? widget.itemCount * widget.itemHeight - : widget.itemHeight, - child: NotificationListener( - onNotification: (not) { - if (not.dragDetails?.primaryVelocity == 0) { - Future.microtask(() => _maybeCenterValue()); - } - return true; - }, - child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), - child: Stack( - children: [ - Center( - child: Container( - width: 300, - height: 45, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: const Color(0xFFD8D8D8).withOpacity(0.50), - ), - ), - ), - if (widget.infiniteLoop) - InfiniteListView.builder( - scrollDirection: widget.axis, - controller: _scrollController as InfiniteScrollController, - itemExtent: itemExtent, - itemBuilder: _itemBuilder, - padding: EdgeInsets.zero, - ) - else - ListView.builder( - itemCount: listItemsCount, - scrollDirection: widget.axis, - controller: _scrollController, - itemExtent: itemExtent, - itemBuilder: _itemBuilder, - padding: EdgeInsets.zero, - ), - _NumberPickerSelectedItemDecoration( - axis: widget.axis, - itemExtent: itemExtent, - decoration: widget.decoration, - ), - ], - ), - ), - ), - ); - } - - Widget _itemBuilder(BuildContext context, int index) { - final themeData = Theme.of(context); - final defaultStyle = widget.textStyle ?? themeData.textTheme.bodyText2; - final selectedStyle = widget.selectedTextStyle ?? - themeData.textTheme.headline5 - ?.copyWith(color: themeData.highlightColor); - - final valueFromIndex = _intValueFromIndex(index % itemCount); - final isExtra = !widget.infiniteLoop && - (index < additionalItemsOnEachSide || - index >= listItemsCount - additionalItemsOnEachSide); - final itemStyle = valueFromIndex == value ? selectedStyle : defaultStyle; - - final child = isExtra - ? const SizedBox.shrink() - : Text( - _getDisplayedValue(valueFromIndex), - style: itemStyle, - ); - - return Container( - width: widget.itemWidth, - height: widget.itemHeight, - alignment: Alignment.center, - child: child, - ); - } - - String _getDisplayedValue(int value) { - final text = widget.zeroPad - ? value.toString().padLeft(widget.maxValue.toString().length, '0') - : value.toString(); - if (widget.textMapper != null) { - return widget.textMapper!(text); - } else { - return text; - } - } - - int _intValueFromIndex(int index) { - index -= additionalItemsOnEachSide; - index %= itemCount; - return widget.minValue + index * widget.step; - } - - void _maybeCenterValue() { - if (_scrollController.hasClients && !isScrolling) { - int diff = value - widget.minValue; - int index = diff ~/ widget.step; - if (widget.infiniteLoop) { - final offset = _scrollController.offset + 0.5 * itemExtent; - final cycles = (offset / (itemCount * itemExtent)).floor(); - index += cycles * itemCount; - } - _scrollController.animateTo( - index * itemExtent, - duration: const Duration(milliseconds: 300), - curve: Curves.easeOutCubic, - ); - } - } -} - -class _NumberPickerSelectedItemDecoration extends StatelessWidget { - final Axis axis; - final double itemExtent; - final Decoration? decoration; - - const _NumberPickerSelectedItemDecoration({ - Key? key, - required this.axis, - required this.itemExtent, - required this.decoration, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Center( - child: IgnorePointer( - child: Container( - width: isVertical ? double.infinity : itemExtent, - height: isVertical ? itemExtent : double.infinity, - decoration: decoration, - ), - ), - ); - } - - bool get isVertical => axis == Axis.vertical; -} diff --git a/lib/src/widgets/input/input_types/input_password/input_password.dart b/lib/src/widgets/input/input_types/input_password/input_password.dart index 54d13fa..edf837c 100644 --- a/lib/src/widgets/input/input_types/input_password/input_password.dart +++ b/lib/src/widgets/input/input_types/input_password/input_password.dart @@ -3,7 +3,8 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; -import 'package:flutter_form_wizard/src/widgets/input/input_types/input_password/password.dart'; +import 'package:flutter_form_wizard/utils/translation_service.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../../flutter_form.dart'; @@ -21,9 +22,15 @@ class FlutterFormInputPassword extends FlutterFormInputWidget { Widget build(BuildContext context, WidgetRef ref) { super.registerController(context); - return PasswordTextField( - label: label, - controller: controller, + String Function(String, {List? params}) _ = + getTranslator(context, ref); + + return input.FlutterFormInputPassword( + initialValue: controller.value, + onSaved: (value) => controller.onSaved(value), + validator: (value) => controller.onValidate(value, _), + onChanged: (value) => controller.onChanged?.call(value), + onFieldSubmitted: (value) => controller.onSubmit?.call(value), ); } } diff --git a/lib/src/widgets/input/input_types/input_password/password.dart b/lib/src/widgets/input/input_types/input_password/password.dart deleted file mode 100644 index 3fc46eb..0000000 --- a/lib/src/widgets/input/input_types/input_password/password.dart +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; -import 'package:flutter_form_wizard/utils/translation_service.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../../../../flutter_form.dart'; - -/// Generates a [TextFormField] for passwords. It requires a [FlutterFormInputController] -/// as the [controller] parameter and an optional [Widget] as [label] -class PasswordTextField extends ConsumerStatefulWidget { - final Widget? label; - final FlutterFormInputController controller; - - const PasswordTextField({ - Key? key, - required this.controller, - this.label, - }) : super(key: key); - - @override - ConsumerState createState() => _PasswordTextFieldState(); -} - -class _PasswordTextFieldState extends ConsumerState { - bool obscured = true; - - @override - Widget build(BuildContext context) { - String Function(String, {List? params}) _ = - getTranslator(context, ref); - - return TextFormField( - initialValue: widget.controller.value, - obscureText: obscured, - onSaved: (value) => widget.controller.onSaved(value), - validator: (value) => widget.controller.onValidate(value, _), - onChanged: (value) => widget.controller.onChanged?.call(value), - onFieldSubmitted: (value) => widget.controller.onSubmit?.call(value), - decoration: InputDecoration( - label: widget.label ?? const Text("Password"), - suffixIcon: IconButton( - onPressed: () { - setState(() { - obscured = !obscured; - }); - }, - icon: Icon(obscured ? Icons.visibility_off : Icons.visibility), - ), - ), - ); - } -} diff --git a/lib/src/widgets/input/input_types/input_plain_text.dart b/lib/src/widgets/input/input_types/input_plain_text.dart index f3909c0..3768352 100644 --- a/lib/src/widgets/input/input_types/input_plain_text.dart +++ b/lib/src/widgets/input/input_types/input_plain_text.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_wizard/utils/translation_service.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../flutter_form.dart'; @@ -45,7 +46,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget { label: label ?? const Text("Plain text"), ); - return TextFormField( + return input.FlutterFormInputPlainText( scrollPadding: scrollPadding ?? const EdgeInsets.all(20.0), initialValue: controller.value, onSaved: (value) => controller.onSaved(value), @@ -69,7 +70,7 @@ class FlutterFormInputPlainText extends FlutterFormInputWidget { /// Hint can be set to set a hint inside the field. /// /// MaxCharacters can be set to set a maximum amount of characters. -class FlutterFormInputMultiLine extends StatelessWidget { +class FlutterFormInputMultiLine extends ConsumerWidget { const FlutterFormInputMultiLine({ Key? key, required this.controller, @@ -85,32 +86,17 @@ class FlutterFormInputMultiLine extends StatelessWidget { final int? maxCharacters; @override - Widget build(BuildContext context) { - return Column( - children: [ - Expanded( - child: FlutterFormInputPlainText( - label: label, - controller: controller, - textAlignVertical: TextAlignVertical.top, - expands: true, - maxLines: null, - maxLength: maxCharacters, - decoration: InputDecoration( - hintText: hint, - floatingLabelBehavior: FloatingLabelBehavior.never, - isDense: true, - border: const OutlineInputBorder( - borderSide: BorderSide(color: Color(0xFF979797)), - ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Color(0xFF979797)), - ), - filled: true, - ), - ), - ), - ], + Widget build(BuildContext context, WidgetRef ref) { + String Function(String, {List? params}) _ = + getTranslator(context, ref); + + return input.FlutterFormInputMultiLine( + label: label, + hint: hint, + maxCharacters: maxCharacters, + onChanged: controller.onChanged, + onSaved: controller.onSaved, + validator: (v) => controller.onValidate(v, _), ); } } diff --git a/lib/src/widgets/input/input_types/input_slider/input_slider.dart b/lib/src/widgets/input/input_types/input_slider/input_slider.dart index cd59bcc..6128c50 100644 --- a/lib/src/widgets/input/input_types/input_slider/input_slider.dart +++ b/lib/src/widgets/input/input_types/input_slider/input_slider.dart @@ -3,7 +3,7 @@ // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; -import 'package:flutter_form_wizard/src/widgets/input/input_types/input_slider/slider.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_form_wizard/utils/translation_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -32,7 +32,7 @@ class FlutterFormInputSlider extends FlutterFormInputWidget { super.registerController(context); - return SliderFormField( + return input.FlutterFormInputSlider( onSaved: (value) => controller.onSaved(value), validator: (value) => controller.onValidate(value, _), ); diff --git a/lib/src/widgets/input/input_types/input_slider/slider.dart b/lib/src/widgets/input/input_types/input_slider/slider.dart deleted file mode 100644 index b1eb6c1..0000000 --- a/lib/src/widgets/input/input_types/input_slider/slider.dart +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; - -/// Creates a slider with the given input parameters -class SliderFormField extends FormField { - SliderFormField({ - Key? key, - required FormFieldSetter onSaved, - required FormFieldValidator validator, - void Function(double value)? onChanged, - double initialValue = 0.5, - }) : super( - key: key, - onSaved: onSaved, - validator: validator, - initialValue: initialValue, - builder: (FormFieldState state) { - return Slider( - value: state.value ?? initialValue, - onChanged: (double value) { - onChanged?.call(value); - - state.didChange(value); - }, - ); - }); -} diff --git a/lib/src/widgets/input/input_types/input_switch/input_switch.dart b/lib/src/widgets/input/input_types/input_switch/input_switch.dart index edc2258..f9002c5 100644 --- a/lib/src/widgets/input/input_types/input_switch/input_switch.dart +++ b/lib/src/widgets/input/input_types/input_switch/input_switch.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_wizard/flutter_form.dart'; -import 'package:flutter_form_wizard/src/widgets/input/input_types/input_switch/input_switch_field.dart'; +import 'package:flutter_input_library/flutter_input_library.dart' as input; import 'package:flutter_form_wizard/utils/translation_service.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -25,10 +25,8 @@ class FlutterFormInputSwitch extends FlutterFormInputWidget { super.registerController(context); - return SwitchFormField( - onSaved: (value) { - controller.onSaved(value); - }, + return input.FlutterFormInputSwitch( + onSaved: (value) => controller.onSaved(value), onChanged: controller.onChanged, validator: (value) => controller.onValidate(value, _), initialValue: controller.value ?? false, diff --git a/lib/src/widgets/input/input_types/input_switch/input_switch_field.dart b/lib/src/widgets/input/input_types/input_switch/input_switch_field.dart deleted file mode 100644 index b01a755..0000000 --- a/lib/src/widgets/input/input_types/input_switch/input_switch_field.dart +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import 'package:flutter/material.dart'; - -class SwitchFormField extends FormField { - SwitchFormField({ - Key? key, - required FormFieldSetter onSaved, - required FormFieldValidator validator, - bool initialValue = false, - bool autovalidate = false, - void Function(bool? value)? onChanged, - }) : super( - key: key, - onSaved: onSaved, - validator: validator, - initialValue: initialValue, - builder: (FormFieldState state) { - return SwitchWidget( - initialValue: initialValue, - state: state, - onChanged: onChanged, - ); - }); -} - -class SwitchWidget extends StatefulWidget { - const SwitchWidget({ - this.initialValue = false, - required this.state, - this.onChanged, - super.key, - }); - - final bool initialValue; - final FormFieldState state; - final void Function(bool? value)? onChanged; - - @override - State createState() => _SwitchWidgetState(); -} - -class _SwitchWidgetState extends State { - late bool value = widget.initialValue; - - @override - Widget build(BuildContext context) { - return Switch( - value: value, - onChanged: (bool value) { - widget.onChanged?.call(value); - - widget.state.didChange(value); - - setState(() { - this.value = value; - }); - }, - ); - } -} diff --git a/pubspec.yaml b/pubspec.yaml index c273135..be0eaeb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_form_wizard description: A new Flutter package project. -version: 4.0.2 +version: 4.0.3 homepage: https://github.com/Iconica-Development/flutter_form_wizard publish_to: none @@ -17,6 +17,10 @@ dependencies: flutter_riverpod: ^2.1.1 intl: ^0.17.0 localization: ^2.1.0 + flutter_input_library: + git: + url: https://github.com/Iconica-Development/flutter_input_library + ref: 0.0.3 dev_dependencies: flutter_test: