diff --git a/controller.py b/controller.py index fe0ccb6a..79fb88be 100644 --- a/controller.py +++ b/controller.py @@ -546,14 +546,17 @@ def callbackSetCtranslate2WeightType(value): def callbackSetDeeplAuthKey(value): print("callbackSetDeeplAuthKey", str(value)) + view.clearNotificationMessage() if len(value) == 39: result = model.authenticationTranslatorDeepLAuthKey(auth_key=value) if result is True: key = value view.printToTextbox_AuthenticationSuccess() + view.showSuccessMessage_DeeplAuthKey() else: key = None view.printToTextbox_AuthenticationError() + view.showErrorMessage_DeeplAuthKey() auth_keys = config.AUTH_KEYS auth_keys["DeepL_API"] = key config.AUTH_KEYS = auth_keys @@ -590,7 +593,7 @@ def callbackSetMicEnergyThreshold(value): try: value = int(value) if 0 <= value and value <= config.MAX_MIC_ENERGY_THRESHOLD: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_MIC_ENERGY_THRESHOLD = value view.setGuiVariable_MicEnergyThreshold(config.INPUT_MIC_ENERGY_THRESHOLD) else: @@ -627,7 +630,7 @@ def callbackSetMicRecordTimeout(value): try: value = int(value) if 0 <= value and value <= config.INPUT_MIC_PHRASE_TIMEOUT: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_MIC_RECORD_TIMEOUT = value view.setGuiVariable_MicRecordTimeout(config.INPUT_MIC_RECORD_TIMEOUT) else: @@ -642,7 +645,7 @@ def callbackSetMicPhraseTimeout(value): try: value = int(value) if 0 <= value and value >= config.INPUT_MIC_RECORD_TIMEOUT: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_MIC_PHRASE_TIMEOUT = value view.setGuiVariable_MicPhraseTimeout(config.INPUT_MIC_PHRASE_TIMEOUT) else: @@ -657,7 +660,7 @@ def callbackSetMicMaxPhrases(value): try: value = int(value) if 0 <= value: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_MIC_MAX_PHRASES = value view.setGuiVariable_MicMaxPhrases(config.INPUT_MIC_MAX_PHRASES) else: @@ -708,7 +711,7 @@ def callbackSetSpeakerEnergyThreshold(value): try: value = int(value) if 0 <= value and value <= config.MAX_SPEAKER_ENERGY_THRESHOLD: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_SPEAKER_ENERGY_THRESHOLD = value view.setGuiVariable_SpeakerEnergyThreshold(config.INPUT_SPEAKER_ENERGY_THRESHOLD) else: @@ -750,7 +753,7 @@ def callbackSetSpeakerRecordTimeout(value): try: value = int(value) if 0 <= value and value <= config.INPUT_SPEAKER_PHRASE_TIMEOUT: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_SPEAKER_RECORD_TIMEOUT = value view.setGuiVariable_SpeakerRecordTimeout(config.INPUT_SPEAKER_RECORD_TIMEOUT) else: @@ -765,7 +768,7 @@ def callbackSetSpeakerPhraseTimeout(value): try: value = int(value) if 0 <= value and value >= config.INPUT_SPEAKER_RECORD_TIMEOUT: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_SPEAKER_PHRASE_TIMEOUT = value view.setGuiVariable_SpeakerPhraseTimeout(config.INPUT_SPEAKER_PHRASE_TIMEOUT) else: @@ -780,7 +783,7 @@ def callbackSetSpeakerMaxPhrases(value): try: value = int(value) if 0 <= value: - view.clearErrorMessage() + view.clearNotificationMessage() config.INPUT_SPEAKER_MAX_PHRASES = value view.setGuiVariable_SpeakerMaxPhrases(config.INPUT_SPEAKER_MAX_PHRASES) else: @@ -854,7 +857,7 @@ def callbackSetSendMessageFormat(value): print("callbackSetSendMessageFormat", value) if isUniqueStrings(["[message]"], value) is True: config.SEND_MESSAGE_FORMAT = value - view.clearErrorMessage() + view.clearNotificationMessage() view.setSendMessageFormat_EntryWidgets(config.SEND_MESSAGE_FORMAT) else: view.showErrorMessage_SendMessageFormat() @@ -865,7 +868,7 @@ def callbackSetSendMessageFormatWithT(value): if len(value) > 0: if isUniqueStrings(["[message]", "[translation]"], value) is True: config.SEND_MESSAGE_FORMAT_WITH_T = value - view.clearErrorMessage() + view.clearNotificationMessage() view.setSendMessageFormatWithT_EntryWidgets(config.SEND_MESSAGE_FORMAT_WITH_T) else: view.showErrorMessage_SendMessageFormatWithT() @@ -876,7 +879,7 @@ def callbackSetReceivedMessageFormat(value): print("callbackSetReceivedMessageFormat", value) if isUniqueStrings(["[message]"], value) is True: config.RECEIVED_MESSAGE_FORMAT = value - view.clearErrorMessage() + view.clearNotificationMessage() view.setReceivedMessageFormat_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT) else: view.showErrorMessage_ReceivedMessageFormat() @@ -887,7 +890,7 @@ def callbackSetReceivedMessageFormatWithT(value): if len(value) > 0: if isUniqueStrings(["[message]", "[translation]"], value) is True: config.RECEIVED_MESSAGE_FORMAT_WITH_T = value - view.clearErrorMessage() + view.clearNotificationMessage() view.setReceivedMessageFormatWithT_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT_WITH_T) else: view.showErrorMessage_ReceivedMessageFormatWithT() diff --git a/locales/en.yml b/locales/en.yml index c885795f..500a00f3 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -130,6 +130,8 @@ config_window: label: DeepL Auth Key desc: Please select %{translator} on the main screen with DeepL_API when using. ※Some languages may not be supported. open_auth_key_webpage: Open DeepL Account Webpage + auth_key_success: Auth key update completed. + auth_key_error: Auth Key is incorrect or Usage limit reached. mic_host: label: Mic Host/Driver diff --git a/locales/ja.yml b/locales/ja.yml index d7d800e1..e9a4492c 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -28,7 +28,7 @@ main_window: disabled_foreground: 最前面への固定を解除しました。 auth_key_success: 認証キーの更新が完了しました。 - auth_key_error: 認証キーが間違っているか、API使用制限が上限に達しています. + auth_key_error: 認証キーが間違っているか、API使用制限が上限に達しています。 no_mic_device_detected_error: マイクデバイスが検出されませんでした。 no_speaker_device_detected_error: スピーカーデバイスが検出されませんでした。 @@ -129,6 +129,8 @@ config_window: label: DeepL 認証キー desc: "使用の際は、メイン画面にある %{translator} をDeepL_APIに変更してください。\n※対応していない言語もあります。" open_auth_key_webpage: DeepLアカウントページを開く + auth_key_success: 認証キーの更新が完了しました。 + auth_key_error: 認証キーが間違っているか、API使用制限が上限に達しています。 mic_host: label: マイク(ホスト/ドライバー) diff --git a/view.py b/view.py index 39ac795f..840a2774 100644 --- a/view.py +++ b/view.py @@ -80,8 +80,8 @@ class View(): **common_args ) - self.settings.error_message_window = SimpleNamespace( - uism=all_uism.error_message_window, + self.settings.notification_message_window = SimpleNamespace( + uism=all_uism.notification_message_window, **common_args ) @@ -297,6 +297,8 @@ class View(): CALLBACK_SET_DEEPL_AUTH_KEY=None, VAR_DEEPL_AUTH_KEY=StringVar(value=config.AUTH_KEYS["DeepL_API"]), VAR_OPEN_DEEPL_WEB_PAGE=StringVar(value=i18n.t( "config_window.deepl_auth_key.open_auth_key_webpage")), + CALLBACK_FOCUS_OUT_DEEPL_AUTH_KEY=self.callbackBindFocusOut_DeeplAuthKey, + # Transcription Tab (Mic) @@ -997,8 +999,8 @@ class View(): def _clearTextBox(entry_widget): entry_widget.delete("1.0", "end") - def clearErrorMessage(self): - vrct_gui._clearErrorMessage() + def clearNotificationMessage(self): + vrct_gui._clearNotificationMessage() @staticmethod @@ -1731,60 +1733,74 @@ class View(): # Callback Bind FocusOut + def callbackBindFocusOut_DeeplAuthKey(self, _e=None): + self.clearNotificationMessage() + def callbackBindFocusOut_MicEnergyThreshold(self, _e=None): self.setLatestConfigVariable("MicEnergyThreshold") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_SpeakerEnergyThreshold(self, _e=None): self.setLatestConfigVariable("SpeakerEnergyThreshold") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_MicRecordTimeout(self, _e=None): self.setLatestConfigVariable("MicRecordTimeout") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_MicPhraseTimeout(self, _e=None): self.setLatestConfigVariable("MicPhraseTimeout") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_MicMaxPhrases(self, _e=None): self.setLatestConfigVariable("MicMaxPhrases") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_SpeakerRecordTimeout(self, _e=None): self.setLatestConfigVariable("SpeakerRecordTimeout") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_SpeakerPhraseTimeout(self, _e=None): self.setLatestConfigVariable("SpeakerPhraseTimeout") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_SpeakerMaxPhrases(self, _e=None): self.setLatestConfigVariable("SpeakerMaxPhrases") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_SendMessageFormat(self, _e=None): self.setLatestConfigVariable("SendMessageFormat") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_SendMessageFormatWithT(self, _e=None): self.setLatestConfigVariable("SendMessageFormatWithT") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_ReceivedMessageFormat(self, _e=None): self.setLatestConfigVariable("ReceivedMessageFormat") - self.clearErrorMessage() + self.clearNotificationMessage() def callbackBindFocusOut_ReceivedMessageFormatWithT(self, _e=None): self.setLatestConfigVariable("ReceivedMessageFormatWithT") - self.clearErrorMessage() + self.clearNotificationMessage() -# Show Error Message (Config Window) +# Show Notification Message (Config Window) + def showSuccessMessage_DeeplAuthKey(self): + self._showSuccessMessage( + vrct_gui.config_window.sb__entry_deepl_auth_key, + i18n.t("config_window.deepl_auth_key.auth_key_success") + ) + def showErrorMessage_DeeplAuthKey(self): + self._showErrorMessage( + vrct_gui.config_window.sb__entry_deepl_auth_key, + i18n.t("config_window.deepl_auth_key.auth_key_error") + ) + def showErrorMessage_MicEnergyThreshold(self): self._showErrorMessage( vrct_gui.config_window.sb__progressbar_x_slider__entry_mic_energy_threshold, @@ -1891,6 +1907,10 @@ class View(): def _makeInvalidValueErrorMessage(error_message): return i18n.t("config_window.common_error_message.invalid_value") + "\n" + error_message + def _showSuccessMessage(self, target_widget, message): + self.view_variable.VAR_ERROR_MESSAGE.set(message) + vrct_gui._showSuccessMessage(target_widget=target_widget) + def _showErrorMessage(self, target_widget, message): self.view_variable.VAR_ERROR_MESSAGE.set(message) vrct_gui._showErrorMessage(target_widget=target_widget) diff --git a/vrct_gui/_CreateErrorWindow.py b/vrct_gui/_CreateNotificationWindow.py similarity index 67% rename from vrct_gui/_CreateErrorWindow.py rename to vrct_gui/_CreateNotificationWindow.py index ef7ff5fb..e7fa2226 100644 --- a/vrct_gui/_CreateErrorWindow.py +++ b/vrct_gui/_CreateNotificationWindow.py @@ -5,7 +5,7 @@ from .ui_utils import getLatestWidth, getLatestHeight from utils import isEven -class _CreateErrorWindow(CTkToplevel): +class _CreateNotificationWindow(CTkToplevel): def __init__( self, settings, @@ -16,7 +16,8 @@ class _CreateErrorWindow(CTkToplevel): message_ipady, message_font_size, - message_bg_color, + error_message_bg_color, + success_message_bg_color, message_text_color, ): @@ -34,7 +35,8 @@ class _CreateErrorWindow(CTkToplevel): self.message_ipady = message_ipady self.message_font_size = message_font_size - self.message_bg_color = message_bg_color + self.error_message_bg_color = error_message_bg_color + self.success_message_bg_color = success_message_bg_color self.message_text_color = message_text_color @@ -51,20 +53,16 @@ class _CreateErrorWindow(CTkToplevel): self.wm_attributes("-alpha", 0) self.wm_attributes("-toolwindow", True) - self.configure(fg_color=self.message_bg_color) - - - self.grid_rowconfigure(0,weight=1) self.grid_columnconfigure(0,weight=1) - self.error_message_container = CTkFrame(self, corner_radius=0, fg_color=self.message_bg_color, width=0, height=0) - self.error_message_container.grid(row=0, column=0, sticky="nsew") + self.notification_message_container = CTkFrame(self, corner_radius=0, width=0, height=0) + self.notification_message_container.grid(row=0, column=0, sticky="nsew") - self.error_message_container_label_wrapper = CTkLabel( - self.error_message_container, + self.notification_message_container_label_wrapper = CTkLabel( + self.notification_message_container, # text=message, textvariable=self._view_variable.VAR_ERROR_MESSAGE, height=0, @@ -74,12 +72,19 @@ class _CreateErrorWindow(CTkToplevel): justify="left", text_color=self.message_text_color, ) - self.error_message_container_label_wrapper.grid(row=0, column=0, padx=self.message_ipadx, pady=self.message_ipady, sticky="nsew") + self.notification_message_container_label_wrapper.grid(row=0, column=0, padx=self.message_ipadx, pady=self.message_ipady, sticky="nsew") - def show(self, target_widget): + def show(self, target_widget, message_type): + if message_type == "Error": + self.notification_message_container.configure(fg_color=self.error_message_bg_color) + elif message_type == "Success": + self.notification_message_container.configure(fg_color=self.success_message_bg_color) + else: + raise ValueError("message_type is not selected") + if self.hide is False: return @@ -92,22 +97,23 @@ class _CreateErrorWindow(CTkToplevel): self.hide = False - label_width = getLatestWidth(self.error_message_container_label_wrapper) - label_height = getLatestHeight(self.error_message_container_label_wrapper) + label_width = getLatestWidth(self.notification_message_container_label_wrapper) + label_height = getLatestHeight(self.notification_message_container_label_wrapper) # for fixing 1px bug if isEven(label_width) is False: - self.error_message_container_label_wrapper.grid(padx=(self.message_ipadx[0], self.message_ipadx[1]-1)) + self.notification_message_container_label_wrapper.grid(padx=(self.message_ipadx[0], self.message_ipadx[1]-1)) else: - self.error_message_container_label_wrapper.grid(padx=self.message_ipadx) + self.notification_message_container_label_wrapper.grid(padx=self.message_ipadx) # for fixing 1px bug if isEven(label_height) is False: - self.error_message_container_label_wrapper.grid(pady=(self.message_ipady[0], self.message_ipady[1]-1)) + self.notification_message_container_label_wrapper.grid(pady=(self.message_ipady[0], self.message_ipady[1]-1)) else: - self.error_message_container_label_wrapper.grid(pady=self.message_ipady) + self.notification_message_container_label_wrapper.grid(pady=self.message_ipady) + # First show animation for i in range(0,101,20): if not self.winfo_exists(): break @@ -117,12 +123,14 @@ class _CreateErrorWindow(CTkToplevel): sleep(0.1) - for i in range(0,91,10): - if not self.winfo_exists(): - break - self.attributes("-alpha", i/100) - self.update() - sleep(1/80) + # Blink animation + if message_type == "Error": + for i in range(0,91,10): + if not self.winfo_exists(): + break + self.attributes("-alpha", i/100) + self.update() + sleep(1/80) def _withdraw(self, e=None): diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py index 7e3a9ba5..3350b4d8 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_translation/createSettingBox_Translation.py @@ -47,6 +47,7 @@ def createSettingBox_Translation(setting_box_wrapper, config_window, settings, v entry_attr_name="sb__entry_deepl_auth_key", entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_300, entry_bind__Any_KeyRelease=lambda value: deeplAuthKeyCallback(value), + entry_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_DEEPL_AUTH_KEY, entry_textvariable=view_variable.VAR_DEEPL_AUTH_KEY, open_authkey_page_command=lambda _e: callFunctionIfCallable(view_variable.CALLBACK_OPEN_WEBPAGE_DEEPL_AUTH_KEY), open_authkey_text_variable=view_variable.VAR_OPEN_DEEPL_WEB_PAGE, diff --git a/vrct_gui/ui_managers/Themes/_darkTheme.py b/vrct_gui/ui_managers/Themes/_darkTheme.py index 1b5fc339..71cbc292 100644 --- a/vrct_gui/ui_managers/Themes/_darkTheme.py +++ b/vrct_gui/ui_managers/Themes/_darkTheme.py @@ -294,6 +294,7 @@ def _darkTheme(base_color): # Error Message Window for Config Window # The color code [#bb4448] is a mixture of [#a9555c] and [#cc3333] (for a redder shade). SB__ERROR_MESSAGE_BG_COLOR = "#bb4448", + SB__SUCCESS_MESSAGE_BG_COLOR = "#368777", SB__ERROR_MESSAGE_TEXT_COLOR = "#fff", ), diff --git a/vrct_gui/ui_managers/Themes/_lightTheme.py b/vrct_gui/ui_managers/Themes/_lightTheme.py index d953372c..fbaf1201 100644 --- a/vrct_gui/ui_managers/Themes/_lightTheme.py +++ b/vrct_gui/ui_managers/Themes/_lightTheme.py @@ -288,6 +288,7 @@ def _lightTheme(base_color): # Error Message Window for Config Window # Check DarkTheme's this part. Based on the color bb4448, used to source, and pick up the number 600 by the generator (https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors) SB__ERROR_MESSAGE_BG_COLOR = "#cd4c4f", + SB__SUCCESS_MESSAGE_BG_COLOR = "#cd4c4f", SB__ERROR_MESSAGE_TEXT_COLOR = "#fff", ), diff --git a/vrct_gui/ui_managers/UiScalingManager.py b/vrct_gui/ui_managers/UiScalingManager.py index 85204af7..798f3412 100644 --- a/vrct_gui/ui_managers/UiScalingManager.py +++ b/vrct_gui/ui_managers/UiScalingManager.py @@ -11,7 +11,7 @@ class UiScalingManager(): self.config_window = SimpleNamespace() self.selectable_language_window = SimpleNamespace() self.main_window_cover = SimpleNamespace() - self.error_message_window = SimpleNamespace() + self.notification_message_window = SimpleNamespace() self.confirmation_modal = SimpleNamespace() self.dropdown_menu_window = SimpleNamespace() diff --git a/vrct_gui/vrct_gui.py b/vrct_gui/vrct_gui.py index 25369a6a..0a795436 100644 --- a/vrct_gui/vrct_gui.py +++ b/vrct_gui/vrct_gui.py @@ -3,7 +3,7 @@ from customtkinter import CTk, CTkImage from ._CreateSelectableLanguagesWindow import _CreateSelectableLanguagesWindow from ._CreateWindowCover import _CreateWindowCover -from ._CreateErrorWindow import _CreateErrorWindow +from ._CreateNotificationWindow import _CreateNotificationWindow from ._CreateDropdownMenuWindow import _CreateDropdownMenuWindow from ._changeMainWindowWidgetsStatus import _changeMainWindowWidgetsStatus from ._changeConfigWindowWidgetsStatus import _changeConfigWindowWidgetsStatus @@ -140,8 +140,8 @@ class VRCT_GUI(CTk): view_variable=self._view_variable ) - self.error_message_window = _CreateErrorWindow( - settings=self.settings.error_message_window, + self.notification_message_window = _CreateNotificationWindow( + settings=self.settings.notification_message_window, view_variable=self._view_variable, wrapper_widget=self.config_window.main_bg_container, @@ -149,7 +149,8 @@ class VRCT_GUI(CTk): message_ipady=self.settings.config_window.uism.SB__ERROR_MESSAGE_IPADY, message_font_size=self.settings.config_window.uism.SB__ERROR_MESSAGE_FONT_SIZE, - message_bg_color=self.settings.config_window.ctm.SB__ERROR_MESSAGE_BG_COLOR, + error_message_bg_color=self.settings.config_window.ctm.SB__ERROR_MESSAGE_BG_COLOR, + success_message_bg_color=self.settings.config_window.ctm.SB__SUCCESS_MESSAGE_BG_COLOR, message_text_color=self.settings.config_window.ctm.SB__ERROR_MESSAGE_TEXT_COLOR, ) @@ -298,11 +299,14 @@ class VRCT_GUI(CTk): def _showErrorMessage(self, target_widget): - self.error_message_window.show(target_widget=target_widget) + self.notification_message_window.show(target_widget=target_widget, message_type="Error") - def _clearErrorMessage(self): + def _showSuccessMessage(self, target_widget): + self.notification_message_window.show(target_widget=target_widget, message_type="Success") + + def _clearNotificationMessage(self): try: - self.error_message_window._withdraw() + self.notification_message_window._withdraw() except Exception: pass