Compare commits
4 Commits
741f963606
...
084a558740
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | 084a558740 | |
Savanni D'Gerinel | 744511a552 | |
Savanni D'Gerinel | c8d21d0e25 | |
Savanni D'Gerinel | 1b9a8eee67 |
|
@ -71,7 +71,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "emseries"
|
||||
version = "0.5.1"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
|
|
|
@ -51,6 +51,7 @@ dependencies = [
|
|||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
|
@ -68,7 +69,9 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"typeshare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -94,6 +97,12 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.64"
|
||||
|
@ -170,6 +179,54 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
|
@ -198,7 +255,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -212,6 +269,28 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeshare"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f44d1a2f454cb35fbe05b218c410792697e76bd868f48d3a418f2cd1a7d527d6"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"typeshare-annotation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeshare-annotation"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc670d0e358428857cc3b4bf504c691e572fccaec9542ff09212d3f13d74b7a9"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
|
@ -245,7 +324,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.18",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -267,7 +346,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.18",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
|
|
@ -6,6 +6,8 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4", features = [ "serde" ] }
|
||||
nom = { version = "7" }
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
thiserror = { version = "1"}
|
||||
chrono = { version = "0.4" }
|
||||
typeshare = { version = "1" }
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use chrono::{Datelike, NaiveDate};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::num::ParseIntError;
|
||||
use thiserror::Error;
|
||||
use typeshare::typeshare;
|
||||
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
pub enum Error {
|
||||
|
@ -14,7 +16,8 @@ pub enum Error {
|
|||
Unsupported,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Deserialize, Serialize)]
|
||||
#[typeshare]
|
||||
pub enum Date {
|
||||
Year(i32),
|
||||
YearMonth(i32, u32),
|
||||
|
|
|
@ -72,6 +72,8 @@ use crate::{
|
|||
date::{self, parse_date_field, Date},
|
||||
tree::{parse_collection, ParseSizeError, Size},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error<'a> {
|
||||
|
@ -97,7 +99,8 @@ impl<'a> From<ParseSizeError> for Error<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub enum Rank {
|
||||
Kyu(u8),
|
||||
Dan(u8),
|
||||
|
@ -118,6 +121,12 @@ impl TryFrom<&str> for Rank {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToString for Rank {
|
||||
fn to_string(&self) -> String {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GameTree {
|
||||
pub file_format: i8,
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
pub mod date;
|
||||
pub mod go;
|
||||
pub mod tree;
|
||||
mod date;
|
||||
pub use date::Date;
|
||||
|
||||
mod go;
|
||||
pub use go::{parse_sgf, GameTree, GameType, Rank};
|
||||
|
||||
mod tree;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
|
@ -125,7 +126,9 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"typeshare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
types::{AppState, GameState, Player, Rank},
|
||||
ui::{new_game, playing_field, NewGameView, PlayingFieldView},
|
||||
Config,
|
||||
ui::{home, playing_field, HomeView, PlayingFieldView},
|
||||
Config, DatabasePath,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
@ -12,8 +12,7 @@ use typeshare::typeshare;
|
|||
#[serde(tag = "type", content = "content")]
|
||||
pub enum CoreRequest {
|
||||
CreateGame(CreateGameRequest),
|
||||
LaunchScreen,
|
||||
NewGame,
|
||||
Home,
|
||||
PlayingField,
|
||||
PlayStone(PlayStoneRequest),
|
||||
StartGame,
|
||||
|
@ -59,7 +58,7 @@ impl From<HotseatPlayerRequest> for Player {
|
|||
#[typeshare]
|
||||
#[serde(tag = "type", content = "content")]
|
||||
pub enum CoreResponse {
|
||||
NewGameView(NewGameView),
|
||||
HomeView(HomeView),
|
||||
PlayingFieldView(PlayingFieldView),
|
||||
}
|
||||
|
||||
|
@ -71,8 +70,14 @@ pub struct CoreApp {
|
|||
|
||||
impl CoreApp {
|
||||
pub fn new(config_path: std::path::PathBuf) -> Self {
|
||||
println!("config_path: {:?}", config_path);
|
||||
let config = Config::from_path(config_path).expect("configuration to open");
|
||||
let state = Arc::new(RwLock::new(AppState::new()));
|
||||
|
||||
let db_path: DatabasePath = config.get();
|
||||
let state = Arc::new(RwLock::new(AppState::new(db_path)));
|
||||
|
||||
println!("config: {:?}", config);
|
||||
println!("games database: {:?}", state.read().unwrap().database.len());
|
||||
|
||||
Self { config, state }
|
||||
}
|
||||
|
@ -113,8 +118,9 @@ impl CoreApp {
|
|||
let game_state = app_state.game.as_ref().unwrap();
|
||||
CoreResponse::PlayingFieldView(playing_field(game_state))
|
||||
}
|
||||
CoreRequest::LaunchScreen => CoreResponse::NewGameView(new_game()),
|
||||
CoreRequest::NewGame => CoreResponse::NewGameView(new_game()),
|
||||
CoreRequest::Home => {
|
||||
CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games()))
|
||||
}
|
||||
CoreRequest::PlayingField => {
|
||||
let app_state = self.state.read().unwrap();
|
||||
let game = app_state.game.as_ref().unwrap();
|
||||
|
|
|
@ -36,6 +36,7 @@ enum OptionNames {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ConfigOption {
|
||||
DatabasePath(DatabasePath),
|
||||
Me(Me),
|
||||
|
@ -96,14 +97,14 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, val: ConfigOption) {
|
||||
pub fn set(&mut self, val: ConfigOption) {
|
||||
let _ = match val {
|
||||
ConfigOption::DatabasePath(_) => self.values.insert(OptionNames::DatabasePath, val),
|
||||
ConfigOption::Me(_) => self.values.insert(OptionNames::Me, val),
|
||||
};
|
||||
}
|
||||
|
||||
fn get<'a, T>(&'a self) -> T
|
||||
pub fn get<'a, T>(&'a self) -> T
|
||||
where
|
||||
T: From<&'a Self>,
|
||||
{
|
||||
|
@ -111,9 +112,16 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct DatabasePath(PathBuf);
|
||||
|
||||
impl std::ops::Deref for DatabasePath {
|
||||
type Target = PathBuf;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Config> for DatabasePath {
|
||||
fn from(config: &Config) -> Self {
|
||||
match config.values.get(&OptionNames::DatabasePath) {
|
||||
|
@ -123,7 +131,7 @@ impl From<&Config> for DatabasePath {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Me(Player);
|
||||
|
||||
impl From<&Config> for Option<Me> {
|
||||
|
@ -137,3 +145,54 @@ impl From<&Config> for Option<Me> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Me {
|
||||
type Target = Player;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::types::Rank;
|
||||
use cool_asserts::assert_matches;
|
||||
|
||||
#[test]
|
||||
fn it_can_set_and_get_options() {
|
||||
let mut config = Config::new(PathBuf::from("."));
|
||||
config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from(
|
||||
"fixtures/five_games",
|
||||
))));
|
||||
config.set(ConfigOption::Me(Me(Player {
|
||||
name: "Savanni".to_owned(),
|
||||
rank: Some(Rank::Kyu(10)),
|
||||
})));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_serialize_and_deserialize() {
|
||||
let mut config = Config::new(PathBuf::from("."));
|
||||
config.set(ConfigOption::DatabasePath(DatabasePath(PathBuf::from(
|
||||
"fixtures/five_games",
|
||||
))));
|
||||
config.set(ConfigOption::Me(Me(Player {
|
||||
name: "Savanni".to_owned(),
|
||||
rank: Some(Rank::Kyu(10)),
|
||||
})));
|
||||
let s = serde_json::to_string(&config.values).unwrap();
|
||||
println!("{}", s);
|
||||
let values: HashMap<OptionNames, ConfigOption> = serde_json::from_str(s.as_ref()).unwrap();
|
||||
println!("options: {:?}", values);
|
||||
|
||||
assert_matches!(values.get(&OptionNames::DatabasePath),
|
||||
Some(ConfigOption::DatabasePath(db_path)) =>
|
||||
assert_eq!(*db_path, config.get())
|
||||
);
|
||||
|
||||
assert_matches!(values.get(&OptionNames::Me), Some(ConfigOption::Me(val)) =>
|
||||
assert_eq!(Some(val.clone()), config.get())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{ffi::OsStr, io::Read, os::unix::ffi::OsStrExt, path::PathBuf};
|
||||
|
||||
use go_sgf::go::{parse_sgf, GameTree, GameType};
|
||||
use go_sgf::{parse_sgf, GameTree};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -17,6 +17,7 @@ impl From<std::io::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Database {
|
||||
path: PathBuf,
|
||||
games: Vec<GameTree>,
|
||||
|
@ -49,6 +50,10 @@ impl Database {
|
|||
Ok(Database { path, games })
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.games.len()
|
||||
}
|
||||
|
||||
pub fn all_games(&self) -> impl Iterator<Item = &GameTree> {
|
||||
self.games.iter()
|
||||
}
|
||||
|
@ -58,6 +63,7 @@ impl Database {
|
|||
mod test {
|
||||
use super::*;
|
||||
use cool_asserts::assert_matches;
|
||||
use go_sgf::{Date, GameType};
|
||||
|
||||
#[test]
|
||||
fn it_reads_empty_database() {
|
||||
|
@ -79,7 +85,7 @@ mod test {
|
|||
Some(game) => {
|
||||
assert_eq!(game.info.black_player, Some("Steve".to_owned()));
|
||||
assert_eq!(game.info.white_player, Some("Savanni".to_owned()));
|
||||
assert_eq!(game.info.date, vec![chrono::NaiveDate::from_ymd_opt(2023, 4, 19).unwrap()]);
|
||||
assert_eq!(game.info.date, vec![Date::Date(chrono::NaiveDate::from_ymd_opt(2023, 4, 19).unwrap())]);
|
||||
assert_eq!(game.info.komi, Some(6.5));
|
||||
}
|
||||
);
|
||||
|
|
|
@ -13,4 +13,5 @@ mod database;
|
|||
|
||||
mod types;
|
||||
pub use types::{BoardError, Color, Rank, Size};
|
||||
|
||||
pub mod ui;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use crate::{
|
||||
api::PlayStoneRequest,
|
||||
board::{Board, Coordinate},
|
||||
config::DatabasePath,
|
||||
database::Database,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
use thiserror::Error;
|
||||
use typeshare::typeshare;
|
||||
|
||||
|
@ -43,12 +45,14 @@ impl Default for Size {
|
|||
#[derive(Debug)]
|
||||
pub struct AppState {
|
||||
pub game: Option<GameState>,
|
||||
pub database: Database,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(database_path: DatabasePath) -> Self {
|
||||
Self {
|
||||
game: Some(GameState::new()),
|
||||
database: Database::open_path(database_path.to_path_buf()).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,7 +95,7 @@ impl From<Rank> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Player {
|
||||
pub name: String,
|
||||
pub rank: Option<Rank>,
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use go_sgf::{Date, GameTree, Rank};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[typeshare]
|
||||
pub struct GamePreviewElement {
|
||||
pub date: Vec<Date>,
|
||||
pub black_player: String,
|
||||
pub black_rank: Option<Rank>,
|
||||
pub white_player: String,
|
||||
pub white_rank: Option<Rank>,
|
||||
}
|
||||
|
||||
impl GamePreviewElement {
|
||||
pub fn new(game: &GameTree) -> GamePreviewElement {
|
||||
GamePreviewElement {
|
||||
date: game.info.date.clone(),
|
||||
black_player: game
|
||||
.info
|
||||
.black_player
|
||||
.clone()
|
||||
.unwrap_or("black_player".to_owned()),
|
||||
black_rank: game.info.black_rank.clone(),
|
||||
white_player: game
|
||||
.info
|
||||
.white_player
|
||||
.clone()
|
||||
.unwrap_or("white_player".to_owned()),
|
||||
white_rank: game.info.white_rank.clone(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod action;
|
||||
pub mod game_preview;
|
||||
pub mod menu;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::ui::Action;
|
||||
use crate::ui::{Action, GamePreviewElement};
|
||||
use go_sgf::GameTree;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
|
@ -48,13 +49,14 @@ pub struct BotPlayerElement {}
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[typeshare]
|
||||
pub struct NewGameView {
|
||||
pub struct HomeView {
|
||||
pub black_player: PlayerElement,
|
||||
pub white_player: PlayerElement,
|
||||
pub games: Vec<GamePreviewElement>,
|
||||
pub start_game: Action<()>,
|
||||
}
|
||||
|
||||
pub fn new_game() -> NewGameView {
|
||||
pub fn home<'a>(games: impl Iterator<Item = &'a GameTree>) -> HomeView {
|
||||
let black_player = PlayerElement::Hotseat(HotseatPlayerElement {
|
||||
placeholder: Some("black player".to_owned()),
|
||||
default_rank: None,
|
||||
|
@ -65,9 +67,10 @@ pub fn new_game() -> NewGameView {
|
|||
default_rank: None,
|
||||
ranks: rank_strings(),
|
||||
});
|
||||
NewGameView {
|
||||
HomeView {
|
||||
black_player,
|
||||
white_player,
|
||||
games: games.map(GamePreviewElement::new).collect(),
|
||||
start_game: Action {
|
||||
id: "start-game-action".to_owned(),
|
||||
label: "New Game".to_owned(),
|
|
@ -1,5 +1,5 @@
|
|||
mod elements;
|
||||
pub use elements::{action::Action, menu::Menu};
|
||||
pub use elements::{action::Action, game_preview::GamePreviewElement, menu::Menu};
|
||||
|
||||
mod playing_field;
|
||||
pub use playing_field::{playing_field, PlayingFieldView};
|
||||
|
@ -7,8 +7,8 @@ pub use playing_field::{playing_field, PlayingFieldView};
|
|||
// mod launch_screen;
|
||||
// pub use launch_screen::{launch_screen, LaunchScreenView};
|
||||
|
||||
mod new_game;
|
||||
pub use new_game::{new_game, HotseatPlayerElement, NewGameView, PlayerElement};
|
||||
mod home;
|
||||
pub use home::{home, HomeView, HotseatPlayerElement, PlayerElement};
|
||||
|
||||
mod types;
|
||||
pub use types::{
|
||||
|
|
|
@ -121,6 +121,8 @@ dependencies = [
|
|||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
@ -442,7 +444,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
@ -543,6 +545,17 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "go-sgf"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"typeshare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.17.4"
|
||||
|
@ -785,6 +798,8 @@ dependencies = [
|
|||
name = "kifu-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"go-sgf",
|
||||
"grid",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -862,6 +877,12 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
|
@ -879,7 +900,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
|
@ -898,6 +919,16 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
|
@ -1330,6 +1361,17 @@ dependencies = [
|
|||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.26.0"
|
||||
|
@ -1433,6 +1475,12 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
|
|
@ -2,6 +2,7 @@ release:
|
|||
cargo build --release
|
||||
|
||||
dev:
|
||||
export CONFIG=.
|
||||
cargo watch -x 'run --bin kifu-gtk'
|
||||
|
||||
screenplay:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"Me":{"name":"Savanni","rank":{"Kyu":10}},"DatabasePath":"../core/fixtures/five_games"}
|
|
@ -2,7 +2,7 @@ use gtk::prelude::*;
|
|||
use kifu_core::{CoreApp, CoreRequest, CoreResponse};
|
||||
use kifu_gtk::{
|
||||
perftrace,
|
||||
ui::{NewGame, PlayingField},
|
||||
ui::{Home, PlayingField},
|
||||
CoreApi,
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
@ -10,10 +10,10 @@ use std::sync::{Arc, RwLock};
|
|||
fn handle_response(api: CoreApi, window: gtk::ApplicationWindow, message: CoreResponse) {
|
||||
let playing_field = Arc::new(RwLock::new(None));
|
||||
match message {
|
||||
CoreResponse::NewGameView(view) => perftrace("NewGameView", || {
|
||||
CoreResponse::HomeView(view) => perftrace("HomeView", || {
|
||||
let api = api.clone();
|
||||
|
||||
let new_game = NewGame::new(api, view);
|
||||
let new_game = Home::new(api, view);
|
||||
window.set_child(Some(&new_game));
|
||||
}),
|
||||
CoreResponse::PlayingFieldView(view) => perftrace("PlayingFieldView", || {
|
||||
|
@ -44,10 +44,17 @@ fn main() {
|
|||
.unwrap(),
|
||||
);
|
||||
|
||||
let user_home = std::env::var("HOME").expect("the user's home directory isn't set");
|
||||
let mut config_path = std::path::PathBuf::from(user_home);
|
||||
config_path.push(".config");
|
||||
config_path.push("kifu");
|
||||
let config_path = std::env::var("CONFIG")
|
||||
.and_then(|config| Ok(std::path::PathBuf::from(config)))
|
||||
.or({
|
||||
std::env::var("HOME").and_then(|base| {
|
||||
let mut config_path = std::path::PathBuf::from(base);
|
||||
config_path.push(".config");
|
||||
config_path.push("kifu");
|
||||
Ok(config_path)
|
||||
})
|
||||
})
|
||||
.expect("no config path could be found");
|
||||
|
||||
let core = CoreApp::new(config_path);
|
||||
|
||||
|
@ -87,7 +94,7 @@ fn main() {
|
|||
}
|
||||
});
|
||||
|
||||
api.dispatch(CoreRequest::NewGame);
|
||||
api.dispatch(CoreRequest::Home);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
use glib::Object;
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
use kifu_core::ui::GamePreviewElement;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GamePreviewPrivate;
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for GamePreviewPrivate {
|
||||
const NAME: &'static str = "GamePreview";
|
||||
type Type = GamePreview;
|
||||
type ParentType = gtk::Box;
|
||||
}
|
||||
|
||||
impl ObjectImpl for GamePreviewPrivate {}
|
||||
impl WidgetImpl for GamePreviewPrivate {}
|
||||
impl BoxImpl for GamePreviewPrivate {}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct GamePreview(ObjectSubclass<GamePreviewPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
|
||||
}
|
||||
|
||||
impl GamePreview {
|
||||
pub fn new(element: GamePreviewElement) -> GamePreview {
|
||||
let s: Self = Object::builder().build();
|
||||
s.set_orientation(gtk::Orientation::Horizontal);
|
||||
|
||||
println!("game_preview: {:?}", element);
|
||||
let black_player = match element.black_rank {
|
||||
Some(rank) => format!("{} ({})", element.black_player, rank.to_string()),
|
||||
None => element.black_player,
|
||||
};
|
||||
let white_player = match element.white_rank {
|
||||
Some(rank) => format!("{} ({})", element.white_player, rank.to_string()),
|
||||
None => element.white_player,
|
||||
};
|
||||
s.append(>k::Label::new(Some(&black_player)));
|
||||
s.append(>k::Label::new(Some(&white_player)));
|
||||
|
||||
s
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
use crate::ui::GamePreview;
|
||||
use crate::CoreApi;
|
||||
use glib::Object;
|
||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||
use kifu_core::{
|
||||
ui::{NewGameView, PlayerElement},
|
||||
ui::{HomeView, PlayerElement},
|
||||
CoreRequest, CreateGameRequest, HotseatPlayerRequest, PlayerInfoRequest,
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
@ -82,12 +83,12 @@ impl PlayerDataEntry {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct NewGamePrivate {
|
||||
pub struct HomePrivate {
|
||||
black_player: Rc<RefCell<Option<PlayerDataEntry>>>,
|
||||
white_player: Rc<RefCell<Option<PlayerDataEntry>>>,
|
||||
}
|
||||
|
||||
impl Default for NewGamePrivate {
|
||||
impl Default for HomePrivate {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
black_player: Rc::new(RefCell::new(None)),
|
||||
|
@ -97,22 +98,22 @@ impl Default for NewGamePrivate {
|
|||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for NewGamePrivate {
|
||||
const NAME: &'static str = "NewGame";
|
||||
type Type = NewGame;
|
||||
impl ObjectSubclass for HomePrivate {
|
||||
const NAME: &'static str = "Home";
|
||||
type Type = Home;
|
||||
type ParentType = gtk::Grid;
|
||||
}
|
||||
|
||||
impl ObjectImpl for NewGamePrivate {}
|
||||
impl WidgetImpl for NewGamePrivate {}
|
||||
impl GridImpl for NewGamePrivate {}
|
||||
impl ObjectImpl for HomePrivate {}
|
||||
impl WidgetImpl for HomePrivate {}
|
||||
impl GridImpl for HomePrivate {}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct NewGame(ObjectSubclass<NewGamePrivate>) @extends gtk::Grid, gtk::Widget;
|
||||
pub struct Home(ObjectSubclass<HomePrivate>) @extends gtk::Grid, gtk::Widget;
|
||||
}
|
||||
|
||||
impl NewGame {
|
||||
pub fn new(api: CoreApi, view: NewGameView) -> NewGame {
|
||||
impl Home {
|
||||
pub fn new(api: CoreApi, view: HomeView) -> Home {
|
||||
let s: Self = Object::builder().build();
|
||||
|
||||
let black_player = PlayerDataEntry::new(view.black_player);
|
||||
|
@ -138,6 +139,12 @@ impl NewGame {
|
|||
}
|
||||
});
|
||||
|
||||
let game_list = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||
s.attach(&game_list, 1, 3, 2, 1);
|
||||
view.games
|
||||
.iter()
|
||||
.for_each(|game_preview| game_list.append(&GamePreview::new(game_preview.clone())));
|
||||
|
||||
s
|
||||
}
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
mod player_card;
|
||||
pub use player_card::PlayerCard;
|
||||
|
||||
mod chat;
|
||||
pub use chat::Chat;
|
||||
|
||||
mod game_preview;
|
||||
pub use game_preview::GamePreview;
|
||||
|
||||
mod player_card;
|
||||
pub use player_card::PlayerCard;
|
||||
|
||||
mod playing_field;
|
||||
pub use playing_field::PlayingField;
|
||||
|
||||
mod new_game;
|
||||
pub use new_game::NewGame;
|
||||
mod home;
|
||||
pub use home::Home;
|
||||
|
||||
mod board;
|
||||
pub use board::Board;
|
||||
|
|
Loading…
Reference in New Issue