gui: fix channel ordering
This commit is contained in:
+120
-13
@@ -4,7 +4,7 @@ use dioxus::prelude::*;
|
||||
use mime_guess::Mime;
|
||||
use mumble_web2_common::{ClientConfig, ServerStatus};
|
||||
use ordermap::OrderSet;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::imp;
|
||||
|
||||
@@ -54,14 +54,6 @@ pub enum Command {
|
||||
use Command::*;
|
||||
use ConnectionState::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ChannelState {
|
||||
pub name: String,
|
||||
pub children: OrderSet<ChannelId>,
|
||||
pub users: OrderSet<UserId>,
|
||||
pub parent: Option<ChannelId>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UserState {
|
||||
pub name: String,
|
||||
@@ -94,8 +86,123 @@ pub struct Chat {
|
||||
}
|
||||
|
||||
#[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>,
|
||||
}
|
||||
|
||||
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 chat: Vec<Chat>,
|
||||
pub session: Option<UserId>,
|
||||
@@ -182,7 +289,7 @@ pub fn Channel(id: ChannelId) -> Element {
|
||||
let net: Coroutine<Command> = use_coroutine_handle();
|
||||
let server = STATE.server.read();
|
||||
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}");
|
||||
};
|
||||
|
||||
@@ -336,7 +443,7 @@ pub fn ControlView(config: Resource<ClientConfig>) -> Element {
|
||||
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
|
||||
.read_unchecked()
|
||||
@@ -528,7 +635,7 @@ pub fn ServerView(config: Resource<ClientConfig>) -> Element {
|
||||
class: "server_grid",
|
||||
div {
|
||||
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() {
|
||||
Channel { id: *id }
|
||||
}
|
||||
|
||||
+5
-34
@@ -335,41 +335,11 @@ fn accept_packet(
|
||||
}
|
||||
ControlPacket::ChannelState(u) => {
|
||||
let mut server = STATE.server.write();
|
||||
let id = u.get_channel_id();
|
||||
|
||||
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();
|
||||
}
|
||||
server.channels_state.update_from_ChannelState(&u);
|
||||
}
|
||||
ControlPacket::ChannelRemove(u) => {
|
||||
let mut server = STATE.server.write();
|
||||
let id = u.get_channel_id();
|
||||
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);
|
||||
}
|
||||
}
|
||||
server.channels_state.update_from_ChannelRemove(&u);
|
||||
}
|
||||
ControlPacket::UserState(u) => {
|
||||
let mut server = STATE.server.write();
|
||||
@@ -381,12 +351,13 @@ fn accept_packet(
|
||||
let state = state_entry.or_default();
|
||||
// the server might now send a channel_id if the user is in channel=0
|
||||
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);
|
||||
}
|
||||
|
||||
let channel_id = u.get_channel_id();
|
||||
server
|
||||
.channels_state
|
||||
.channels
|
||||
.entry(channel_id)
|
||||
.or_default()
|
||||
@@ -418,7 +389,7 @@ fn accept_packet(
|
||||
let mut server = STATE.server.write();
|
||||
let id = u.get_session();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user