Line data Source code
1 : import 'dart:collection';
2 :
3 : import 'package:flutter/material.dart';
4 : import 'package:widgetbook/src/models/models.dart';
5 : import 'package:widgetbook/src/models/organizers/organizer_helper/organizer_helper.dart';
6 : import 'package:widgetbook/src/providers/organizer_state.dart';
7 : import 'package:widgetbook/src/providers/provider.dart';
8 : import 'package:widgetbook/src/repositories/selected_story_repository.dart';
9 : import 'package:widgetbook/src/repositories/story_repository.dart';
10 : import 'package:widgetbook/src/services/filter_service.dart';
11 :
12 : class OrganizerBuilder extends StatefulWidget {
13 1 : const OrganizerBuilder({
14 : Key? key,
15 : required this.initialState,
16 : required this.child,
17 : required this.storyRepository,
18 : required this.selectedStoryRepository,
19 : required this.filterService,
20 1 : }) : super(key: key);
21 :
22 : final Widget child;
23 : final StoryRepository storyRepository;
24 : final OrganizerState initialState;
25 : final SelectedStoryRepository selectedStoryRepository;
26 : final FilterService filterService;
27 :
28 1 : @override
29 1 : _OrganizerBuilderState createState() => _OrganizerBuilderState();
30 : }
31 :
32 : class _OrganizerBuilderState extends State<OrganizerBuilder> {
33 : late OrganizerState state;
34 : late OrganizerProvider provider;
35 1 : @override
36 : void initState() {
37 3 : state = widget.initialState;
38 1 : setProvider();
39 :
40 5 : widget.selectedStoryRepository.getStream().forEach((Story? story) {
41 2 : provider.openStory(story);
42 : });
43 :
44 1 : super.initState();
45 : }
46 :
47 1 : void setProvider() {
48 2 : provider = OrganizerProvider(
49 2 : selectedStoryRepository: widget.selectedStoryRepository,
50 2 : storyRepository: widget.storyRepository,
51 2 : filterService: widget.filterService,
52 1 : state: state,
53 1 : onStateChanged: (OrganizerState state) {
54 2 : setState(() {
55 1 : this.state = state;
56 1 : setProvider();
57 : });
58 : },
59 2 : child: widget.child,
60 : );
61 : }
62 :
63 1 : @override
64 : Widget build(BuildContext context) {
65 1 : return provider;
66 : }
67 : }
68 :
69 : class OrganizerProvider extends Provider<OrganizerState> {
70 1 : const OrganizerProvider({
71 : required this.selectedStoryRepository,
72 : required this.storyRepository,
73 : required this.filterService,
74 : required OrganizerState state,
75 : required ValueChanged<OrganizerState> onStateChanged,
76 : required Widget child,
77 : Key? key,
78 1 : }) : super(
79 : state: state,
80 : onStateChanged: onStateChanged,
81 : child: child,
82 : key: key,
83 : );
84 :
85 : final SelectedStoryRepository selectedStoryRepository;
86 : final StoryRepository storyRepository;
87 : final FilterService filterService;
88 :
89 1 : static OrganizerProvider? of(BuildContext context) {
90 1 : return context.dependOnInheritedWidgetOfExactType<OrganizerProvider>();
91 : }
92 :
93 1 : void openStory(Story? story) {
94 : if (story == null) {
95 : return;
96 : }
97 1 : var currentOrganizer = story.parent as ExpandableOrganizer?;
98 : while (currentOrganizer != null) {
99 1 : currentOrganizer.isExpanded = true;
100 1 : currentOrganizer = currentOrganizer.parent as ExpandableOrganizer?;
101 : }
102 : }
103 :
104 1 : void _updateFolders(List<Category> categories) {
105 1 : final oldFolders = FolderHelper.getAllFoldersFromCategories(
106 2 : state.allCategories,
107 : );
108 1 : final newFolders = FolderHelper.getAllFoldersFromCategories(
109 : categories,
110 : );
111 1 : final oldFolderMap = HashMap<String, Folder>.fromIterable(
112 : oldFolders,
113 2 : key: (dynamic k) => k.path as String,
114 1 : value: (dynamic v) => v as Folder,
115 : );
116 :
117 2 : for (final folder in newFolders) {
118 1 : final path = folder.path;
119 1 : if (oldFolderMap.containsKey(path)) {
120 3 : folder.isExpanded = oldFolderMap[path]!.isExpanded;
121 : }
122 : }
123 : }
124 :
125 1 : void _updateWidgets(List<Category> categories) {
126 1 : final oldWidgets = WidgetHelper.getAllWidgetElementsFromCategories(
127 2 : state.allCategories,
128 : );
129 1 : final newWidgets = WidgetHelper.getAllWidgetElementsFromCategories(
130 : categories,
131 : );
132 1 : final oldFolderMap = HashMap<String, WidgetElement>.fromIterable(
133 : oldWidgets,
134 2 : key: (dynamic k) => k.path as String,
135 1 : value: (dynamic v) => v as WidgetElement,
136 : );
137 :
138 2 : for (final widget in newWidgets) {
139 1 : final path = widget.path;
140 1 : if (oldFolderMap.containsKey(path)) {
141 3 : widget.isExpanded = oldFolderMap[path]!.isExpanded;
142 : }
143 : }
144 : }
145 :
146 1 : void update(List<Category> categories) {
147 1 : _updateFolders(categories);
148 1 : _updateWidgets(categories);
149 1 : emit(
150 1 : OrganizerState.unfiltered(categories: categories),
151 : );
152 :
153 1 : final stories = StoryHelper.getAllStoriesFromCategories(categories);
154 1 : storyRepository
155 1 : ..deleteAll()
156 1 : ..addAll(stories);
157 : }
158 :
159 1 : void resetFilter() {
160 1 : emit(
161 1 : OrganizerState.unfiltered(
162 2 : categories: state.allCategories,
163 : ),
164 : );
165 : }
166 :
167 1 : void filter(String searchTerm) {
168 2 : final categories = filterService.filter(
169 : searchTerm,
170 2 : state.allCategories,
171 : );
172 :
173 1 : emit(
174 1 : OrganizerState(
175 2 : allCategories: state.allCategories,
176 : filteredCategories: categories,
177 : searchTerm: searchTerm,
178 : ),
179 : );
180 : }
181 :
182 1 : @override
183 : void emit(OrganizerState state) {
184 1 : onStateChanged(state);
185 : }
186 :
187 1 : void toggleExpander(ExpandableOrganizer organizer) {
188 2 : organizer.isExpanded = !organizer.isExpanded;
189 1 : emit(
190 1 : OrganizerState(
191 2 : allCategories: state.allCategories,
192 2 : filteredCategories: state.filteredCategories,
193 2 : searchTerm: state.searchTerm,
194 : ),
195 : );
196 : }
197 : }
|