Skip to content

Commit 4695c17

Browse files
aloisdenielclaude
andcommitted
Improve design system: new widgets, bug fixes, no more black window at launch
New widgets: OmarchyDialog (+showOmarchyDialog/showOmarchyConfirmDialog), OmarchyContextMenuArea/showOmarchyContextMenu, showOmarchyToast, OmarchySlider, OmarchyRadio and OmarchyBadge, all covered in the gallery example and by widget tests. Fixes across existing components: tab close buttons now invoke onClose, command panel keyboard navigation works, select highlights the selected option, PanelSize.absolute resolves to its own size, split panel honors min/max sizes and vertical orientation, status bar trailing grouping, divider orientation semantics, button style equality, and several controller/focus-node lifecycle fixes. The Linux runners (example, examples/app) and the omarchy_app template now only show the GTK window after Flutter renders its first frame, removing the black window at startup; documented in the README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VuFFumwANFHGJH6eHFmcjD
1 parent 4bcf9cd commit 4695c17

35 files changed

Lines changed: 2137 additions & 135 deletions

examples/app/packages/app/linux/runner/my_application.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ struct _MyApplication {
1414

1515
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
1616

17+
// Called when the first Flutter frame is received. The window is only shown
18+
// at this point, so the user never sees the default (black) surface that
19+
// backs the Flutter view before rendering starts.
20+
static void first_frame_cb(MyApplication* self, FlView* view) {
21+
gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));
22+
}
23+
1724
// Implements GApplication::activate.
1825
static void my_application_activate(GApplication* application) {
1926
MyApplication* self = MY_APPLICATION(application);
@@ -48,7 +55,6 @@ static void my_application_activate(GApplication* application) {
4855
}
4956

5057
gtk_window_set_default_size(window, 1280, 720);
51-
gtk_widget_show(GTK_WIDGET(window));
5258

5359
g_autoptr(FlDartProject) project = fl_dart_project_new();
5460
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
@@ -57,6 +63,12 @@ static void my_application_activate(GApplication* application) {
5763
gtk_widget_show(GTK_WIDGET(view));
5864
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
5965

66+
// Show the window when Flutter renders its first frame. The view must be
67+
// realized so rendering can start while the window is still hidden.
68+
g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb),
69+
self);
70+
gtk_widget_realize(GTK_WIDGET(view));
71+
6072
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
6173

6274
gtk_widget_grab_focus(GTK_WIDGET(view));

