front-end: Impl Reset button

This commit is contained in:
Stephen Seo 2022-04-25 15:02:18 +09:00
parent d55e43cc6c
commit b26c9ff6d1
2 changed files with 150 additions and 57 deletions

View file

@ -188,6 +188,12 @@
opacity: 1; opacity: 1;
} }
} }
button#resetbutton {
background-color: #C55;
color: #FFF;
grid-row: 2;
grid-column: 8;
}
</style> </style>
</head> </head>
</html> </html>

View file

@ -52,8 +52,6 @@ impl Component for MainMenu {
.link() .link()
.context::<SharedState>(Callback::noop()) .context::<SharedState>(Callback::noop())
.expect("state to be set"); .expect("state to be set");
match shared.game_state.get() {
GameState::MainMenu => {
let player_type: Turn; let player_type: Turn;
{ {
let mut rng = get_seeded_random().expect("Random should be available"); let mut rng = get_seeded_random().expect("Random should be available");
@ -68,25 +66,29 @@ impl Component for MainMenu {
let normal_player_type = player_type; let normal_player_type = player_type;
let hard_player_type = player_type; let hard_player_type = player_type;
let onclick_singleplayer_easy = ctx.link().callback(move |_| { let onclick_singleplayer_easy = ctx
MainMenuMessage::SinglePlayer(easy_player_type, AIDifficulty::Easy) .link()
}); .callback(move |_| MainMenuMessage::SinglePlayer(easy_player_type, AIDifficulty::Easy));
let onclick_singleplayer_normal = ctx.link().callback(move |_| { let onclick_singleplayer_normal = ctx.link().callback(move |_| {
MainMenuMessage::SinglePlayer(normal_player_type, AIDifficulty::Normal) MainMenuMessage::SinglePlayer(normal_player_type, AIDifficulty::Normal)
}); });
let onclick_singleplayer_hard = ctx.link().callback(move |_| { let onclick_singleplayer_hard = ctx
MainMenuMessage::SinglePlayer(hard_player_type, AIDifficulty::Hard) .link()
}); .callback(move |_| MainMenuMessage::SinglePlayer(hard_player_type, AIDifficulty::Hard));
let onclick_local_multiplayer = let onclick_local_multiplayer = ctx.link().callback(|_| MainMenuMessage::LocalMultiplayer);
ctx.link().callback(|_| MainMenuMessage::LocalMultiplayer);
let onclick_networked_multiplayer = ctx let onclick_networked_multiplayer = ctx
.link() .link()
.callback(|_| MainMenuMessage::NetworkedMultiplayer); .callback(|_| MainMenuMessage::NetworkedMultiplayer);
let menu_class = if shared.game_state.get() == GameState::MainMenu {
"menu"
} else {
"hidden_menu"
};
html! { html! {
<div class={"menu"} id={"mainmenu"}> <div class={menu_class} id={"mainmenu"}>
<b class={"menuText"}>{"Please pick a game mode."}</b> <b class={"menuText"}>{"Please pick a game mode."}</b>
<div class={"singlePlayerMenu"}> <div class={"singlePlayerMenu"}>
<button class={"menuSinglePlayerEasy"} onclick={onclick_singleplayer_easy}> <button class={"menuSinglePlayerEasy"} onclick={onclick_singleplayer_easy}>
@ -108,12 +110,6 @@ impl Component for MainMenu {
</div> </div>
} }
} }
_ => html! {
<div class={"hidden_menu"} id={"mainmenu"}>
</div>
},
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool { fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
let (shared, _) = ctx let (shared, _) = ctx
@ -129,7 +125,6 @@ impl Component for MainMenu {
.get_element_by_id("mainmenu") .get_element_by_id("mainmenu")
.expect("mainmenu should exist"); .expect("mainmenu should exist");
mainmenu.set_class_name("hidden_menu"); mainmenu.set_class_name("hidden_menu");
mainmenu.set_inner_html("");
match shared.game_state.get() { match shared.game_state.get() {
GameState::SinglePlayer(turn, _) => { GameState::SinglePlayer(turn, _) => {
@ -176,7 +171,7 @@ impl Component for MainMenu {
.expect("Wrapper should be a parent of MainMenu") .expect("Wrapper should be a parent of MainMenu")
.clone() .clone()
.downcast::<Wrapper>() .downcast::<Wrapper>()
.send_message(WrapperMsg::BackendTick); .send_message(WrapperMsg::StartBackendTick);
} }
_ => { _ => {
append_to_info_text( append_to_info_text(
@ -194,6 +189,36 @@ impl Component for MainMenu {
} }
} }
struct ResetButton {}
impl Component for ResetButton {
type Message = ();
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let onclick_reset = ctx.link().callback(|_| ());
html! {
<button class={"resetbutton"} id={"resetbutton"} onclick={onclick_reset}>
{"Reset"}
</button>
}
}
fn update(&mut self, ctx: &Context<Self>, _msg: Self::Message) -> bool {
ctx.link()
.get_parent()
.expect("Wrapper should be parent of ResetButton")
.clone()
.downcast::<Wrapper>()
.send_message(WrapperMsg::Reset);
true
}
}
pub struct Slot {} pub struct Slot {}
pub enum SlotMessage { pub enum SlotMessage {
@ -575,6 +600,8 @@ pub enum WrapperMsg {
AIPressed(u8), AIPressed(u8),
AIChoice, AIChoice,
AIChoiceImpl, AIChoiceImpl,
StartBackendTick,
StartBackendTickImpl,
BackendTick, BackendTick,
BackendRequest { place: u8 }, BackendRequest { place: u8 },
BackendResponse(BREnum), BackendResponse(BREnum),
@ -607,6 +634,7 @@ impl Component for Wrapper {
html! { html! {
<div class="wrapper"> <div class="wrapper">
<MainMenu /> <MainMenu />
<ResetButton />
<Slot idx=0 state={shared.board[0].clone()} placed={shared.placed[0].clone()} /> <Slot idx=0 state={shared.board[0].clone()} placed={shared.placed[0].clone()} />
<Slot idx=1 state={shared.board[1].clone()} placed={shared.placed[1].clone()} /> <Slot idx=1 state={shared.board[1].clone()} placed={shared.placed[1].clone()} />
<Slot idx=2 state={shared.board[2].clone()} placed={shared.placed[2].clone()} /> <Slot idx=2 state={shared.board[2].clone()} placed={shared.placed[2].clone()} />
@ -1175,8 +1203,44 @@ impl Component for Wrapper {
} }
} }
} }
WrapperMsg::StartBackendTick => {
self.defer_message(
ctx,
WrapperMsg::StartBackendTickImpl,
BACKEND_TICK_DURATION_MILLIS,
);
}
WrapperMsg::StartBackendTickImpl => {
// If previous id is still stored, request disconnect so that a
// new id can be received
if let Some(id) = self.player_id.take() {
let function = Function::new_no_args(&format!(
"
let xhr = new XMLHttpRequest();
xhr.open('POST', '{}');
xhr.send('{{\"type\": \"disconnect\", \"id\": {}}}');
",
BACKEND_URL, id
));
function.call0(&function).ok();
}
self.do_backend_tick = true;
ctx.link().send_message(WrapperMsg::BackendTick);
}
WrapperMsg::BackendTick => { WrapperMsg::BackendTick => {
if !self.do_backend_tick { if !self.do_backend_tick || shared.game_state.get() == GameState::default() {
// disconnect id if backend tick is to be stopped
if let Some(id) = self.player_id.take() {
let function = Function::new_no_args(&format!(
"
let xhr = new XMLHttpRequest();
xhr.open('POST', '{}');
xhr.send('{{\"type\": \"disconnect\", \"id\": {}}}');
",
BACKEND_URL, id
));
function.call0(&function).ok();
}
return false; return false;
} }
@ -1415,6 +1479,13 @@ impl Component for Wrapper {
self.do_backend_tick = false; self.do_backend_tick = false;
} }
NetworkedGameState::Disconnected => { NetworkedGameState::Disconnected => {
append_to_info_text(
&document,
"info_text0",
"The opponent disconnected",
INFO_TEXT_MAX_ITEMS,
)
.ok();
append_to_info_text( append_to_info_text(
&document, &document,
"info_text1", "info_text1",
@ -1593,6 +1664,22 @@ impl Component for Wrapper {
function.call0(&function).ok(); function.call0(&function).ok();
} }
self.place_request = None; self.place_request = None;
element_remove_class(&document, "mainmenu", "hidden_menu").ok();
element_append_class(&document, "mainmenu", "menu").ok();
append_to_info_text(
&document,
"info_text1",
"<b>Waiting to choose game-mode...</b>",
1,
)
.ok();
append_to_info_text(
&document,
"info_text0",
"Reset button was pressed",
INFO_TEXT_MAX_ITEMS,
)
.ok();
self.do_backend_tick = false; self.do_backend_tick = false;
} }
} // match (msg) } // match (msg)