Update the build environment and some architectural elements of the Kifu app #210
|
@ -3,14 +3,13 @@ use crate::{
|
||||||
types::{AppState, Config, ConfigOption, DatabasePath, GameState, Player, Rank},
|
types::{AppState, Config, ConfigOption, DatabasePath, GameState, Player, Rank},
|
||||||
ui::{configuration, home, playing_field, ConfigurationView, HomeView, PlayingFieldView},
|
ui::{configuration, home, playing_field, ConfigurationView, HomeView, PlayingFieldView},
|
||||||
};
|
};
|
||||||
|
use async_std::channel::{Receiver, Sender};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", content = "content")]
|
|
||||||
pub enum CoreRequest {
|
pub enum CoreRequest {
|
||||||
ChangeSetting(ChangeSettingRequest),
|
ChangeSetting(ChangeSettingRequest),
|
||||||
CreateGame(CreateGameRequest),
|
CreateGame(CreateGameRequest),
|
||||||
|
@ -22,7 +21,6 @@ pub enum CoreRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", content = "content")]
|
|
||||||
pub enum ChangeSettingRequest {
|
pub enum ChangeSettingRequest {
|
||||||
LibraryPath(String),
|
LibraryPath(String),
|
||||||
}
|
}
|
||||||
|
@ -60,7 +58,6 @@ impl From<HotseatPlayerRequest> for Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", content = "content")]
|
|
||||||
pub enum CoreResponse {
|
pub enum CoreResponse {
|
||||||
ConfigurationView(ConfigurationView),
|
ConfigurationView(ConfigurationView),
|
||||||
HomeView(HomeView),
|
HomeView(HomeView),
|
||||||
|
@ -78,6 +75,7 @@ pub struct Core {
|
||||||
// config: Arc<RwLock<Config>>,
|
// config: Arc<RwLock<Config>>,
|
||||||
// state: Arc<RwLock<AppState>>,
|
// state: Arc<RwLock<AppState>>,
|
||||||
database: Arc<RwLock<Option<Database>>>,
|
database: Arc<RwLock<Option<Database>>>,
|
||||||
|
subscribers: Arc<RwLock<Vec<Sender<CoreNotification>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
|
@ -90,9 +88,19 @@ impl Core {
|
||||||
// config: Arc::new(RwLock::new(config)),
|
// config: Arc::new(RwLock::new(config)),
|
||||||
// state,
|
// state,
|
||||||
database: Arc::new(RwLock::new(None)),
|
database: Arc::new(RwLock::new(None)),
|
||||||
|
subscribers: Arc::new(RwLock::new(vec![])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe(&self) -> Receiver<CoreNotification> {
|
||||||
|
let mut subscribers = self.subscribers.write().unwrap();
|
||||||
|
|
||||||
|
let (sender, receiver) = async_std::channel::unbounded();
|
||||||
|
subscribers.push(sender);
|
||||||
|
|
||||||
|
receiver
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
||||||
match request {
|
match request {
|
||||||
|
|
|
@ -29,7 +29,6 @@ impl StoneElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", content = "content")]
|
|
||||||
pub enum IntersectionElement {
|
pub enum IntersectionElement {
|
||||||
Unplayable,
|
Unplayable,
|
||||||
Empty(CoreRequest),
|
Empty(CoreRequest),
|
||||||
|
|
|
@ -22,13 +22,20 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct GameState {
|
||||||
|
goban: Goban,
|
||||||
|
white_clock: Duration,
|
||||||
|
black_clock: Duration,
|
||||||
|
white_score: f32,
|
||||||
|
black_score: f32,
|
||||||
|
current: Color,
|
||||||
|
}
|
||||||
|
|
||||||
struct GameViewModelPrivate {
|
struct GameViewModelPrivate {
|
||||||
white: Player, /* Maybe this should be PlayerState, instead, combining the player info, current clock, and current captures. */
|
white: Player, /* Maybe this should be PlayerState, instead, combining the player info, current clock, and current captures. */
|
||||||
black: Player,
|
black: Player,
|
||||||
current: Color,
|
|
||||||
goban: Goban, /* Or perhaps clocks, captures, and the board should be bound into GameState. */
|
state: GameState,
|
||||||
white_clock: Duration,
|
|
||||||
black_clock: Duration,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Game View Model manages the current state of the game. It shows the two player cards, the board, the current capture count, the current player, and it maintains the UI for the clock (bearing in mind that the real clock is managed in the core). This view model should only be created once the details of the game, whether a game in progress or a new game (this view model won't know the difference) is known.
|
/// The Game View Model manages the current state of the game. It shows the two player cards, the board, the current capture count, the current player, and it maintains the UI for the clock (bearing in mind that the real clock is managed in the core). This view model should only be created once the details of the game, whether a game in progress or a new game (this view model won't know the difference) is known.
|
||||||
|
@ -44,32 +51,24 @@ impl GameViewModelPrivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameViewModel {
|
impl GameViewModel {
|
||||||
pub fn new(
|
pub fn new(white: Player, black: Player, game: GameState, core: Core) -> Self {
|
||||||
white: Player,
|
|
||||||
black: Player,
|
|
||||||
current: Color,
|
|
||||||
goban: Goban,
|
|
||||||
white_clock: Duration,
|
|
||||||
black_clock: Duration,
|
|
||||||
core: Core,
|
|
||||||
notifications: Receiver<CoreNotification>,
|
|
||||||
) -> Self {
|
|
||||||
let data = Arc::new(RwLock::new(GameViewModelPrivate {
|
let data = Arc::new(RwLock::new(GameViewModelPrivate {
|
||||||
white,
|
white,
|
||||||
black,
|
black,
|
||||||
current,
|
state: game,
|
||||||
goban,
|
|
||||||
white_clock,
|
|
||||||
black_clock,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let handler = spawn({
|
let handler = spawn({
|
||||||
|
let core = core.clone();
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
async move {
|
async move {
|
||||||
|
let notifications = core.subscribe();
|
||||||
loop {
|
loop {
|
||||||
match notifications.recv().await {
|
match notifications.recv().await {
|
||||||
Ok(msg) => data.write().unwrap().handle(msg),
|
Ok(msg) => data.write().unwrap().handle(msg),
|
||||||
Err(err) => unimplemented!("Should display an error message in the UI"),
|
Err(err) => {
|
||||||
|
unimplemented!("Should display an error message in the UI: {}", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
yield_now().await;
|
yield_now().await;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue