working workspaces

This commit is contained in:
Henry Hiles 2026-04-19 15:57:01 -04:00
commit add25edbdc
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
9 changed files with 581 additions and 358 deletions

View file

@ -1,12 +1,12 @@
import "package:flight/src/rust/api/workspace_api.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
class WorkspacesController extends StreamNotifier<List<Workspace>> {
class WorkspacesController extends StreamNotifier<List<List<Workspace>>> {
@override
Stream<List<Workspace>> build() => listenWorkspaces();
Stream<List<List<Workspace>>> build() => listenWorkspaces();
static final provider =
StreamNotifierProvider<WorkspacesController, List<Workspace>>(
StreamNotifierProvider<WorkspacesController, List<List<Workspace>>>(
WorkspacesController.new,
);
}

View file

@ -6,9 +6,9 @@
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt`
Stream<List<Workspace>> listenWorkspaces() =>
Stream<List<List<Workspace>>> listenWorkspaces() =>
RustLib.instance.api.crateApiWorkspaceApiListenWorkspaces();
class Workspace {

View file

@ -75,7 +75,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
}
abstract class RustLibApi extends BaseApi {
Stream<List<Workspace>> crateApiWorkspaceApiListenWorkspaces();
Stream<List<List<Workspace>>> crateApiWorkspaceApiListenWorkspaces();
}
class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@ -87,14 +87,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
});
@override
Stream<List<Workspace>> crateApiWorkspaceApiListenWorkspaces() {
final sink = RustStreamSink<List<Workspace>>();
Stream<List<List<Workspace>>> crateApiWorkspaceApiListenWorkspaces() {
final sink = RustStreamSink<List<List<Workspace>>>();
unawaited(
handler.executeNormal(
NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_StreamSink_list_workspace_Sse(sink, serializer);
sse_encode_StreamSink_list_list_workspace_Sse(sink, serializer);
pdeCallFfi(
generalizedFrbRustBinding,
serializer,
@ -125,9 +125,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}
@protected
RustStreamSink<List<Workspace>> dco_decode_StreamSink_list_workspace_Sse(
dynamic raw,
) {
RustStreamSink<List<List<Workspace>>>
dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
throw UnimplementedError();
}
@ -144,6 +143,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as bool;
}
@protected
List<List<Workspace>> dco_decode_list_list_workspace(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return (raw as List<dynamic>).map(dco_decode_list_workspace).toList();
}
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@ -185,9 +190,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}
@protected
RustStreamSink<List<Workspace>> sse_decode_StreamSink_list_workspace_Sse(
SseDeserializer deserializer,
) {
RustStreamSink<List<List<Workspace>>>
sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
throw UnimplementedError('Unreachable ()');
}
@ -205,6 +209,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getUint8() != 0;
}
@protected
List<List<Workspace>> sse_decode_list_list_workspace(
SseDeserializer deserializer,
) {
// Codec=Sse (Serialization based), see doc to use other codecs
var len_ = sse_decode_i_32(deserializer);
var ans_ = <List<Workspace>>[];
for (var idx_ = 0; idx_ < len_; ++idx_) {
ans_.add(sse_decode_list_workspace(deserializer));
}
return ans_;
}
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@ -258,15 +276,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}
@protected
void sse_encode_StreamSink_list_workspace_Sse(
RustStreamSink<List<Workspace>> self,
void sse_encode_StreamSink_list_list_workspace_Sse(
RustStreamSink<List<List<Workspace>>> self,
SseSerializer serializer,
) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_String(
self.setupAndSerialize(
codec: SseCodec(
decodeSuccessData: sse_decode_list_workspace,
decodeSuccessData: sse_decode_list_list_workspace,
decodeErrorData: sse_decode_AnyhowException,
),
),
@ -286,6 +304,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
serializer.buffer.putUint8(self ? 1 : 0);
}
@protected
void sse_encode_list_list_workspace(
List<List<Workspace>> self,
SseSerializer serializer,
) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_i_32(self.length, serializer);
for (final item in self) {
sse_encode_list_workspace(item, serializer);
}
}
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self,

View file

@ -22,9 +22,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
RustStreamSink<List<Workspace>> dco_decode_StreamSink_list_workspace_Sse(
dynamic raw,
);
RustStreamSink<List<List<Workspace>>>
dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@ -32,6 +31,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool dco_decode_bool(dynamic raw);
@protected
List<List<Workspace>> dco_decode_list_list_workspace(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@ -51,9 +53,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
RustStreamSink<List<Workspace>> sse_decode_StreamSink_list_workspace_Sse(
SseDeserializer deserializer,
);
RustStreamSink<List<List<Workspace>>>
sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer);
@protected
String sse_decode_String(SseDeserializer deserializer);
@ -61,6 +62,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
List<List<Workspace>> sse_decode_list_list_workspace(
SseDeserializer deserializer,
);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@ -86,8 +92,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
);
@protected
void sse_encode_StreamSink_list_workspace_Sse(
RustStreamSink<List<Workspace>> self,
void sse_encode_StreamSink_list_list_workspace_Sse(
RustStreamSink<List<List<Workspace>>> self,
SseSerializer serializer,
);
@ -97,6 +103,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_list_list_workspace(
List<List<Workspace>> self,
SseSerializer serializer,
);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self,

View file

@ -24,9 +24,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected
RustStreamSink<List<Workspace>> dco_decode_StreamSink_list_workspace_Sse(
dynamic raw,
);
RustStreamSink<List<List<Workspace>>>
dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw);
@protected
String dco_decode_String(dynamic raw);
@ -34,6 +33,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool dco_decode_bool(dynamic raw);
@protected
List<List<Workspace>> dco_decode_list_list_workspace(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@ -53,9 +55,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected
RustStreamSink<List<Workspace>> sse_decode_StreamSink_list_workspace_Sse(
SseDeserializer deserializer,
);
RustStreamSink<List<List<Workspace>>>
sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer);
@protected
String sse_decode_String(SseDeserializer deserializer);
@ -63,6 +64,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
List<List<Workspace>> sse_decode_list_list_workspace(
SseDeserializer deserializer,
);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@ -88,8 +94,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
);
@protected
void sse_encode_StreamSink_list_workspace_Sse(
RustStreamSink<List<Workspace>> self,
void sse_encode_StreamSink_list_list_workspace_Sse(
RustStreamSink<List<List<Workspace>>> self,
SseSerializer serializer,
);
@ -99,6 +105,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_list_list_workspace(
List<List<Workspace>> self,
SseSerializer serializer,
);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self,

View file

@ -16,52 +16,67 @@ class Bar extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children:
[
ref
.watch(WorkspacesController.provider)
.whenOrNull(
error: (error, stackTrace) => [
Text(error.toString()),
],
data: (value) {
return value
.map(
(element) => IconButton(
onPressed: () {},
icon: Icon(
element.activated
? Icons.circle
: Icons.circle_outlined,
...ref
.watch(WorkspacesController.provider)
.when(
error: (error, stackTrace) => [Text(error.toString())],
loading: () => [],
data: (value) => value
.map(
(group) => Row(
children: group
.map(
(workspace) => IconButton(
onPressed: () {},
icon: Icon(
workspace.activated
? Icons.circle
: Icons.circle_outlined,
),
),
),
)
.toList();
},
) ??
[],
[
TextButton(
onPressed: () {},
child: Text(
DateFormat.Hm().format(
ref
.watch(TimeController.provider)
.when(
data: (time) => time,
loading: DateTime.now,
error: (_, _) => DateTime.now(),
)
.toList(),
),
),
)
.toList(),
),
Center(
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () {},
child: Text(
DateFormat.Hm().format(
ref
.watch(TimeController.provider)
.when(
data: (time) => time,
loading: DateTime.now,
error: (_, _) => DateTime.now(),
),
),
),
),
],
),
],
[
IconButton(onPressed: () {}, icon: Icon(Icons.wifi)),
IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)),
IconButton(onPressed: () {}, icon: Icon(Icons.volume_off)),
],
),
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(onPressed: () {}, icon: Icon(Icons.wifi)),
IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)),
IconButton(
onPressed: () {},
icon: Icon(Icons.volume_off),
),
],
),
]
.map(
(children) => Padding(
(child) => Padding(
padding: EdgeInsetsGeometry.directional(bottom: 6),
child: Container(
height: 42,
@ -72,11 +87,7 @@ class Bar extends ConsumerWidget {
).colorScheme.surfaceContainerLow,
borderRadius: BorderRadius.circular(999),
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
child: child,
),
),
)

View file

@ -4,12 +4,12 @@ use std::collections::HashMap;
use crate::{frb_generated::StreamSink, internal::wayland::AppState};
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Workspace {
pub activated: bool,
}
pub fn listen_workspaces(sink: StreamSink<Vec<Workspace>>) -> Result<()> {
pub fn listen_workspaces(sink: StreamSink<Vec<Vec<Workspace>>>) -> Result<()> {
std::thread::spawn(move || {
let conn = Connection::connect_to_env().expect("Failed to connect to Wayland");
@ -18,6 +18,8 @@ pub fn listen_workspaces(sink: StreamSink<Vec<Workspace>>) -> Result<()> {
let mut state = AppState {
workspaces: HashMap::new(),
workspace_group: HashMap::new(),
workspace_coords: HashMap::new(),
sink,
};

View file

@ -2,43 +2,42 @@
// @generated by `flutter_rust_bridge`@ 2.11.1.
#![allow(
non_camel_case_types,
unused,
non_snake_case,
clippy::needless_return,
clippy::redundant_closure_call,
clippy::redundant_closure,
clippy::useless_conversion,
clippy::unit_arg,
clippy::unused_unit,
clippy::double_parens,
clippy::let_and_return,
clippy::too_many_arguments,
clippy::match_single_binding,
clippy::clone_on_copy,
clippy::let_unit_value,
clippy::deref_addrof,
clippy::explicit_auto_deref,
clippy::borrow_deref_ref,
clippy::needless_borrow
non_camel_case_types,
unused,
non_snake_case,
clippy::needless_return,
clippy::redundant_closure_call,
clippy::redundant_closure,
clippy::useless_conversion,
clippy::unit_arg,
clippy::unused_unit,
clippy::double_parens,
clippy::let_and_return,
clippy::too_many_arguments,
clippy::match_single_binding,
clippy::clone_on_copy,
clippy::let_unit_value,
clippy::deref_addrof,
clippy::explicit_auto_deref,
clippy::borrow_deref_ref,
clippy::needless_borrow
)]
// Section: imports
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};
use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable};
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};
// Section: boilerplate
flutter_rust_bridge::frb_generated_boilerplate!(
default_stream_sink_codec = SseCodec,
default_rust_opaque = RustOpaqueMoi,
default_rust_auto_opaque = RustAutoOpaqueMoi,
);
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831;
default_stream_sink_codec = SseCodec,
default_rust_opaque = RustOpaqueMoi,
default_rust_auto_opaque = RustAutoOpaqueMoi,
);
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831;
// Section: executor
@ -46,226 +45,333 @@ flutter_rust_bridge::frb_generated_default_handler!();
// Section: wire_funcs
fn wire__crate__api__workspace_api__listen_workspaces_impl(port_: flutter_rust_bridge::for_generated::MessagePort,ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,rust_vec_len_: i32,data_len_: i32) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec,_,_>(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "listen_workspaces", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || {
let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) };
let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message);
let api_sink = <StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec>>::sse_decode(&mut deserializer);deserializer.end(); move |context| {
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || {
let output_ok = crate::api::workspace_api::listen_workspaces(api_sink)?; Ok(output_ok)
})())
} })
fn wire__crate__api__workspace_api__listen_workspaces_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
rust_vec_len_: i32,
data_len_: i32,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "listen_workspaces",
port: Some(port_),
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
},
move || {
let message = unsafe {
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
ptr_,
rust_vec_len_,
data_len_,
)
};
let mut deserializer =
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
let api_sink = <StreamSink<
Vec<Vec<crate::api::workspace_api::Workspace>>,
flutter_rust_bridge::for_generated::SseCodec,
>>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
(move || {
let output_ok = crate::api::workspace_api::listen_workspaces(api_sink)?;
Ok(output_ok)
})(),
)
}
},
)
}
// Section: dart2rust
impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut inner = <String>::sse_decode(deserializer);
return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);
}
}
impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = <String>::sse_decode(deserializer);
return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);}
}
impl SseDecode
for StreamSink<
Vec<Vec<crate::api::workspace_api::Workspace>>,
flutter_rust_bridge::for_generated::SseCodec,
>
{
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut inner = <String>::sse_decode(deserializer);
return StreamSink::deserialize(inner);
}
}
impl SseDecode for StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = <String>::sse_decode(deserializer);
return StreamSink::deserialize(inner);}
}
impl SseDecode for String {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut inner = <Vec<u8>>::sse_decode(deserializer);
return String::from_utf8(inner).unwrap();
}
}
impl SseDecode for String {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = <Vec<u8>>::sse_decode(deserializer);
return String::from_utf8(inner).unwrap();}
}
impl SseDecode for bool {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
deserializer.cursor.read_u8().unwrap() != 0
}
}
impl SseDecode for bool {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {deserializer.cursor.read_u8().unwrap() != 0}
}
impl SseDecode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut len_ = <i32>::sse_decode(deserializer);
impl SseDecode for Vec<Vec<crate::api::workspace_api::Workspace>> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut len_ = <i32>::sse_decode(deserializer);
let mut ans_ = vec![];
for idx_ in 0..len_ { ans_.push(<u8>::sse_decode(deserializer)); }
return ans_;}
}
for idx_ in 0..len_ {
ans_.push(<Vec<crate::api::workspace_api::Workspace>>::sse_decode(
deserializer,
));
}
return ans_;
}
}
impl SseDecode for Vec<crate::api::workspace_api::Workspace> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut len_ = <i32>::sse_decode(deserializer);
impl SseDecode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut len_ = <i32>::sse_decode(deserializer);
let mut ans_ = vec![];
for idx_ in 0..len_ { ans_.push(<crate::api::workspace_api::Workspace>::sse_decode(deserializer)); }
return ans_;}
}
for idx_ in 0..len_ {
ans_.push(<u8>::sse_decode(deserializer));
}
return ans_;
}
}
impl SseDecode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {deserializer.cursor.read_u8().unwrap()}
}
impl SseDecode for Vec<crate::api::workspace_api::Workspace> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut len_ = <i32>::sse_decode(deserializer);
let mut ans_ = vec![];
for idx_ in 0..len_ {
ans_.push(<crate::api::workspace_api::Workspace>::sse_decode(
deserializer,
));
}
return ans_;
}
}
impl SseDecode for () {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {}
}
impl SseDecode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
deserializer.cursor.read_u8().unwrap()
}
}
impl SseDecode for crate::api::workspace_api::Workspace {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut var_activated = <bool>::sse_decode(deserializer);
return crate::api::workspace_api::Workspace{activated: var_activated};}
}
impl SseDecode for () {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {}
}
impl SseDecode for i32 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {deserializer.cursor.read_i32::<NativeEndian>().unwrap()}
}
impl SseDecode for crate::api::workspace_api::Workspace {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut var_activated = <bool>::sse_decode(deserializer);
return crate::api::workspace_api::Workspace {
activated: var_activated,
};
}
}
fn pde_ffi_dispatcher_primary_impl(
func_id: i32,port: flutter_rust_bridge::for_generated::MessagePort,
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
rust_vec_len: i32,
data_len: i32,
) {
// Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id {
1 => wire__crate__api__workspace_api__listen_workspaces_impl(port, ptr, rust_vec_len, data_len),
_ => unreachable!(),
}
}
impl SseDecode for i32 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
deserializer.cursor.read_i32::<NativeEndian>().unwrap()
}
}
fn pde_ffi_dispatcher_sync_impl(
func_id: i32,
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
rust_vec_len: i32,
data_len: i32,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
// Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id {
_ => unreachable!(),
}
}
fn pde_ffi_dispatcher_primary_impl(
func_id: i32,
port: flutter_rust_bridge::for_generated::MessagePort,
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
rust_vec_len: i32,
data_len: i32,
) {
// Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id {
1 => wire__crate__api__workspace_api__listen_workspaces_impl(
port,
ptr,
rust_vec_len,
data_len,
),
_ => unreachable!(),
}
}
fn pde_ffi_dispatcher_sync_impl(
func_id: i32,
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
rust_vec_len: i32,
data_len: i32,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
// Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id {
_ => unreachable!(),
}
}
// Section: rust2dart
// Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
[
self.activated.into_into_dart().into_dart()
].into_dart()
}
}
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::workspace_api::Workspace {}
impl flutter_rust_bridge::IntoIntoDart<crate::api::workspace_api::Workspace> for crate::api::workspace_api::Workspace {
fn into_into_dart(self) -> crate::api::workspace_api::Workspace {
self
}
impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
[self.activated.into_into_dart().into_dart()].into_dart()
}
}
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
for crate::api::workspace_api::Workspace
{
}
impl flutter_rust_bridge::IntoIntoDart<crate::api::workspace_api::Workspace>
for crate::api::workspace_api::Workspace
{
fn into_into_dart(self) -> crate::api::workspace_api::Workspace {
self
}
}
impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<String>::sse_encode(format!("{:?}", self), serializer);
}
}
impl SseEncode
for StreamSink<
Vec<Vec<crate::api::workspace_api::Workspace>>,
flutter_rust_bridge::for_generated::SseCodec,
>
{
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
unimplemented!("")
}
}
impl SseEncode for String {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<Vec<u8>>::sse_encode(self.into_bytes(), serializer);
}
}
impl SseEncode for bool {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
serializer.cursor.write_u8(self as _).unwrap();
}
}
impl SseEncode for Vec<Vec<crate::api::workspace_api::Workspace>> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<i32>::sse_encode(self.len() as _, serializer);
for item in self {
<Vec<crate::api::workspace_api::Workspace>>::sse_encode(item, serializer);
}
}
}
impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<String>::sse_encode(format!("{:?}", self), serializer);}
}
impl SseEncode for StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {unimplemented!("")}
}
impl SseEncode for String {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<Vec<u8>>::sse_encode(self.into_bytes(), serializer);}
}
impl SseEncode for bool {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {serializer.cursor.write_u8(self as _).unwrap();}
}
impl SseEncode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<i32>::sse_encode(self.len() as _, serializer);
for item in self { <u8>::sse_encode(item, serializer); }}
}
impl SseEncode for Vec<crate::api::workspace_api::Workspace> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<i32>::sse_encode(self.len() as _, serializer);
for item in self { <crate::api::workspace_api::Workspace>::sse_encode(item, serializer); }}
}
impl SseEncode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {serializer.cursor.write_u8(self).unwrap();}
}
impl SseEncode for () {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {}
}
impl SseEncode for crate::api::workspace_api::Workspace {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<bool>::sse_encode(self.activated, serializer);}
}
impl SseEncode for i32 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {serializer.cursor.write_i32::<NativeEndian>(self).unwrap();}
}
#[cfg(not(target_family = "wasm"))]
mod io {
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// Section: imports
use flutter_rust_bridge::{Handler, IntoIntoDart};
use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable};
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};use super::*;
// Section: boilerplate
flutter_rust_bridge::frb_generated_boilerplate_io!();
impl SseEncode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<i32>::sse_encode(self.len() as _, serializer);
for item in self {
<u8>::sse_encode(item, serializer);
}
#[cfg(not(target_family = "wasm"))]
pub use io::*;
/// cbindgen:ignore
#[cfg(target_family = "wasm")]
mod web {
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// Section: imports
use flutter_rust_bridge::{Handler, IntoIntoDart};
use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable};
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};use super::*;
use flutter_rust_bridge::for_generated::wasm_bindgen;
use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*;
// Section: boilerplate
flutter_rust_bridge::frb_generated_boilerplate_web!();
}
}
impl SseEncode for Vec<crate::api::workspace_api::Workspace> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<i32>::sse_encode(self.len() as _, serializer);
for item in self {
<crate::api::workspace_api::Workspace>::sse_encode(item, serializer);
}
#[cfg(target_family = "wasm")]
pub use web::*;
}
}
impl SseEncode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
serializer.cursor.write_u8(self).unwrap();
}
}
impl SseEncode for () {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {}
}
impl SseEncode for crate::api::workspace_api::Workspace {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<bool>::sse_encode(self.activated, serializer);
}
}
impl SseEncode for i32 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
serializer.cursor.write_i32::<NativeEndian>(self).unwrap();
}
}
#[cfg(not(target_family = "wasm"))]
mod io {
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// Section: imports
use super::*;
use flutter_rust_bridge::for_generated::byteorder::{
NativeEndian, ReadBytesExt, WriteBytesExt,
};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};
// Section: boilerplate
flutter_rust_bridge::frb_generated_boilerplate_io!();
}
#[cfg(not(target_family = "wasm"))]
pub use io::*;
/// cbindgen:ignore
#[cfg(target_family = "wasm")]
mod web {
// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.11.1.
// Section: imports
use super::*;
use flutter_rust_bridge::for_generated::byteorder::{
NativeEndian, ReadBytesExt, WriteBytesExt,
};
use flutter_rust_bridge::for_generated::wasm_bindgen;
use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*;
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};
// Section: boilerplate
flutter_rust_bridge::frb_generated_boilerplate_web!();
}
#[cfg(target_family = "wasm")]
pub use web::*;

View file

@ -2,38 +2,62 @@ use crate::{frb_generated::StreamSink, workspace_api::Workspace};
use std::collections::HashMap;
use wayland_client::{
self, Connection, Dispatch, QueueHandle, backend::ObjectId, event_created_child, protocol::wl_registry
self, backend::ObjectId, Proxy, Connection, Dispatch, QueueHandle, event_created_child,
protocol::wl_registry,
};
use wayland_protocols::ext::workspace::v1::client::{
ext_workspace_group_handle_v1, ext_workspace_handle_v1, ext_workspace_manager_v1,
};
// ------------------------
// App State
// ------------------------
pub struct AppState {
pub workspaces: HashMap<ObjectId, Workspace>,
pub sink: StreamSink<Vec<Workspace>>,
pub workspace_group: HashMap<ObjectId, ObjectId>, // workspace -> group
pub workspace_coords: HashMap<ObjectId, (u8, u8)>,
pub sink: StreamSink<Vec<Vec<Workspace>>>,
}
impl AppState {
fn emit(&self) {
let mut entries: Vec<(&ObjectId, &Workspace)> = self.workspaces.iter().collect();
fn emit(&self) {
let mut groups: HashMap<ObjectId, Vec<(&ObjectId, &Workspace)>> = HashMap::new();
entries.sort_by_key(
|entry: &(&ObjectId, &Workspace)| -> u32 {
entry.0.protocol_id()
},
);
for (ws_id, ws) in &self.workspaces {
if let Some(group_id) = self.workspace_group.get(ws_id) {
groups
.entry(group_id.clone())
.or_insert_with(Vec::new)
.push((ws_id, ws));
}
}
let sorted: Vec<Workspace> = entries
.into_iter()
.map(
|entry: (&ObjectId, &Workspace)| -> Workspace {
entry.1.clone()
},
)
.collect();
let mut grouped: Vec<(ObjectId, Vec<(&ObjectId, &Workspace)>)> =
groups.into_iter().collect();
let _ = self.sink.add(sorted);
}
grouped.sort_by_key(|(group_id, _)| group_id.protocol_id());
let result: Vec<Vec<Workspace>> = grouped
.into_iter()
.map(|(_, mut entries)| {
entries.sort_by_key(|(id, _)| {
self.workspace_coords
.get(id)
.copied()
.unwrap_or((0, 0))
});
entries
.into_iter()
.map(|(_, ws)| ws.clone())
.collect()
})
.collect();
let _ = self.sink.add(result);
}
}
impl Dispatch<wl_registry::WlRegistry, ()> for AppState {
@ -71,18 +95,17 @@ impl Dispatch<ext_workspace_manager_v1::ExtWorkspaceManagerV1, ()> for AppState
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
}
) {}
event_created_child!(
AppState,
ext_workspace_manager_v1::ExtWorkspaceManagerV1,
[
wayland_protocols::ext::workspace::v1::client::ext_workspace_manager_v1::EVT_WORKSPACE_GROUP_OPCODE => (
ext_workspace_manager_v1::EVT_WORKSPACE_GROUP_OPCODE => (
ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1,
()
),
wayland_protocols::ext::workspace::v1::client::ext_workspace_manager_v1::EVT_WORKSPACE_OPCODE => (
ext_workspace_manager_v1::EVT_WORKSPACE_OPCODE => (
ext_workspace_handle_v1::ExtWorkspaceHandleV1,
()
)
@ -90,7 +113,6 @@ impl Dispatch<ext_workspace_manager_v1::ExtWorkspaceManagerV1, ()> for AppState
);
}
use wayland_client::Proxy;
impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
fn event(
state: &mut Self,
@ -100,23 +122,34 @@ impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
match event {
ext_workspace_handle_v1::Event::Id { id: _ } => {
let id = proxy.id();
match event {
ext_workspace_handle_v1::Event::Id { .. } => {
state.workspaces.insert(
id,
Workspace { activated: false },
);
state
.workspaces
.insert(proxy.id(), Workspace { activated: false });
state.emit();
}
ext_workspace_handle_v1::Event::Coordinates { coordinates } => {
let id = proxy.id();
if coordinates.len() >= 2 {
state.workspace_coords.insert(id, (coordinates[0], coordinates[1]));
}
state.emit();
}
ext_workspace_handle_v1::Event::State { state: flags } => {
let active = matches!(
flags,
wayland_client::WEnum::Value(ext_workspace_handle_v1::State::Active)
);
let id = proxy.id();
if let Some(ws) = state.workspaces.get_mut(&id) {
ws.activated = active;
}
@ -125,7 +158,8 @@ impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
}
ext_workspace_handle_v1::Event::Removed => {
state.workspaces.remove(&proxy.id());
state.workspaces.remove(&id);
state.workspace_group.remove(&id);
state.emit();
}
@ -136,13 +170,29 @@ impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
impl Dispatch<ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, ()> for AppState {
fn event(
_state: &mut Self,
_proxy: &ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1,
_event: ext_workspace_group_handle_v1::Event,
state: &mut Self,
proxy: &ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1,
event: ext_workspace_group_handle_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
// println!("workspace GROUP event: {:?}", event);
let group_id = proxy.id();
match event {
ext_workspace_group_handle_v1::Event::WorkspaceEnter { workspace } => {
state
.workspace_group
.insert(workspace.id(), group_id);
state.emit();
}
ext_workspace_group_handle_v1::Event::WorkspaceLeave { workspace } => {
state.workspace_group.remove(&workspace.id());
state.emit();
}
_ => {}
}
}
}