gui: fix channel ordering
This commit is contained in:
+120
-13
@@ -4,7 +4,7 @@ use dioxus::prelude::*;
|
|||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use mumble_web2_common::{ClientConfig, ServerStatus};
|
use mumble_web2_common::{ClientConfig, ServerStatus};
|
||||||
use ordermap::OrderSet;
|
use ordermap::OrderSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::imp;
|
use crate::imp;
|
||||||
|
|
||||||
@@ -54,14 +54,6 @@ pub enum Command {
|
|||||||
use Command::*;
|
use Command::*;
|
||||||
use ConnectionState::*;
|
use ConnectionState::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ChannelState {
|
|
||||||
pub name: String,
|
|
||||||
pub children: OrderSet<ChannelId>,
|
|
||||||
pub users: OrderSet<UserId>,
|
|
||||||
pub parent: Option<ChannelId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct UserState {
|
pub struct UserState {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -94,8 +86,123 @@ pub struct Chat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ServerState {
|
pub struct ChannelState {
|
||||||
|
pub name: String,
|
||||||
|
pub children: OrderSet<ChannelId>,
|
||||||
|
pub users: OrderSet<UserId>,
|
||||||
|
pub parent: Option<ChannelId>,
|
||||||
|
pub position: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelState {
|
||||||
|
pub fn update_from_ChannelState(
|
||||||
|
&mut self,
|
||||||
|
channel_state: &mumble_protocol::control::msgs::ChannelState,
|
||||||
|
) {
|
||||||
|
if channel_state.has_position() {
|
||||||
|
self.position = channel_state.get_position();
|
||||||
|
}
|
||||||
|
if channel_state.has_parent() {
|
||||||
|
self.parent = Some(channel_state.get_parent());
|
||||||
|
}
|
||||||
|
if channel_state.has_name() {
|
||||||
|
self.name = channel_state.get_name().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ChannelsState {
|
||||||
pub channels: HashMap<ChannelId, ChannelState>,
|
pub channels: HashMap<ChannelId, ChannelState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelsState {
|
||||||
|
pub fn update_from_ChannelState(
|
||||||
|
&mut self,
|
||||||
|
channel_state: &mumble_protocol::control::msgs::ChannelState,
|
||||||
|
) {
|
||||||
|
self.channels
|
||||||
|
.entry(channel_state.get_channel_id())
|
||||||
|
.or_default()
|
||||||
|
.update_from_ChannelState(channel_state);
|
||||||
|
|
||||||
|
self.update_channel_parents();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_from_ChannelRemove(
|
||||||
|
&mut self,
|
||||||
|
channel_remove: &mumble_protocol::control::msgs::ChannelRemove,
|
||||||
|
) {
|
||||||
|
self.channels.remove(&channel_remove.get_channel_id());
|
||||||
|
self.update_channel_parents();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_channel_parents(&mut self) {
|
||||||
|
// Zero out existing children
|
||||||
|
for (id, state) in self.channels.iter_mut() {
|
||||||
|
state.children = OrderSet::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut channels_updated: HashSet<ChannelId> = HashSet::new();
|
||||||
|
channels_updated.insert(0); // insert root channel
|
||||||
|
|
||||||
|
let mut channels_to_parse: Vec<(ChannelId, ChannelId, i32)> = Vec::new();
|
||||||
|
for (id, state) in self.channels.iter() {
|
||||||
|
// Skip root channel
|
||||||
|
if *id == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore channels with no parent
|
||||||
|
let Some(parent_id) = state.parent else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If a channel has a parent that we haven't gotten a channel
|
||||||
|
// state packet for, ignore it
|
||||||
|
if !self.channels.contains_key(&parent_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
channels_to_parse.push((*id, parent_id, state.position));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut channel_positions = HashMap::new();
|
||||||
|
for (id, state) in self.channels.iter() {
|
||||||
|
channel_positions.insert(*id, state.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
while channels_updated.len() < channels_to_parse.len() {
|
||||||
|
for (id, parent_id, position) in &channels_to_parse {
|
||||||
|
if channels_updated.contains(&id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip channels whose parent we haven't seen yet
|
||||||
|
if !channels_updated.contains(&parent_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent = self.channels.get_mut(&parent_id).unwrap();
|
||||||
|
|
||||||
|
let mut after_index = 0;
|
||||||
|
for (index, child_id) in parent.children.iter().enumerate() {
|
||||||
|
after_index = index;
|
||||||
|
if channel_positions[child_id] > *position {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent.children.insert_before(after_index, *id);
|
||||||
|
|
||||||
|
channels_updated.insert(*id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ServerState {
|
||||||
|
pub channels_state: ChannelsState,
|
||||||
pub users: HashMap<UserId, UserState>,
|
pub users: HashMap<UserId, UserState>,
|
||||||
pub chat: Vec<Chat>,
|
pub chat: Vec<Chat>,
|
||||||
pub session: Option<UserId>,
|
pub session: Option<UserId>,
|
||||||
@@ -182,7 +289,7 @@ pub fn Channel(id: ChannelId) -> Element {
|
|||||||
let net: Coroutine<Command> = use_coroutine_handle();
|
let net: Coroutine<Command> = use_coroutine_handle();
|
||||||
let server = STATE.server.read();
|
let server = STATE.server.read();
|
||||||
let user = server.session.unwrap();
|
let user = server.session.unwrap();
|
||||||
let Some(state) = server.channels.get(&id) else {
|
let Some(state) = server.channels_state.channels.get(&id) else {
|
||||||
return rsx!("missing channel {id}");
|
return rsx!("missing channel {id}");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -336,7 +443,7 @@ pub fn ControlView(config: Resource<ClientConfig>) -> Element {
|
|||||||
return rsx!();
|
return rsx!();
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_channel_name = server.channels[&channel].name.clone();
|
let current_channel_name = server.channels_state.channels[&channel].name.clone();
|
||||||
|
|
||||||
let proxy_url = config
|
let proxy_url = config
|
||||||
.read_unchecked()
|
.read_unchecked()
|
||||||
@@ -528,7 +635,7 @@ pub fn ServerView(config: Resource<ClientConfig>) -> Element {
|
|||||||
class: "server_grid",
|
class: "server_grid",
|
||||||
div {
|
div {
|
||||||
class: "server_channel_box",
|
class: "server_channel_box",
|
||||||
for (id, state) in server.channels.iter() {
|
for (id, state) in server.channels_state.channels.iter() {
|
||||||
if state.parent.is_none() {
|
if state.parent.is_none() {
|
||||||
Channel { id: *id }
|
Channel { id: *id }
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-34
@@ -335,41 +335,11 @@ fn accept_packet(
|
|||||||
}
|
}
|
||||||
ControlPacket::ChannelState(u) => {
|
ControlPacket::ChannelState(u) => {
|
||||||
let mut server = STATE.server.write();
|
let mut server = STATE.server.write();
|
||||||
let id = u.get_channel_id();
|
server.channels_state.update_from_ChannelState(&u);
|
||||||
|
|
||||||
let state = server.channels.entry(id).or_default();
|
|
||||||
let new_parent = if u.has_parent() {
|
|
||||||
if let Some(parent) = state.parent.and_then(|p| server.channels.get_mut(&p)) {
|
|
||||||
parent.children.remove(&id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let parent_id = u.get_parent();
|
|
||||||
let parent = server.channels.entry(parent_id).or_default();
|
|
||||||
if u.has_position() && u.get_position() as usize <= parent.children.len() {
|
|
||||||
// TODO: what if positions are received out of order? we need to sort afterwards?
|
|
||||||
parent.children.insert_before(u.get_position() as usize, id);
|
|
||||||
} else {
|
|
||||||
parent.children.insert(id);
|
|
||||||
}
|
|
||||||
Some(parent_id)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let state = server.channels.entry(id).or_default();
|
|
||||||
state.parent = new_parent;
|
|
||||||
if u.has_name() {
|
|
||||||
state.name = u.get_name().to_string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ControlPacket::ChannelRemove(u) => {
|
ControlPacket::ChannelRemove(u) => {
|
||||||
let mut server = STATE.server.write();
|
let mut server = STATE.server.write();
|
||||||
let id = u.get_channel_id();
|
server.channels_state.update_from_ChannelRemove(&u);
|
||||||
if let Some(channel) = server.channels.remove(&id) {
|
|
||||||
if let Some(parent) = channel.parent.and_then(|p| server.channels.get_mut(&p)) {
|
|
||||||
parent.children.remove(&id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ControlPacket::UserState(u) => {
|
ControlPacket::UserState(u) => {
|
||||||
let mut server = STATE.server.write();
|
let mut server = STATE.server.write();
|
||||||
@@ -381,12 +351,13 @@ fn accept_packet(
|
|||||||
let state = state_entry.or_default();
|
let state = state_entry.or_default();
|
||||||
// the server might now send a channel_id if the user is in channel=0
|
// the server might now send a channel_id if the user is in channel=0
|
||||||
if u.has_channel_id() || new {
|
if u.has_channel_id() || new {
|
||||||
if let Some(parent) = server.channels.get_mut(&state.channel) {
|
if let Some(parent) = server.channels_state.channels.get_mut(&state.channel) {
|
||||||
parent.users.remove(&id);
|
parent.users.remove(&id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let channel_id = u.get_channel_id();
|
let channel_id = u.get_channel_id();
|
||||||
server
|
server
|
||||||
|
.channels_state
|
||||||
.channels
|
.channels
|
||||||
.entry(channel_id)
|
.entry(channel_id)
|
||||||
.or_default()
|
.or_default()
|
||||||
@@ -418,7 +389,7 @@ fn accept_packet(
|
|||||||
let mut server = STATE.server.write();
|
let mut server = STATE.server.write();
|
||||||
let id = u.get_session();
|
let id = u.get_session();
|
||||||
if let Some(state) = server.users.remove(&id) {
|
if let Some(state) = server.users.remove(&id) {
|
||||||
if let Some(parent) = server.channels.get_mut(&state.channel) {
|
if let Some(parent) = server.channels_state.channels.get_mut(&state.channel) {
|
||||||
parent.users.remove(&id);
|
parent.users.remove(&id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user