wip popovers

This commit is contained in:
Henry Hiles 2026-04-24 21:22:59 -04:00
commit 6d25568c59
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
7 changed files with 136 additions and 55 deletions

View file

@ -9,5 +9,9 @@ extension SchemeToTheme on ColorScheme {
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
popupMenuTheme: PopupMenuThemeData(
color: Colors.transparent,
shadowColor: Colors.transparent,
),
);
}

View file

@ -3,6 +3,7 @@ import 'package:flight/helpers/extensions/scheme_to_theme.dart';
import 'package:flight/src/rust/frb_generated.dart';
import 'package:flight/widgets/bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:wayland_layer_shell/types.dart';
import 'package:wayland_layer_shell/wayland_layer_shell.dart';
@ -38,7 +39,9 @@ void main() async {
brightness: Brightness.dark,
))
.theme,
home: Scaffold(body: Bar(), backgroundColor: Colors.transparent),
home: Portal(
child: Scaffold(body: Bar(), backgroundColor: Colors.transparent),
),
),
),
),

View file

@ -1,6 +1,7 @@
import 'package:collection/collection.dart';
import 'package:flight/controllers/time_controller.dart';
import 'package:flight/controllers/workspaces_controller.dart';
import 'package:flight/widgets/bubble.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
@ -21,7 +22,8 @@ class Bar extends ConsumerWidget {
loading: () => [SizedBox.shrink()],
data: (value) => value
.map(
(group) => Row(
(group) => Bubble(
Row(
children: group
.map(
(workspace) => IconButton(
@ -35,12 +37,27 @@ class Bar extends ConsumerWidget {
)
.toList(),
),
),
)
.toList(),
),
[
TextButton(
onPressed: () {},
Bubble(
popover: Bubble(
Padding(
padding: EdgeInsetsGeometry.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
DateFormat.MMMMEEEEd().format(DateTime.now()),
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
),
Center(
child: Text(
DateFormat.Hm().format(
ref
@ -53,13 +70,18 @@ class Bar extends ConsumerWidget {
),
),
),
),
],
[
Bubble(
Row(
children: [
IconButton(onPressed: () {}, icon: Icon(Icons.wifi)),
IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)),
IconButton(
onPressed: () {},
icon: Icon(Icons.bluetooth),
),
IconButton(
onPressed: () {},
@ -67,36 +89,20 @@ class Bar extends ConsumerWidget {
),
],
),
),
],
]
.mapIndexed(
(index, children) => Align(
alignment: [
Alignment.centerLeft,
Alignment.center,
Alignment.centerRight,
Alignment.bottomLeft,
Alignment.bottomCenter,
Alignment.bottomRight,
][index],
child: Row(
spacing: 8,
mainAxisSize: MainAxisSize.min,
children: children
.map(
(child) => Padding(
padding: EdgeInsetsGeometry.directional(bottom: 6),
child: Container(
height: 42,
padding: EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Theme.of(
context,
).colorScheme.surfaceContainerLow,
borderRadius: BorderRadius.circular(999),
),
child: child,
),
),
)
.toList(),
children: children,
),
),
)

58
lib/widgets/bubble.dart Normal file
View file

@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:wayland_layer_shell/types.dart';
import 'package:wayland_layer_shell/wayland_layer_shell.dart';
class Bubble extends HookWidget {
final Widget child;
final Widget? popover;
const Bubble(this.child, {this.popover, super.key});
@override
Widget build(BuildContext context) {
final isVisible = useState(false);
return PortalTarget(
visible: isVisible.value,
anchor: const Filled(),
portalFollower: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
isVisible.value = false;
WaylandLayerShell().setAnchor(ShellEdge.edgeTop, false);
},
),
child: PortalTarget(
visible: isVisible.value,
anchor: Aligned(
follower: Alignment.bottomCenter,
target: Alignment.topCenter,
),
portalFollower: popover,
child: Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Material(
color: Theme.of(context).colorScheme.surfaceContainerLow,
borderRadius: BorderRadius.circular(999),
child: InkWell(
borderRadius: BorderRadius.circular(999),
onTap: popover == null
? null
: () async {
await WaylandLayerShell().setAnchor(
ShellEdge.edgeTop,
true,
);
isVisible.value = true;
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: child,
),
),
),
),
),
);
}
}

View file

@ -248,7 +248,7 @@ packages:
source: sdk
version: "0.0.0"
flutter_hooks:
dependency: transitive
dependency: "direct main"
description:
name: flutter_hooks
sha256: "8ae1f090e5f4ef5cfa6670ce1ab5dddadd33f3533a7f9ba19d9f958aa2a89f42"
@ -268,6 +268,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_portal:
dependency: "direct main"
description:
name: flutter_portal
sha256: "4601b3dc24f385b3761721bd852a3f6c09cddd4e943dd184ed58ee1f43006257"
url: "https://pub.dev"
source: hosted
version: "1.1.4"
flutter_riverpod:
dependency: "direct main"
description:

View file

@ -25,6 +25,8 @@ dependencies:
path: rust_builder
flutter_rust_bridge: 2.11.1
collection: ^1.19.1
flutter_hooks: ^0.21.3+1
flutter_portal: ^1.1.4
dev_dependencies:
build_runner: ^2.13.1

View file

@ -63,7 +63,7 @@ impl AppState {
})
.collect();
self.sink.add(result).expect("Updating stream failed");
let _ = self.sink.add(result);
}
}