Skip to content

Commit 25ae122

Browse files
authored
Merge pull request #56 from knopp/window-states-in-reference-app
Add ability to change the window state in the reference app and updatd the API per the current understanding
2 parents 3f3e74a + c042ac9 commit 25ae122

File tree

5 files changed

+240
-104
lines changed

5 files changed

+240
-104
lines changed

examples/multi_window_ref_app/lib/app/main_window.dart

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import 'regular_window_edit_dialog.dart';
1313

1414
class MainWindow extends StatefulWidget {
1515
MainWindow({super.key, required WindowController mainController}) {
16-
_windowManagerModel.add(
17-
KeyedWindowController(isMainWindow: true, key: UniqueKey(), controller: mainController));
16+
_windowManagerModel.add(KeyedWindowController(
17+
isMainWindow: true, key: UniqueKey(), controller: mainController));
1818
}
1919

2020
final WindowManagerModel _windowManagerModel = WindowManagerModel();
@@ -38,7 +38,8 @@ class _MainWindowState extends State<MainWindow> {
3838
flex: 60,
3939
child: SingleChildScrollView(
4040
scrollDirection: Axis.vertical,
41-
child: _ActiveWindowsTable(windowManagerModel: widget._windowManagerModel),
41+
child: _ActiveWindowsTable(
42+
windowManagerModel: widget._windowManagerModel),
4243
),
4344
),
4445
Expanded(
@@ -66,15 +67,18 @@ class _MainWindowState extends State<MainWindow> {
6667
listenable: widget._windowManagerModel,
6768
builder: (BuildContext context, Widget? _) {
6869
final List<Widget> childViews = <Widget>[];
69-
for (final KeyedWindowController controller in widget._windowManagerModel.windows) {
70+
for (final KeyedWindowController controller
71+
in widget._windowManagerModel.windows) {
7072
if (controller.parent == null && !controller.isMainWindow) {
7173
childViews.add(WindowControllerRender(
7274
controller: controller.controller,
7375
key: controller.key,
7476
windowSettings: widget._settings,
7577
windowManagerModel: widget._windowManagerModel,
76-
onDestroyed: () => widget._windowManagerModel.remove(controller.key),
77-
onError: () => widget._windowManagerModel.remove(controller.key),
78+
onDestroyed: () =>
79+
widget._windowManagerModel.remove(controller.key),
80+
onError: () =>
81+
widget._windowManagerModel.remove(controller.key),
7882
));
7983
}
8084
}
@@ -130,7 +134,8 @@ class _ActiveWindowsTable extends StatelessWidget {
130134
),
131135
numeric: true),
132136
],
133-
rows: (windowManagerModel.windows).map<DataRow>((KeyedWindowController controller) {
137+
rows: (windowManagerModel.windows)
138+
.map<DataRow>((KeyedWindowController controller) {
134139
return DataRow(
135140
key: controller.key,
136141
color: WidgetStateColor.resolveWith((states) {
@@ -142,49 +147,30 @@ class _ActiveWindowsTable extends StatelessWidget {
142147
selected: controller.controller == windowManagerModel.selected,
143148
onSelectChanged: (selected) {
144149
if (selected != null) {
145-
windowManagerModel
146-
.select(selected ? controller.controller.rootView.viewId : null);
150+
windowManagerModel.select(selected
151+
? controller.controller.rootView.viewId
152+
: null);
147153
}
148154
},
149155
cells: [
150156
DataCell(Text('${controller.controller.rootView.viewId}')),
151157
DataCell(
152158
ListenableBuilder(
153159
listenable: controller.controller,
154-
builder: (BuildContext context, Widget? _) => Text(controller
155-
.controller.type
156-
.toString()
157-
.replaceFirst('WindowArchetype.', ''))),
160+
builder: (BuildContext context, Widget? _) => Text(
161+
controller.controller.type
162+
.toString()
163+
.replaceFirst('WindowArchetype.', ''))),
158164
),
159165
DataCell(
160166
ListenableBuilder(
161167
listenable: controller.controller,
162-
builder: (BuildContext context, Widget? _) => Row(children: [
168+
builder: (BuildContext context, Widget? _) =>
169+
Row(children: [
163170
IconButton(
164-
icon: const Icon(Icons.edit_outlined),
165-
onPressed: () {
166-
if (controller.controller.type == WindowArchetype.regular) {
167-
showRegularWindowEditDialog(
168-
context,
169-
initialWidth: controller.controller.contentSize.width,
170-
initialHeight: controller.controller.contentSize.height,
171-
initialTitle: "",
172-
onSave: (double? width, double? height, String? title) {
173-
final regularController =
174-
controller.controller as RegularWindowController;
175-
if (width != null && height != null) {
176-
regularController.updateContentSize(
177-
WindowSizing(preferredSize: Size(width, height)),
178-
);
179-
}
180-
if (title != null) {
181-
regularController.setTitle(title);
182-
}
183-
},
184-
);
185-
}
186-
},
187-
),
171+
icon: const Icon(Icons.edit_outlined),
172+
onPressed: () => _showWindowEditDialog(
173+
controller, context)),
188174
IconButton(
189175
icon: const Icon(Icons.delete_outlined),
190176
onPressed: () async {
@@ -199,6 +185,17 @@ class _ActiveWindowsTable extends StatelessWidget {
199185
);
200186
});
201187
}
188+
189+
void _showWindowEditDialog(
190+
KeyedWindowController controller, BuildContext context) {
191+
if (controller.controller.type != WindowArchetype.regular) {
192+
return;
193+
}
194+
195+
showRegularWindowEditDialog(
196+
context: context,
197+
controller: controller.controller as RegularWindowController);
198+
}
202199
}
203200

204201
class _WindowCreatorCard extends StatelessWidget {
@@ -243,7 +240,8 @@ class _WindowCreatorCard extends StatelessWidget {
243240
onDestroyed: () => windowManagerModel.remove(key),
244241
),
245242
title: "Regular",
246-
contentSize: WindowSizing(preferredSize: windowSettings.regularSize),
243+
contentSize: WindowSizing(
244+
preferredSize: windowSettings.regularSize),
247245
)));
248246
},
249247
child: const Text('Regular'),

examples/multi_window_ref_app/lib/app/regular_window_edit_dialog.dart

Lines changed: 171 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,180 @@
55
import 'package:flutter/material.dart';
66

77
void showRegularWindowEditDialog(
8-
BuildContext context, {
9-
double? initialWidth,
10-
double? initialHeight,
11-
String? initialTitle,
12-
Function(double?, double?, String?)? onSave,
13-
}) {
14-
final TextEditingController widthController =
15-
TextEditingController(text: initialWidth?.toString() ?? '');
16-
final TextEditingController heightController =
17-
TextEditingController(text: initialHeight?.toString() ?? '');
18-
final TextEditingController titleController = TextEditingController(text: initialTitle ?? '');
19-
8+
{required BuildContext context,
9+
required RegularWindowController controller}) {
2010
showDialog(
21-
context: context,
22-
builder: (context) {
23-
return AlertDialog(
24-
title: Text("Edit Window Properties"),
25-
content: StatefulBuilder(
26-
builder: (context, setState) {
27-
return Column(
28-
mainAxisSize: MainAxisSize.min,
29-
children: [
30-
TextField(
31-
controller: widthController,
32-
keyboardType: TextInputType.number,
33-
decoration: InputDecoration(labelText: "Width"),
34-
),
35-
TextField(
36-
controller: heightController,
37-
keyboardType: TextInputType.number,
38-
decoration: InputDecoration(labelText: "Height"),
39-
),
40-
TextField(
41-
controller: titleController,
42-
decoration: InputDecoration(labelText: "Title"),
43-
),
44-
],
45-
);
46-
},
47-
),
48-
actions: [
49-
TextButton(
50-
onPressed: () => Navigator.of(context).pop(),
51-
child: Text("Cancel"),
11+
context: context,
12+
builder: (context) => _RegularWindowEditDialog(
13+
controller: controller, onClose: () => Navigator.pop(context)));
14+
}
15+
16+
class _RegularWindowEditDialog extends StatefulWidget {
17+
const _RegularWindowEditDialog(
18+
{required this.controller, required this.onClose});
19+
20+
final RegularWindowController controller;
21+
final VoidCallback onClose;
22+
23+
@override
24+
State<StatefulWidget> createState() => _RegularWindowEditDialogState();
25+
}
26+
27+
class _RegularWindowEditDialogState extends State<_RegularWindowEditDialog> {
28+
late Size initialSize;
29+
late String initialTitle;
30+
late bool initialFullscreen;
31+
late bool initialMaximized;
32+
late bool initialMinimized;
33+
34+
late final TextEditingController widthController;
35+
late final TextEditingController heightController;
36+
late final TextEditingController titleController;
37+
38+
bool? nextIsFullscreen;
39+
bool? nextIsMaximized;
40+
bool? nextIsMinized;
41+
42+
@override
43+
void initState() {
44+
super.initState();
45+
initialSize = widget.controller.contentSize;
46+
initialTitle = ""; // TODO: Get the title
47+
initialFullscreen = widget.controller.isFullscreen();
48+
initialMaximized = widget.controller.isMaximized();
49+
initialMinimized = widget.controller.isMinimized();
50+
51+
widthController = TextEditingController(text: initialSize.width.toString());
52+
heightController =
53+
TextEditingController(text: initialSize.height.toString());
54+
titleController = TextEditingController(text: initialTitle);
55+
56+
widget.controller.addListener(_onNotification);
57+
}
58+
59+
void _onNotification() {
60+
// We listen on the state of the controller. If a value that the user
61+
// can edit changes from what it was initially set to, we invalidate
62+
// their current change and store the new "initial" value.
63+
if (widget.controller.contentSize != initialSize) {
64+
initialSize = widget.controller.contentSize;
65+
widthController.text = widget.controller.contentSize.width.toString();
66+
heightController.text = widget.controller.contentSize.height.toString();
67+
}
68+
if (widget.controller.isFullscreen() != initialFullscreen) {
69+
setState(() {
70+
initialFullscreen = widget.controller.isFullscreen();
71+
nextIsFullscreen = null;
72+
});
73+
}
74+
if (widget.controller.isMaximized() != initialMaximized) {
75+
setState(() {
76+
initialMaximized = widget.controller.isMaximized();
77+
nextIsMaximized = null;
78+
});
79+
}
80+
if (widget.controller.isMinimized() != initialMinimized) {
81+
setState(() {
82+
initialMinimized = widget.controller.isMinimized();
83+
nextIsMinized = null;
84+
});
85+
}
86+
}
87+
88+
@override
89+
void dispose() {
90+
super.dispose();
91+
widget.controller.removeListener(_onNotification);
92+
}
93+
94+
@override
95+
Widget build(BuildContext context) {
96+
return AlertDialog(
97+
title: Text("Edit Window Properties"),
98+
content: Column(
99+
mainAxisSize: MainAxisSize.min,
100+
children: [
101+
TextField(
102+
controller: widthController,
103+
keyboardType: TextInputType.number,
104+
decoration: InputDecoration(labelText: "Width"),
52105
),
53-
TextButton(
54-
onPressed: () {
55-
double? width = double.tryParse(widthController.text);
56-
double? height = double.tryParse(heightController.text);
57-
String? title = titleController.text.isEmpty ? null : titleController.text;
58-
59-
onSave?.call(width, height, title);
60-
Navigator.of(context).pop();
61-
},
62-
child: Text("Save"),
106+
TextField(
107+
controller: heightController,
108+
keyboardType: TextInputType.number,
109+
decoration: InputDecoration(labelText: "Height"),
63110
),
111+
TextField(
112+
controller: titleController,
113+
decoration: InputDecoration(labelText: "Title"),
114+
),
115+
CheckboxListTile(
116+
title: const Text('Fullscreen'),
117+
value: nextIsFullscreen ?? initialFullscreen,
118+
onChanged: (bool? value) {
119+
if (value != null) {
120+
setState(() => nextIsFullscreen = value);
121+
}
122+
}),
123+
CheckboxListTile(
124+
title: const Text('Maximized'),
125+
value: nextIsMaximized ?? initialMaximized,
126+
onChanged: (bool? value) {
127+
if (value != null) {
128+
setState(() => nextIsMaximized = value);
129+
}
130+
}),
131+
CheckboxListTile(
132+
title: const Text('Minimized'),
133+
value: nextIsMinized ?? initialMinimized,
134+
onChanged: (bool? value) {
135+
if (value != null) {
136+
setState(() => nextIsMinized = value);
137+
}
138+
})
64139
],
140+
),
141+
actions: [
142+
TextButton(
143+
onPressed: () => widget.onClose(),
144+
child: Text("Cancel"),
145+
),
146+
TextButton(
147+
onPressed: () => _onSave(),
148+
child: Text("Save"),
149+
),
150+
],
151+
);
152+
}
153+
154+
void _onSave() {
155+
double? width = double.tryParse(widthController.text);
156+
double? height = double.tryParse(heightController.text);
157+
String? title = titleController.text.isEmpty ? null : titleController.text;
158+
if (width != null && height != null) {
159+
widget.controller.updateContentSize(
160+
WindowSizing(preferredSize: Size(width, height)),
65161
);
66-
},
67-
);
162+
}
163+
if (title != null) {
164+
widget.controller.setTitle(title);
165+
}
166+
if (nextIsFullscreen != null) {
167+
if (widget.controller.isFullscreen() != nextIsFullscreen) {
168+
widget.controller.setFullscreen(nextIsFullscreen!);
169+
}
170+
}
171+
if (nextIsMaximized != null) {
172+
if (widget.controller.isMaximized() != nextIsMaximized) {
173+
widget.controller.setMaximized(nextIsMaximized!);
174+
}
175+
}
176+
if (nextIsMinized != null) {
177+
if (widget.controller.isMinimized() != nextIsMinized) {
178+
widget.controller.setMinimized(nextIsMinized!);
179+
}
180+
}
181+
182+
widget.onClose();
183+
}
68184
}

0 commit comments

Comments
 (0)