Rearange file structure and add coop_widget
6
Cargo.lock
generated
@@ -646,6 +646,11 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "coop_widgets"
|
||||
version = "0.1.0"
|
||||
source = "git+https://codeberg.org/flovansl/co_sl#35ae498f0b02a82788a32dc02aa9018ab0a5d65c"
|
||||
|
||||
[[package]]
|
||||
name = "copypasta"
|
||||
version = "0.8.2"
|
||||
@@ -2697,6 +2702,7 @@ name = "remote"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"coop_widgets",
|
||||
"env_logger",
|
||||
"lib",
|
||||
"log",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod tcp;
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use crossbeam::channel::{Sender, Receiver};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -16,6 +17,11 @@ pub enum ServerMessage {
|
||||
Playing(bool),
|
||||
}
|
||||
|
||||
pub type MessageToServer = Sender<ClientMessage>;
|
||||
pub type MessageFromServer = Receiver<ServerMessage>;
|
||||
pub type MessageToClient = Sender<ServerMessage>;
|
||||
pub type MessageFomClient = Receiver<ClientMessage>;
|
||||
|
||||
pub enum Origin {
|
||||
Server,
|
||||
Client,
|
||||
|
||||
@@ -80,9 +80,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start_server() -> Result<(Sender<ServerMessage>, Receiver<ClientMessage>)> {
|
||||
let (sender_c, reciever_c) = channel::bounded(4);
|
||||
let (sender_s, reciever_s) = channel::bounded(4);
|
||||
pub fn start_server() -> Result<(MessageToClient, MessageFomClient)> {
|
||||
let (message_to_server, message_from_client) = channel::bounded(4);
|
||||
let (message_to_client, message_from_server) = channel::bounded(4);
|
||||
|
||||
let server = create_listener("0.0.0.0", PORT);
|
||||
info!("Listening on port {}", PORT);
|
||||
@@ -93,8 +93,8 @@ pub fn start_server() -> Result<(Sender<ServerMessage>, Receiver<ClientMessage>)
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
match stream_result {
|
||||
Ok(stream) => {
|
||||
let reciever_s = reciever_s.clone();
|
||||
let sender_c = sender_c.clone();
|
||||
let reciever_s = message_from_server.clone();
|
||||
let sender_c = message_to_server.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
if let Err(error) =
|
||||
@@ -110,19 +110,19 @@ pub fn start_server() -> Result<(Sender<ServerMessage>, Receiver<ClientMessage>)
|
||||
}
|
||||
});
|
||||
|
||||
Ok((sender_s, reciever_c))
|
||||
Ok((message_to_client, message_from_client))
|
||||
}
|
||||
|
||||
pub fn start_client(ip: IpAddr) -> Result<(Sender<ClientMessage>, Receiver<ServerMessage>)> {
|
||||
let (sender_c, reciever_c) = channel::bounded(4);
|
||||
let (sender_s, reciever_s) = channel::bounded(4);
|
||||
pub fn start_client(ip: IpAddr) -> Result<(MessageToServer, MessageFromServer)> {
|
||||
let (message_to_server, message_from_client) = channel::bounded(4);
|
||||
let (message_to_client, message_from_server) = channel::bounded(4);
|
||||
|
||||
let serv_addr = SocketAddr::new(ip, PORT);
|
||||
|
||||
let server = TcpStream::connect(serv_addr)?;
|
||||
info!("Connected successfully to {}", serv_addr);
|
||||
|
||||
thread::spawn(move || handle_connection(server, reciever_c, sender_s, Origin::Server));
|
||||
thread::spawn(move || handle_connection(server, message_from_client, message_to_client, Origin::Server));
|
||||
|
||||
Ok((sender_c, reciever_s))
|
||||
Ok((message_to_server, message_from_server))
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ anyhow = "1.0"
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
|
||||
slint = "1.0"
|
||||
slint = "1.1"
|
||||
|
||||
[build-dependencies]
|
||||
slint-build = "1.0"
|
||||
slint-build = "1.1"
|
||||
coop_widgets = { git = "https://codeberg.org/flovansl/co_sl" }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
fn main() {
|
||||
slint_build::compile("ui/appwindow.slint").unwrap();
|
||||
coop_widgets::generate_import().unwrap();
|
||||
slint_build::compile("ui/app.slint").unwrap();
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
47
remote/src/controller/media.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use lib::{ClientMessage, MessageFromServer, MessageToServer, ServerMessage};
|
||||
use log::info;
|
||||
|
||||
use slint::ComponentHandle;
|
||||
use crate::{App,MediaLogic};
|
||||
|
||||
pub fn init(ui: &App, sender_co: MessageToServer, receiver_s: MessageFromServer) {
|
||||
let sender_c = sender_co.clone();
|
||||
|
||||
ui.global::<MediaLogic>().on_play_pause(move || {
|
||||
sender_c.send(ClientMessage::PlayPause).unwrap();
|
||||
});
|
||||
|
||||
let sender_c = sender_co.clone();
|
||||
ui.global::<MediaLogic>().on_next(move || {
|
||||
sender_c.send(ClientMessage::Next).unwrap();
|
||||
});
|
||||
|
||||
let sender_c = sender_co.clone();
|
||||
ui.global::<MediaLogic>().on_previous(move || {
|
||||
sender_c.send(ClientMessage::Previous).unwrap();
|
||||
});
|
||||
|
||||
let ui_handle = ui.as_weak();
|
||||
thread::spawn(move || loop {
|
||||
if receiver_s.is_empty() {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
continue;
|
||||
}
|
||||
let msg = receiver_s.recv().unwrap();
|
||||
info!("Received : {msg:?}");
|
||||
match msg {
|
||||
ServerMessage::NowPlaying(title) => ui_handle
|
||||
.upgrade_in_event_loop(move |handle| {
|
||||
handle.global::<MediaLogic>().set_now_playing(title.into())
|
||||
})
|
||||
.unwrap(),
|
||||
ServerMessage::Playing(bool) => ui_handle
|
||||
.upgrade_in_event_loop(move |handle| {
|
||||
handle.global::<MediaLogic>().set_playing(bool)
|
||||
})
|
||||
.unwrap(),
|
||||
};
|
||||
});
|
||||
}
|
||||
1
remote/src/controller/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod media;
|
||||
25
remote/src/link/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use lib::{tcp::start_client, MessageToServer, MessageFromServer};
|
||||
use log::info;
|
||||
use std::{net::IpAddr, process::exit, str::FromStr, thread, time::Duration};
|
||||
|
||||
pub fn init_tcp() -> (MessageToServer, MessageFromServer){
|
||||
info!("Trying to connect ot server");
|
||||
let mut retries = 1;
|
||||
let (messages_to_server, message_from_server) = loop {
|
||||
let res = start_client(IpAddr::from_str("127.0.0.1").unwrap());
|
||||
if let Ok((s, r)) = res {
|
||||
break (s, r);
|
||||
}
|
||||
println!("Failde to connect retrying in {} ms", 200 * retries);
|
||||
thread::sleep(Duration::from_millis(200 * retries));
|
||||
retries *= 5;
|
||||
if retries >= 500 {
|
||||
println!("Could not connect to server exiting...");
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
info!("Connected to Server");
|
||||
|
||||
(messages_to_server, message_from_server)
|
||||
}
|
||||
@@ -1,70 +1,23 @@
|
||||
use std::{net::IpAddr, process::exit, str::FromStr, thread, time::Duration};
|
||||
mod controller;
|
||||
mod link;
|
||||
|
||||
use lib::{tcp::start_client, ServerMessage};
|
||||
use log::info;
|
||||
|
||||
use crate::{controller::media, link::init_tcp};
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
fn main() -> Result<(), slint::PlatformError> {
|
||||
env_logger::init_from_env(
|
||||
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
|
||||
);
|
||||
|
||||
let (messages_to_server, message_from_server) = init_tcp();
|
||||
|
||||
let mut retries = 1;
|
||||
let (sender_co, receiver_s) = loop {
|
||||
let res = start_client(IpAddr::from_str("127.0.0.1").unwrap());
|
||||
if let Ok((s, r)) = res {
|
||||
break (s, r);
|
||||
}
|
||||
println!("Failde to connect retrying in {} ms", 200 * retries);
|
||||
thread::sleep(Duration::from_millis(200 * retries));
|
||||
retries *= 5;
|
||||
if retries >= 500 {
|
||||
println!("Could not connect to server exiting...");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
info!("Connected to Server");
|
||||
|
||||
let ui = AppWindow::new()?;
|
||||
|
||||
let sender_c = sender_co.clone();
|
||||
|
||||
ui.global::<MediaLogic>().on_play_pause(move || {
|
||||
sender_c.send(lib::ClientMessage::PlayPause).unwrap();
|
||||
});
|
||||
|
||||
let sender_c = sender_co.clone();
|
||||
ui.global::<MediaLogic>().on_next(move || {
|
||||
sender_c.send(lib::ClientMessage::Next).unwrap();
|
||||
});
|
||||
|
||||
let sender_c = sender_co.clone();
|
||||
ui.global::<MediaLogic>().on_previous(move || {
|
||||
sender_c.send(lib::ClientMessage::Previous).unwrap();
|
||||
});
|
||||
|
||||
let ui_handle = ui.as_weak();
|
||||
thread::spawn(move || loop {
|
||||
if receiver_s.is_empty() {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
continue;
|
||||
}
|
||||
let msg = receiver_s.recv().unwrap();
|
||||
info!("Received : {msg:?}");
|
||||
match msg {
|
||||
ServerMessage::NowPlaying(title) => ui_handle
|
||||
.upgrade_in_event_loop(move |handle| handle.set_now_playing(title.into()))
|
||||
.unwrap(),
|
||||
ServerMessage::Playing(bool) => ui_handle
|
||||
.upgrade_in_event_loop(move |handle| {
|
||||
handle.global::<MediaLogic>().set_playing(bool)
|
||||
})
|
||||
.unwrap(),
|
||||
};
|
||||
});
|
||||
let ui = App::new()?;
|
||||
|
||||
media::init(&ui, messages_to_server, message_from_server);
|
||||
|
||||
info!("Launching UI");
|
||||
ui.run()
|
||||
}
|
||||
|
||||
25
remote/ui/_imports/coop-widgets.slint
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: 2022 Florian Blasius <co_sl@tutanota.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { Duration, Icography, Icons, Radius, ColorVariant, ColorTheme, CoopPalette, CosmicPalette, Palette, Size, State, Space, Typography } from "/home/jika/.cargo/git/checkouts/co_sl-418b266b7ff25a3f/35ae498/widgets/coop_widgets/ui/styling/styling.slint";
|
||||
export { Duration, Icography, Icons, Radius, ColorVariant, ColorTheme, CoopPalette, CosmicPalette, Palette, Size, State, Space, Typography }
|
||||
|
||||
import { HeaderBar, SideBar } from "/home/jika/.cargo/git/checkouts/co_sl-418b266b7ff25a3f/35ae498/widgets/coop_widgets/ui/building-blocks/building-blocks.slint";
|
||||
export { HeaderBar, SideBar }
|
||||
|
||||
import { CoopWindow, FocusTouchArea, SmallLabel, MediumLabel, LargeLabel, ErrorLabel, SmallTitle, MediumTitle, LargeTitle, Popup, PopupBorder,
|
||||
ThemedWindow } from "/home/jika/.cargo/git/checkouts/co_sl-418b266b7ff25a3f/35ae498/widgets/coop_widgets/ui/components/components.slint";
|
||||
export { CoopWindow, FocusTouchArea, SmallLabel, MediumLabel, LargeLabel, ErrorLabel, SmallTitle, MediumTitle, LargeTitle, Popup, PopupBorder, ThemedWindow }
|
||||
|
||||
import { Button, OutlineButton, RoundButton, Carousel, ComboBox, ListViewItem, GroupListViewItem, ListView, GroupListView, ItemDelegate,
|
||||
ScrollView, LineEdit, RoundOutlineButton, Switch, CheckBox, CheckableBase, Slider, StandardTableView, ProgressIndicator, StandardListView } from "/home/jika/.cargo/git/checkouts/co_sl-418b266b7ff25a3f/35ae498/widgets/coop_widgets/ui/widgets/widgets.slint";
|
||||
export { Button, ComboBox, OutlineButton, RoundButton, Carousel, ListViewItem, GroupListViewItem, ListView, GroupListView, ItemDelegate,
|
||||
ScrollView, LineEdit, RoundOutlineButton, CheckBox, Switch, CheckableBase, Slider, StandardTableView, ProgressIndicator, StandardListView }
|
||||
|
||||
import { VirtualKeyboard, VirtualKeyboardHandler, KeyModel } from "/home/jika/.cargo/git/checkouts/co_sl-418b266b7ff25a3f/35ae498/widgets/coop_widgets/ui/keyboard/keyboard.slint";
|
||||
export { VirtualKeyboard, VirtualKeyboardHandler, KeyModel }
|
||||
|
||||
import { CenterLayout, FormElement, VerticalSeparator, HorizontalSeparator, Spacer, VerticalSpacerSmall, VerticalSpacerMedium, VerticalSpacerLarge,
|
||||
HorizontalSpacerSmall, HorizontalSpacerMedium, HorizontalSpacerLarge } from "/home/jika/.cargo/git/checkouts/co_sl-418b266b7ff25a3f/35ae498/widgets/coop_widgets/ui/layouts/layouts.slint";
|
||||
export { CenterLayout, FormElement, VerticalSeparator, HorizontalSeparator, Spacer, VerticalSpacerSmall, VerticalSpacerMedium, VerticalSpacerLarge,
|
||||
HorizontalSpacerSmall, HorizontalSpacerMedium, HorizontalSpacerLarge }
|
||||
8
remote/ui/app.slint
Normal file
@@ -0,0 +1,8 @@
|
||||
import { MediaControls, MediaLogic } from "widgets/mediacontrols.slint";
|
||||
export { MediaLogic }
|
||||
|
||||
|
||||
export component App inherits Window {
|
||||
background: white;
|
||||
MediaControls {}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Button, VerticalBox } from "std-widgets.slint";
|
||||
import { MediaControls, MediaLogic } from "widgets/mediacontrols.slint";
|
||||
export { MediaLogic }
|
||||
|
||||
|
||||
export component AppWindow inherits Window {
|
||||
background: white;
|
||||
in-out property <string> now_playing: "Loading...";
|
||||
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
|
||||
MediaControls { }
|
||||
Text {
|
||||
horizontal-alignment: center;
|
||||
color: black;
|
||||
text: root.now_playing;
|
||||
font-size:35px;
|
||||
font-weight: 600;
|
||||
wrap: word-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,38 +1,56 @@
|
||||
import { Clickable } from "clickable.slint";
|
||||
import { HorizontalBox } from "std-widgets.slint";
|
||||
|
||||
export global MediaLogic {
|
||||
pure callback play-pause();
|
||||
pure callback next();
|
||||
pure callback previous();
|
||||
in-out property <bool> playing;
|
||||
in-out property <string> now_playing: "Loading...";
|
||||
}
|
||||
|
||||
export component MediaControls inherits Clickable {
|
||||
in-out property <bool> playing: false;
|
||||
|
||||
HorizontalBox {
|
||||
export component Buttons {
|
||||
HorizontalLayout {
|
||||
width: 450px;
|
||||
Clickable {
|
||||
icon: @image-url("../../icons/back.png");
|
||||
icon: @image-url("../../icons/media-controls/back.png");
|
||||
action => {
|
||||
MediaLogic.previous();
|
||||
}
|
||||
}
|
||||
|
||||
Clickable {
|
||||
icon: MediaLogic.playing ? @image-url("../../icons/pause.png"): @image-url("../../icons/play.png");
|
||||
icon: MediaLogic.playing ? @image-url("../../icons/media-controls/pause.png"): @image-url("../../icons/media-controls/play.png");
|
||||
action => {
|
||||
MediaLogic.playing = !MediaLogic.playing;
|
||||
MediaLogic.play-pause();
|
||||
}
|
||||
}
|
||||
Clickable {
|
||||
icon: @image-url("../../icons/skip.png");
|
||||
icon: @image-url("../../icons/media-controls/skip.png");
|
||||
action => {
|
||||
MediaLogic.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export component MediaControls inherits Clickable {
|
||||
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
|
||||
Buttons { }
|
||||
Text {
|
||||
horizontal-alignment: center;
|
||||
color: black;
|
||||
text: MediaLogic.now_playing;
|
||||
font-size:35px;
|
||||
font-weight: 600;
|
||||
wrap: word-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||