@@ -7,60 +7,41 @@ import '../extensions/build_context_x.dart';
77import '../weather/view/city_search_field.dart' ;
88import '../weather/weather_model.dart' ;
99
10- class SideBar extends StatelessWidget with WatchItMixin {
10+ class SideBar extends StatefulWidget with WatchItStatefulWidgetMixin {
1111 const SideBar ({super .key, this .onSelected});
1212
1313 final VoidCallback ? onSelected;
1414
15+ @override
16+ State <SideBar > createState () => _SideBarState ();
17+ }
18+
19+ class _SideBarState extends State <SideBar > {
1520 @override
1621 Widget build (BuildContext context) {
1722 final theme = context.theme;
1823
19- final model = di <WeatherModel >();
20-
2124 final favLocationsLength =
2225 watchPropertyValue ((WeatherModel m) => m.favLocations.length);
2326 final favLocations = watchPropertyValue ((WeatherModel m) => m.favLocations);
24- final lastLocation = watchPropertyValue ((WeatherModel m) => m.lastLocation);
27+ final currentLocation =
28+ watchPropertyValue ((WeatherModel m) => m.lastLocation);
2529
2630 final listView = ListView .builder (
2731 itemCount: favLocationsLength,
2832 itemBuilder: (context, index) {
29- final location = favLocations.elementAt (index);
30- return Stack (
31- alignment: Alignment .centerRight,
32- children: [
33- YaruMasterTile (
34- onTap: () {
35- model.loadWeather (cityName: location);
36- onSelected? .call ();
37- },
38- selected: lastLocation == location,
39- title: Text (
40- favLocations.elementAt (index),
41- ),
42- ),
43- if (favLocationsLength > 1 && lastLocation == location)
44- Positioned (
45- right: 20 ,
46- child: SizedBox .square (
47- dimension: 30 ,
48- child: IconButton (
49- padding: EdgeInsets .zero,
50- onPressed: () {
51- model.removeFavLocation (location).then (
52- (value) => model.loadWeather (
53- cityName: favLocations.lastOrNull,
54- ),
55- );
56- },
57- icon: const Icon (
58- YaruIcons .window_close,
59- ),
60- ),
61- ),
62- ),
63- ],
33+ final selected = currentLocation == favLocations.elementAt (index);
34+ return Tile (
35+ selected: selected,
36+ location: favLocations.elementAt (index),
37+ onClear: favLocationsLength > 1
38+ ? () => di <WeatherModel >().loadWeather (
39+ cityName: selected
40+ ? favLocations.elementAtOrNull (index - 1 )
41+ : currentLocation,
42+ )
43+ : null ,
44+ onSelected: widget.onSelected,
6445 );
6546 },
6647 );
@@ -89,3 +70,69 @@ class SideBar extends StatelessWidget with WatchItMixin {
8970 );
9071 }
9172}
73+
74+ class Tile extends StatefulWidget {
75+ const Tile ({
76+ super .key,
77+ required this .location,
78+ required this .onSelected,
79+ required this .onClear,
80+ required this .selected,
81+ });
82+
83+ final String location;
84+ final VoidCallback ? onSelected;
85+ final bool selected;
86+ final Function ()? onClear;
87+
88+ @override
89+ State <Tile > createState () => _TileState ();
90+ }
91+
92+ class _TileState extends State <Tile > {
93+ bool _hovered = false ;
94+
95+ @override
96+ Widget build (BuildContext context) {
97+ return MouseRegion (
98+ onEnter: (_) => setState (() => _hovered = true ),
99+ onExit: (_) => setState (() => _hovered = false ),
100+ child: Stack (
101+ alignment: Alignment .centerRight,
102+ children: [
103+ Tooltip (
104+ message: widget.location,
105+ child: YaruMasterTile (
106+ onTap: () {
107+ di <WeatherModel >().loadWeather (cityName: widget.location);
108+ widget.onSelected? .call ();
109+ },
110+ selected: widget.selected,
111+ title: Text (
112+ widget.location,
113+ ),
114+ ),
115+ ),
116+ if (widget.onClear != null && (_hovered || widget.selected))
117+ Positioned (
118+ right: 20 ,
119+ child: SizedBox .square (
120+ dimension: 30 ,
121+ child: IconButton (
122+ padding: EdgeInsets .zero,
123+ onPressed: () {
124+ di <WeatherModel >().removeFavLocation (widget.location).then (
125+ (_) => widget.onClear? .call (),
126+ );
127+ },
128+ icon: const Icon (
129+ YaruIcons .window_close,
130+ ),
131+ ),
132+ ),
133+ ),
134+ ],
135+ ),
136+ );
137+ }
138+ }
0 commit comments