DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

ref: a8f056d1523e00e69662e2868f3976103ead82ff deck-builder/sdbclient/src/plugins/menu/accountlogin/mod.rs -rw-r--r-- 3.5 KiB
a8f056d1Jonni Liljamo Move register/login to plugins, implement mostly 1 year, 9 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * This file is part of sdbclient
 * Copyright (C) 2022 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use bevy::{
    prelude::*,
    tasks::{AsyncComputeTaskPool, Task},
};
use bevy_console::PrintConsoleLine;

use futures_lite::future;

use crate::{
    api::{self, user::ResponseToken},
    cfg::{self, CfgDirs, CfgHidden, CfgUser},
    util,
};

use super::MenuState;

pub mod ui;

pub struct AccountLoginPlugin;

impl Plugin for AccountLoginPlugin {
    fn build(&self, app: &mut App) {
        app.add_state(LoginState::None)
            // UI system
            .insert_resource(ui::InputsUserLogin::new())
            .add_system_set(
                SystemSet::on_update(LoginState::Input).with_system(ui::account_login_ui),
            )
            // Login system, as in calling the API
            .add_system_set(
                SystemSet::on_enter(LoginState::LoggingIn).with_system(start_login_call),
            )
            .add_system_set(
                SystemSet::on_update(LoginState::LoggingIn).with_system(handle_login_call),
            );
    }
}

/// Login State
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub enum LoginState {
    None,
    Input,
    LoggingIn,
}

#[derive(Component)]
struct LoginCall(Task<ResponseToken>);

fn start_login_call(
    mut commands: Commands,
    cfg_hidden: Res<CfgHidden>,
    inputs: Res<ui::InputsUserLogin>,
) {
    let api_address = cfg_hidden.api_server.clone();
    let i = inputs.clone();

    let thread_pool = AsyncComputeTaskPool::get();
    let task = thread_pool.spawn(async move {
        let token_response = api::user::token(api_address, i.email, i.password);

        token_response
    });
    commands.spawn(LoginCall(task));
}

fn handle_login_call(
    mut commands: Commands,
    mut login_call_tasks: Query<(Entity, &mut LoginCall)>,
    mut inputs: ResMut<ui::InputsUserLogin>,
    mut login_state: ResMut<State<LoginState>>,
    mut menu_state: ResMut<State<MenuState>>,
    mut cfg_user: ResMut<CfgUser>,
    cfg_dirs: Res<CfgDirs>,
    mut console: EventWriter<PrintConsoleLine>,
) {
    let (entity, mut task) = login_call_tasks.single_mut();
    if let Some(login_response) = future::block_on(future::poll_once(&mut task.0)) {
        match login_response {
            ResponseToken::Valid(res) => {
                console.send(PrintConsoleLine::new(format!(
                    "Logged in with: {}",
                    inputs.email
                )));

                // TODO: We need to fetch the user details at some point.
                *cfg_user = CfgUser {
                    logged_in: true,
                    user_token: res.token,
                    id: res.id,
                    username: "NOT SET".to_string(),
                    email: "NOT SET".to_string(),
                };

                util::sl::save(
                    cfg_dirs.0.config_dir().to_str().unwrap(),
                    cfg::FILE_CFG_USER,
                    &cfg_user.into_inner(),
                    console,
                );

                login_state.set(LoginState::None).unwrap();
                menu_state.set(MenuState::AccountLoggedIn).unwrap();
            }
            ResponseToken::Error { error } => {
                inputs.error = error;
                login_state.set(LoginState::Input).unwrap();
            }
        }

        // Remove the task, since it's done now
        commands.entity(entity).remove::<LoginCall>();
        commands.entity(entity).despawn_recursive();
    }
}