from pathlib import Path from kivy.clock import Clock from kivy.metrics import dp from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.popup import Popup from kivy.uix.textinput import TextInput from src.markovbot_gui.libs.settings import Settings from src.markovbot_gui.libs.timer import logger class ConfigWindow(BoxLayout): def __init__(self, config_path: Path, **kwargs): super().__init__(**kwargs) self.config_path = config_path self.orientation = "vertical" self.spacing = dp(10) self.padding = dp(20) # Load existing configuration default_config = { "Host": "irc.chat.twitch.tv", "Port": 6667, "Channel": "#", "Nickname": "", "Authentication": "oauth:", "DeniedUsers": ["StreamElements", "Nightbot", "Moobot", "Marbiebot"], "Cooldown": 20, "KeyLength": 2, "MaxSentenceWordAmount": 25, "MinSentenceWordAmount": -1, "HelpMessageTimer": 60 * 60 * 5, # 18000 seconds, 5 hours "AutomaticGenerationTimer": -1, "WhisperCooldown": True, "EnableGenerateCommand": True, "SentenceSeparator": " - ", "AllowGenerateParams": True, } if config_path.exists(): self.s = Settings.read(config_path) else: self.s = Settings(**default_config) # type: ignore[arg-type] self.s.write(config_path) # Create widgets # Channel input channel_layout = BoxLayout( orientation="horizontal", size_hint_y=None, height=dp(40), ) channel_label = Label(text="Channel:", size_hint_x=0.3) self.channel_input = TextInput( multiline=False, size_hint_x=0.7, text=self.s.channel, ) channel_layout.add_widget(channel_label) channel_layout.add_widget(self.channel_input) # Nickname input nickname_layout = BoxLayout( orientation="horizontal", size_hint_y=None, height=dp(40), ) nickname_label = Label(text="Nickname:", size_hint_x=0.3) self.nickname_input = TextInput( multiline=False, size_hint_x=0.7, text=self.s.nickname, ) nickname_layout.add_widget(nickname_label) nickname_layout.add_widget(self.nickname_input) # Authentication input auth_layout = BoxLayout( orientation="horizontal", size_hint_y=None, height=dp(40), ) auth_label = Label(text="Auth:", size_hint_x=0.3) self.auth_input = TextInput( multiline=False, size_hint_x=0.7, password=True, text=self.s.authentication, ) auth_layout.add_widget(auth_label) auth_layout.add_widget(self.auth_input) automatic_generation_label = Label(text="Automatic generation (seconds): ") self.automatic_generation_input = TextInput( multiline=False, size_hint_x=0.7, text=str(self.s.automatic_generation_timer), ) automatic_generation_layout = BoxLayout( orientation="horizontal", size_hint_y=None, height=dp(40), ) automatic_generation_layout.add_widget(automatic_generation_label) automatic_generation_layout.add_widget(self.automatic_generation_input) # Save button save_button = Button( text="Save", size_hint=(None, None), size=(dp(100), dp(40)), pos_hint={"center_x": 0.5}, ) save_button.bind(on_release=self.save_config) # Add all widgets to the layout self.add_widget(channel_layout) self.add_widget(nickname_layout) self.add_widget(auth_layout) self.add_widget(automatic_generation_layout) self.add_widget(save_button) def save_config(self, instance): try: self.s.channel = self.channel_input.text.strip() self.s.nickname = self.nickname_input.text.strip() self.s.authentication = self.auth_input.text.strip() self.s.automatic_generation_timer = int( self.automatic_generation_input.text ) if 0 < self.s.automatic_generation_timer < 29: # noqa: PLR2004 raise ValueError( "Value for 'Automatic generation' must be at least 30 seconds, " # noqa: EM101 "or a negative number for no automatic generations." ) self.s.write(self.config_path) # Show success message success_popup = Popup( title="Success", content=Label(text="Configuration saved successfully"), size_hint=(None, None), size=(dp(250), dp(100)), ) success_popup.open() Clock.schedule_once(success_popup.dismiss, 1) except Exception as e: # noqa: BLE001 self.show_error_message(f"Failed to save configuration:\n{e!s}") error_popup = Popup( title="Error", content=Label(text=f"Failed to save configuration:\n{e!s}"), size_hint=(None, None), size=(dp(400), dp(150)), ) error_popup.open() logger.exception("Failed to save configuration")