Line data Source code
1 : // Copyright 2023 The terCAD team. All rights reserved.
2 : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
3 :
4 : import 'package:app_finance/_classes/controller/focus_controller.dart';
5 : import 'package:app_finance/_classes/herald/app_design.dart';
6 : import 'package:app_finance/design/form/list_selector_item.dart';
7 : import 'package:app_finance/_configs/custom_color_scheme.dart';
8 : import 'package:app_finance/_configs/custom_text_theme.dart';
9 : import 'package:app_finance/_configs/theme_helper.dart';
10 : import 'package:app_finance/_ext/build_context_ext.dart';
11 : import 'package:app_finance/design/form/list_selector_page.dart';
12 : import 'package:app_finance/design/wrapper/focus_wrapper.dart';
13 : import 'package:app_finance/design/wrapper/row_widget.dart';
14 : import 'package:app_finance/design/wrapper/tap_widget.dart';
15 : import 'package:app_finance/design/wrapper/text_wrapper.dart';
16 : import 'package:flutter/material.dart';
17 :
18 : typedef FnState = Function(ListSelectorItem? value);
19 :
20 : class ListSelector<K extends ListSelectorItem> extends StatefulWidget {
21 : final List<K> options;
22 : final K? value;
23 : final FnState setState;
24 : final String? hintText;
25 : final String? tooltip;
26 : final TextStyle? hintStyle;
27 : final Color? hintColor;
28 : final bool withLabel;
29 :
30 2 : const ListSelector({
31 : super.key,
32 : required this.options,
33 : required this.setState,
34 : this.hintText,
35 : this.tooltip,
36 : this.hintStyle,
37 : this.hintColor,
38 : this.value,
39 : this.withLabel = false,
40 : });
41 :
42 2 : @override
43 2 : ListSelectorState createState() => ListSelectorState();
44 : }
45 :
46 : class ListSelectorState<T extends ListSelector, K extends ListSelectorItem> extends State<T> {
47 : final textController = SearchController();
48 : late FocusController focusController;
49 0 : FntSelectorCallback? getItemBuilder() => null;
50 :
51 0 : void onTap(BuildContext context) async {
52 0 : focusController.blur();
53 : FocusController.force = true;
54 0 : final result = await Navigator.push(
55 : context,
56 0 : MaterialPageRoute(
57 0 : builder: (context) => ListSelectorPage(
58 0 : options: widget.options,
59 0 : result: widget.value,
60 0 : tooltip: widget.tooltip ?? widget.hintText ?? '...',
61 0 : itemBuilder: getItemBuilder(),
62 : ),
63 : ),
64 : );
65 : FocusController.force = false;
66 0 : widget.setState(result);
67 0 : WidgetsBinding.instance.addPostFrameCallback((_) => focusController.onEditingComplete(this));
68 : }
69 :
70 2 : @override
71 : Widget build(BuildContext context) {
72 4 : focusController = FocusWrapper.of(context) ?? FocusController();
73 2 : final indent = ThemeHelper.getIndent(1.5);
74 6 : final hintStyle = context.textTheme.tooltipMedium.copyWith(overflow: TextOverflow.ellipsis);
75 4 : final labelStyle = context.textTheme.tooltipSmall;
76 24 : K? item = widget.value != null ? widget.options.cast().where((e) => e.equal(widget.value?.id)).firstOrNull : null;
77 :
78 2 : return InkWell(
79 4 : autofocus: focusController.isFocused(this),
80 8 : focusNode: focusController.bind(this, context: context, value: widget.value),
81 2 : child: TapWidget(
82 4 : tooltip: widget.tooltip ?? '',
83 0 : onTap: () => onTap(context),
84 0 : onFocusChange: (v) => v ? focusController.scrollToFocusedElement(this) : null,
85 2 : child: Container(
86 : width: double.infinity,
87 4 : color: context.colorScheme.fieldBackground,
88 4 : child: LayoutBuilder(builder: (_, constraints) {
89 2 : return RowWidget(
90 6 : chunk: [null, ThemeHelper.barHeight - ThemeHelper.getIndent()],
91 2 : maxWidth: constraints.maxWidth,
92 : indent: 0.0,
93 2 : children: [
94 2 : [
95 2 : Container(
96 2 : padding: EdgeInsets.fromLTRB(
97 2 : indent / 1.5,
98 4 : widget.withLabel && item != null ? 1 : indent,
99 2 : AppDesign.isRightToLeft() ? ThemeHelper.getIndent() : 0,
100 4 : widget.withLabel && item != null ? indent / 2 : indent,
101 : ),
102 6 : constraints: BoxConstraints(maxWidth: constraints.maxWidth - ThemeHelper.barHeight),
103 : child: item != null
104 4 : ? widget.withLabel
105 0 : ? Column(
106 0 : mainAxisAlignment: AppDesign.getAlignment<MainAxisAlignment>(),
107 0 : crossAxisAlignment: AppDesign.getAlignment(),
108 0 : children: [
109 0 : TextWrapper(widget.hintText ?? '...', style: labelStyle),
110 0 : item.build(context),
111 : ],
112 : )
113 2 : : item.build(context)
114 2 : : TextWrapper(
115 4 : widget.hintText ?? '...',
116 4 : style: widget.hintStyle ?? hintStyle,
117 : ),
118 : ),
119 : ],
120 2 : [
121 2 : Padding(
122 4 : padding: EdgeInsets.only(top: indent / 3),
123 2 : child: ExcludeFocus(
124 2 : child: IconButton(
125 4 : tooltip: widget.hintText ?? '...',
126 6 : icon: Icon(Icons.arrow_drop_down, color: widget.hintStyle?.color),
127 0 : onPressed: () => onTap(context),
128 : ),
129 : ),
130 : ),
131 : ],
132 : ],
133 : );
134 : }),
135 : ),
136 : ),
137 : );
138 : }
139 : }
|