diff --git a/pyproject.toml b/pyproject.toml index c854931..a4fed70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "vapor-steam" -version = "1.3.2" +version = "1.4.0" description = "TUI program to check the ProtonDB compatibility of all the games of a Steam user." authors = ["TabulateJarl8 "] license = "GPLv3" @@ -78,8 +78,6 @@ extend-select = [ "ARG", # flake8-use-pathlib "PTH", - # flake8-todos - "TD", # eradicate "ERA", # perflint diff --git a/vapor/config_handler.py b/vapor/config_handler.py index 74bac38..558ee14 100644 --- a/vapor/config_handler.py +++ b/vapor/config_handler.py @@ -6,24 +6,33 @@ """The path to the config file.""" -def write_steam_api_key(api_key: str): - """Writes the Steam API key to the config file. +# TODO: make this into a class so that i don't have to read it multiple times +def write_config(key: str, value: str): + """Writes a value to the config file. Args: - api_key (str): The Steam API key. + key (str): The key to write. + value (str): The value to write. """ try: data = configparser.ConfigParser() - data.add_section('vapor') - data.set('vapor', 'steam-api-key', api_key) + data.read(CONFIG_PATH) + + if not data.has_section('vapor'): + data.add_section('vapor') + + data.set('vapor', key, value) with CONFIG_PATH.open('w') as f: data.write(f) except Exception: pass -def read_steam_api_key() -> str: - """Read the Steam API key from the config file if it exists. +def read_config(key: str) -> str: + """Read a value from the config file if it exists. + + Args: + key (str): The key to read. Returns: str: The API key if it exists. If not, an empty string. @@ -32,10 +41,8 @@ def read_steam_api_key() -> str: parser = configparser.ConfigParser() if CONFIG_PATH.exists(): parser.read(CONFIG_PATH) - if 'vapor' in parser.sections() and 'steam-api-key' in parser.options( - 'vapor' - ): - return parser.get('vapor', 'steam-api-key') + if 'vapor' in parser.sections() and key in parser.options('vapor'): + return parser.get('vapor', key) return '' except Exception: diff --git a/vapor/main.py b/vapor/main.py index bd16eb8..36c115d 100644 --- a/vapor/main.py +++ b/vapor/main.py @@ -4,17 +4,27 @@ from rich.text import Text from textual import on, work from textual.app import App, ComposeResult -from textual.containers import Center -from textual.screen import ModalScreen +from textual.containers import Center, Container, Horizontal, VerticalScroll +from textual.screen import ModalScreen, Screen from textual.validation import Regex -from textual.widgets import Button, DataTable, Header, Input, Label +from textual.widgets import ( + Button, + DataTable, + Footer, + Header, + Input, + Label, + Markdown, + Static, + Switch, +) from vapor import argument_handler from vapor.api_interface import ( get_anti_cheat_data, get_steam_user_data, ) -from vapor.config_handler import read_steam_api_key, write_steam_api_key +from vapor.config_handler import read_config, write_config from vapor.data_structures import ( PRIVATE_ACCOUNT_HELP_MESSAGE, RATING_DICT, @@ -24,6 +34,34 @@ from vapor.exceptions import InvalidIDError, PrivateAccountError, UnauthorizedError +class SettingsScreen(Screen): + BINDINGS = [('escape', 'app.pop_screen', 'Close Settings')] + + def compose(self) -> ComposeResult: + with Container(id='content-container'): + yield Markdown('# Settings', classes='heading') + + with VerticalScroll(): + yield Horizontal( + Static('Preserve Profile URL Input Value: ', classes='label'), + Switch( + value=read_config('preserve-user-id') == 'true', + id='preserve-user-id', + ), + classes='container', + ) + + yield Footer() + + def on_mount(self) -> None: + if not read_config('preserve-user-id'): + write_config('preserve-user-id', 'true') + + @on(Switch.Changed) + def on_setting_changed(self, event: Switch.Changed): + write_config(event.switch.id, str(event.value).lower()) # type: ignore + + class PrivateAccountScreen(ModalScreen): def compose(self) -> ComposeResult: yield Center( @@ -39,32 +77,40 @@ def on_button_pressed(self) -> None: class SteamApp(App): CSS_PATH = 'main.tcss' TITLE = 'Steam Profile Proton Compatibility Checker' + BINDINGS = [('ctrl+s', "push_screen('settings')", 'Settings')] def compose(self) -> ComposeResult: self.show_account_help_dialog = False yield Header() - yield Center( - Input( - value=read_steam_api_key(), - placeholder='Steam API Key', - id='api-key', - validators=Regex(r'[A-Z0-9]{32}'), + yield Container( + Center( + Input( + value=read_config('steam-api-key'), + placeholder='Steam API Key', + id='api-key', + validators=Regex(r'[A-Z0-9]{32}'), + ), + Input( + placeholder='Profile URL or Steam ID', + value=read_config('user-id') + if read_config('preserve-user-id') == 'true' + else '', + id='user-id', + validators=Regex(r'.+'), + ), + id='input-container', ), - Input( - placeholder='Profile URL or Steam ID', - id='user-id', - validators=Regex(r'.+'), + Center(Button('Check Profile', variant='primary')), + Center( + Label( + Text.assemble('User Average Rating: ', ('N/A', 'magenta')), + id='user-rating', + ) ), - id='input-container', - ) - yield Center(Button('Check Profile', variant='primary')) - yield Center( - Label( - Text.assemble('User Average Rating: ', ('N/A', 'magenta')), - id='user-rating', - ) + DataTable(zebra_stripes=True), + id='body', ) - yield DataTable(zebra_stripes=True) + yield Footer() def on_mount(self) -> None: # add nothing to table so that it shows up @@ -74,6 +120,8 @@ def on_mount(self) -> None: for _ in range(12): table.add_row('', '') + self.install_screen(SettingsScreen(), name='settings') + @work(exclusive=True) @on(Button.Pressed) @on(Input.Submitted) @@ -99,10 +147,7 @@ async def populate_table(self) -> None: api_key: Input = self.query_one('#api-key') # type: ignore id: Input = self.query_one('#user-id') # type: ignore - write_steam_api_key(api_key.value) - - # fetch anti-cheat data - cache = await get_anti_cheat_data() + write_config('steam-api-key', api_key.value) # parse id input to add URL compatibility parsed_url = urlparse(id.value) @@ -112,6 +157,12 @@ async def populate_table(self) -> None: id.value = Path(parsed_url.path).name id.refresh() + if read_config('preserve-user-id') == 'true': + write_config('user-id', id.value) + + # fetch anti-cheat data + cache = await get_anti_cheat_data() + # Fetch user data user_data = await get_steam_user_data(api_key.value, id.value) table.clear() diff --git a/vapor/main.tcss b/vapor/main.tcss index abf8720..09548df 100644 --- a/vapor/main.tcss +++ b/vapor/main.tcss @@ -1,4 +1,4 @@ -Screen { +#body { padding: 2; } @@ -43,4 +43,28 @@ PrivateAccountScreen { #acct-info { padding-bottom: 1; +} + +Screen { + align: center middle; +} + +#content-container { + width: 50%; + height: auto; + max-height: 100%; + padding: 1 2; + background: $panel; + color: $text; + border: $secondary tall; +} + +#content-container * { + align: center top; +} + +.label { + height: 3; + content-align: center middle; + width: auto; } \ No newline at end of file