packages/flutter_omarchy/CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
1+
## 0.3.0
2+
3+
### New widgets
4+
5+
* `OmarchyDialog`, `showOmarchyDialog` and `showOmarchyConfirmDialog` for modal dialogs.
6+
* `OmarchyContextMenuArea` and `showOmarchyContextMenu` for right-click context menus (with icons, shortcut hints, accents, disabled items and dividers).
7+
* `showOmarchyToast` for transient notifications stacked at the bottom right of the screen.
8+
* `OmarchySlider`, a horizontal slider with divisions and keyboard support.
9+
* `OmarchyRadio`, a radio button for single-choice groups.
10+
* `OmarchyBadge`, a small status/count label (filled and outlined).
11+
12+
### Improvements
13+
14+
* `OmarchyTab.closable` now actually invokes `onClose` when the close icon is pressed (with its own hover feedback).
15+
* `OmarchyCommandPanel` keyboard navigation (arrows, Enter, Escape) now works, and the item list refreshes when `items` changes.
16+
* `OmarchySelect` now highlights the currently selected option in the dropdown.
17+
* `OmarchyCheckbox`, `OmarchyToggle` and the new `OmarchyRadio` accept a `focusNode` and show a focus highlight; `OmarchyButton` gained `autofocus`.
18+
* `OmarchyTile` gained a `trailing` widget slot.
19+
* `OmarchyResizeDivider` uses the correct resize cursor for vertical splits.
20+
* `OmarchySplitPanel` respects `minPanelSize`/`maxPanelSize` while dragging and sizes the panel correctly in vertical orientation.
21+
* `PanelSize.absolute` now resolves to its own size instead of the available space.
22+
* `OmarchyStatusBar` renders `trailing` statuses with proper grouping.
23+
* The Linux runner of the example (and the `omarchy_app` template) now waits for Flutter's first frame before showing the window, removing the black window at startup. See the README section "Avoid the Black Window at Startup".
24+
* Lifecycle fixes: external `OmarchySidePanelController`s are no longer disposed by the panel, `OmarchyFocusBorder` disposes its internal focus node, and theme config reloads no longer call `setState` after unmount.
25+
26+
### Breaking changes
27+
28+
* `OmarchyDivider` semantics were inverted and have been fixed: `direction` is now the axis along which the line extends (`OmarchyDivider.horizontal()` is a full-width line for columns, `OmarchyDivider.vertical()` a full-height line for rows). The default is now horizontal.
29+
* Removed the unused `padding` parameter of `OmarchyButton` (use the style's `padding` instead).
30+
* Removed the unused `alignment` parameter of `OmarchyPopOverContainer`.
31+
* Removed the unimplemented `OmarchyBordered` placeholder.
32+
133
## 0.2.0
234

335
* Support for the latest Omarchy theming system: colors are now read from the canonical `~/.local/state/omarchy/current/theme/colors.toml` palette.

packages/flutter_omarchy/README.md

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class MyApp extends StatelessWidget {
3737
Widget build(BuildContext context) {
3838
return OmarchyApp(
3939
home: OmarchyScaffold(
40-
body: Center(
40+
child: Center(
4141
child: OmarchyButton(
4242
onPressed: () {},
4343
child: Text('Hello Omarchy!'),
@@ -102,41 +102,90 @@ Omarchy provides a rich set of widgets:
102102

103103
#### Basic Widgets
104104

105-
- `OmarchyButton`: Terminal-style button
105+
- `OmarchyButton`: Terminal-style button (outline, filled and bar styles)
106106
- `OmarchyTextInput`: Text input field
107107
- `OmarchyCheckbox`: Checkbox component
108+
- `OmarchyRadio`: Radio button for single-choice groups
109+
- `OmarchyToggle`: On/off toggle switch
110+
- `OmarchySlider`: Horizontal slider with keyboard support
111+
- `OmarchySelect`: Dropdown selection
108112
- `OmarchyTile`: List tile component
113+
- `OmarchyBadge`: Small status or count label
114+
- `OmarchyProgressBar`: Progress indicator
115+
- `OmarchyLoader`: Animated loading indicator
109116

110117
#### Navigation
111118

112119
- `OmarchyScaffold`: Main layout container
113-
- `OmarchyNavigationBar`: Side navigation bar
114-
- `OmarchyTabs`: Tabbed interface
120+
- `OmarchyNavigationBar`: Top navigation bar with leading/trailing actions
121+
- `OmarchyTabs`: Tabbed interface with closable tabs
115122
- `OmarchyStatusBar`: Status bar for displaying app state
123+
- `OmarchyTree`: Tree view for hierarchical data
116124

117125
#### Layout
118126

119127
- `OmarchyDivider`: Horizontal or vertical divider
128+
- `OmarchySplitPanel`: Resizable two-pane layout
129+
- `OmarchySidePanel`: Overlay side panel (drawer)
120130
- `OmarchyResizeDivider`: Resizable divider for split views
121131

122-
#### Utility
132+
#### Overlays
123133

124134
- `OmarchyTooltip`: Tooltip component
125135
- `OmarchyPopOver`: Popup overlay
136+
- `OmarchyDialog` / `showOmarchyDialog` / `showOmarchyConfirmDialog`: Modal dialogs
137+
- `OmarchyContextMenuArea` / `showOmarchyContextMenu`: Right-click context menus
138+
- `showOmarchyToast`: Transient notifications stacked at the bottom right
139+
- `OmarchyCommandPanel` / `showOmarchyCommandPanel`: Command palette
126140

127141
## Bundling the app for Omarchy
128142

129143
To bundle and run your Flutter Omarchy application on Linux, follow these steps:
130144

131145
### Remove the Title Bar
132146

133-
Flutter Linux apps are GTK windows. To remove the default title bar, edit `linux/runner/my_application.cc`.
147+
Flutter Linux apps are GTK windows. To remove the default GTK header bar, edit `linux/runner/my_application.cc` and disable it:
134148

135-
Remove the code related to the title bar:
149+
```c
150+
gboolean use_header_bar = FALSE;
151+
```
152+
153+
Under Hyprland (Omarchy's compositor) windows are tiled and undecorated, so this is all that is needed for a clean, borderless window. Rebuild the app to apply the change. The `omarchy_app` mason template applies this automatically.
154+
155+
### Avoid the Black Window at Startup
156+
157+
By default, older Flutter Linux runners show the GTK window immediately, before Flutter has rendered anything. Since the Flutter view's surface defaults to black, the window appears filled with black for a moment at startup, before the theme background is painted.
158+
159+
The fix is to keep the window hidden until Flutter has rendered its first frame, using the `first-frame` signal of `FlView`. Recent Flutter versions (3.22+) generate a `linux/runner/my_application.cc` that already does this. If your runner was generated by an older Flutter version, update `my_application_activate` in `linux/runner/my_application.cc`:
160+
161+
```c
162+
// Called when the first Flutter frame is received: only show the
163+
// window at this point to avoid a black window at startup.
164+
static void first_frame_cb(MyApplication* self, FlView* view) {
165+
gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));
166+
}
167+
168+
static void my_application_activate(GApplication* application) {
169+
// ...
170+
gtk_window_set_default_size(window, 1280, 720);
171+
// Do NOT call gtk_widget_show(GTK_WIDGET(window)) here.
172+
173+
FlView* view = fl_view_new(project);
174+
gtk_widget_show(GTK_WIDGET(view));
175+
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
136176

137-
> TODO
177+
// Show the window when Flutter renders its first frame. The view must be
178+
// realized so rendering can start while the window is still hidden.
179+
g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb),
180+
self);
181+
gtk_widget_realize(GTK_WIDGET(view));
182+
183+
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
184+
gtk_widget_grab_focus(GTK_WIDGET(view));
185+
}
186+
```
138187
139-
Rebuild the app, and you’ll have a clean, borderless window.
188+
The `omarchy_app` mason template applies this patch automatically when the generated runner does not already handle it.
140189
141190
### Building the Linux Bundle
142191
@@ -242,9 +291,10 @@ flutter run --app=pomodoro
242291
* Preconfigured HJKL shortcuts for navigation
243292
* Specific ormarchy theme configuration (colors, hide nav bar, ...)
244293
* Widgets
245-
* Toasts
246-
* Progress
247294
* Skeleton
295+
* Menu bar
296+
* Date/time pickers
297+
* Table / data grid
248298
* Examples
249299
* Todo list
250300
* AI Chat

packages/flutter_omarchy/example/lib/calculator/app.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class _CalculatorPageState extends State<CalculatorPage> {
9494
child = Row(
9595
children: [
9696
Expanded(child: FadeIn(child: HistoryPane())),
97-
OmarchyDivider.horizontal(),
97+
OmarchyDivider.vertical(),
9898
SizedBox(width: 1000, child: child),
9999
],
100100
);

0 commit comments

Comments
 (0)