feat: implement settings dialog for configuration of authentication, paths, and language
This commit is contained in:
@@ -122,6 +122,21 @@ STRINGS = {
|
||||
"msg_update_failed_code": "Upload fejlede: {code}",
|
||||
"msg_unknown_error": "Ukendt fejl",
|
||||
"type_unknown": "Ukendt",
|
||||
"btn_settings": "⚙️ Indstillinger",
|
||||
"settings_title": "Indstillinger",
|
||||
"settings_auth_group": "Authentication / API",
|
||||
"settings_client_id": "App (Client) ID:",
|
||||
"settings_tenant_id": "Tenant ID:",
|
||||
"settings_path_group": "Systemstier",
|
||||
"settings_temp_dir": "Midlertidig mappe:",
|
||||
"settings_app_path": "Applikationssti:",
|
||||
"settings_active_temp_path": "Aktuel Temp-sti:",
|
||||
"settings_lang_group": "Sprog / UI",
|
||||
"settings_language": "Programsprog:",
|
||||
"settings_save": "Gem indstillinger",
|
||||
"settings_cancel": "Annuller",
|
||||
"msg_settings_saved": "Indstillingerne er gemt.",
|
||||
"msg_restart_required": "Visse ændringer (f.eks. ID'er) træder først i kraft efter genstart.",
|
||||
"status_login_needed": "Session udløbet. Log ind igen."
|
||||
},
|
||||
"en": {
|
||||
@@ -192,6 +207,21 @@ STRINGS = {
|
||||
"msg_update_failed_code": "Upload failed: {code}",
|
||||
"msg_unknown_error": "Unknown error",
|
||||
"type_unknown": "Unknown",
|
||||
"btn_settings": "⚙️ Settings",
|
||||
"settings_title": "Settings",
|
||||
"settings_auth_group": "Authentication / API",
|
||||
"settings_client_id": "App (Client) ID:",
|
||||
"settings_tenant_id": "Tenant ID:",
|
||||
"settings_path_group": "System Paths",
|
||||
"settings_temp_dir": "Temporary folder:",
|
||||
"settings_app_path": "Application path:",
|
||||
"settings_active_temp_path": "Active Temp path:",
|
||||
"settings_lang_group": "Language / UI",
|
||||
"settings_language": "App Language:",
|
||||
"settings_save": "Save Settings",
|
||||
"settings_cancel": "Cancel",
|
||||
"msg_settings_saved": "Settings saved.",
|
||||
"msg_restart_required": "Some changes (e.g., IDs) only take effect after restart.",
|
||||
"status_login_needed": "Session expired. Please login again."
|
||||
}
|
||||
}
|
||||
@@ -243,6 +273,117 @@ def format_size(bytes_num):
|
||||
else:
|
||||
return f"{bytes_num/(1024**3):.1f} GB"
|
||||
|
||||
def is_configured(cfg):
|
||||
placeholders = ["DIN_CLIENT_ID_HER", "DIN_TENANT_ID_HER", ""]
|
||||
return cfg.get("client_id") not in placeholders and cfg.get("tenant_id") not in placeholders
|
||||
|
||||
class SettingsDialog(wx.Dialog):
|
||||
def __init__(self, parent, current_settings):
|
||||
lang = current_settings.get("language", "da")
|
||||
title = STRINGS[lang].get("settings_title", "Settings")
|
||||
super().__init__(parent, title=title, size=(520, 620))
|
||||
|
||||
self.settings = current_settings.copy()
|
||||
self.lang = lang
|
||||
self.InitUI()
|
||||
|
||||
def get_txt(self, key):
|
||||
return STRINGS[self.lang].get(key, key)
|
||||
|
||||
def InitUI(self):
|
||||
vbox = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
panel = wx.Panel(self)
|
||||
inner_vbox = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
# --- Group: Authentication ---
|
||||
auth_box = wx.StaticBox(panel, label=self.get_txt("settings_auth_group"))
|
||||
auth_sizer = wx.StaticBoxSizer(auth_box, wx.VERTICAL)
|
||||
|
||||
grid = wx.FlexGridSizer(2, 2, 10, 10)
|
||||
grid.AddGrowableCol(1, 1)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label=self.get_txt("settings_client_id")), 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
||||
self.client_id_ctrl = wx.TextCtrl(panel, value=self.settings.get("client_id", ""), size=(-1, 25))
|
||||
grid.Add(self.client_id_ctrl, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label=self.get_txt("settings_tenant_id")), 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
||||
self.tenant_id_ctrl = wx.TextCtrl(panel, value=self.settings.get("tenant_id", ""), size=(-1, 25))
|
||||
grid.Add(self.tenant_id_ctrl, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
|
||||
|
||||
auth_sizer.Add(grid, 1, wx.EXPAND | wx.ALL, 10)
|
||||
inner_vbox.Add(auth_sizer, 0, wx.EXPAND | wx.ALL, 10)
|
||||
|
||||
# --- Group: Paths ---
|
||||
path_box = wx.StaticBox(panel, label=self.get_txt("settings_path_group"))
|
||||
path_sizer = wx.StaticBoxSizer(path_box, wx.VERTICAL)
|
||||
|
||||
path_sizer.Add(wx.StaticText(panel, label=self.get_txt("settings_temp_dir")), 0, wx.BOTTOM, 5)
|
||||
self.temp_dir_picker = wx.DirPickerCtrl(panel, path=self.settings.get("temp_dir", "C:\\Temp_SP"),
|
||||
style=wx.DIRP_DIR_MUST_EXIST)
|
||||
path_sizer.Add(self.temp_dir_picker, 0, wx.EXPAND | wx.BOTTOM, 10)
|
||||
|
||||
path_sizer.Add(wx.StaticText(panel, label=self.get_txt("settings_app_path")), 0, wx.BOTTOM, 5)
|
||||
app_path_box = wx.TextCtrl(panel, value=CONFIG_DIR, style=wx.TE_READONLY | wx.BORDER_NONE)
|
||||
app_path_box.SetBackgroundColour(panel.GetBackgroundColour())
|
||||
path_sizer.Add(app_path_box, 0, wx.EXPAND | wx.BOTTOM, 10)
|
||||
|
||||
path_sizer.Add(wx.StaticText(panel, label=self.get_txt("settings_active_temp_path")), 0, wx.BOTTOM, 5)
|
||||
temp_path_box = wx.TextCtrl(panel, value=TEMP_DIR, style=wx.TE_READONLY | wx.BORDER_NONE)
|
||||
temp_path_box.SetBackgroundColour(panel.GetBackgroundColour())
|
||||
path_sizer.Add(temp_path_box, 0, wx.EXPAND)
|
||||
|
||||
inner_vbox.Add(path_sizer, 0, wx.EXPAND | wx.ALL, 10)
|
||||
|
||||
# --- Group: Language ---
|
||||
lang_box = wx.StaticBox(panel, label=self.get_txt("settings_lang_group"))
|
||||
lang_sizer = wx.StaticBoxSizer(lang_box, wx.HORIZONTAL)
|
||||
|
||||
lang_sizer.Add(wx.StaticText(panel, label=self.get_txt("settings_language")), 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10)
|
||||
self.lang_choice = wx.Choice(panel, choices=["Dansk", "English"])
|
||||
self.lang_choice.SetSelection(0 if self.settings.get("language") == "da" else 1)
|
||||
lang_sizer.Add(self.lang_choice, 1, wx.EXPAND)
|
||||
|
||||
inner_vbox.Add(lang_sizer, 0, wx.EXPAND | wx.ALL, 10)
|
||||
|
||||
panel.SetSizer(inner_vbox)
|
||||
inner_vbox.Fit(panel)
|
||||
vbox.Add(panel, 1, wx.EXPAND | wx.ALL, 0)
|
||||
|
||||
# --- Buttons ---
|
||||
btn_hbox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
save_btn = wx.Button(self, label=self.get_txt("settings_save"), size=(150, 35))
|
||||
save_btn.SetBackgroundColour(wx.Colour(0, 120, 215)) # SharePoint Blue
|
||||
save_btn.SetForegroundColour(wx.WHITE)
|
||||
save_btn.Bind(wx.EVT_BUTTON, self.on_save)
|
||||
|
||||
cancel_btn = wx.Button(self, label=self.get_txt("settings_cancel"), size=(100, 35))
|
||||
cancel_btn.Bind(wx.EVT_BUTTON, self.on_cancel)
|
||||
|
||||
btn_hbox.Add(save_btn, 0, wx.RIGHT, 10)
|
||||
btn_hbox.Add(cancel_btn, 0)
|
||||
|
||||
vbox.Add(btn_hbox, 0, wx.ALIGN_RIGHT | wx.ALL, 15)
|
||||
|
||||
self.SetSizer(vbox)
|
||||
self.Layout()
|
||||
self.Centre()
|
||||
|
||||
def on_save(self, event):
|
||||
self.settings["client_id"] = self.client_id_ctrl.GetValue().strip()
|
||||
self.settings["tenant_id"] = self.tenant_id_ctrl.GetValue().strip()
|
||||
self.settings["temp_dir"] = self.temp_dir_picker.GetPath()
|
||||
self.settings["language"] = "da" if self.lang_choice.GetSelection() == 0 else "en"
|
||||
|
||||
if not self.settings["client_id"] or not self.settings["tenant_id"]:
|
||||
wx.MessageBox("Client ID og Tenant ID skal udfyldes.", "Fejl", wx.OK | wx.ICON_ERROR)
|
||||
return
|
||||
|
||||
self.EndModal(wx.ID_OK)
|
||||
|
||||
def on_cancel(self, event):
|
||||
self.EndModal(wx.ID_CANCEL)
|
||||
|
||||
class SharePointApp(wx.Frame):
|
||||
def __init__(self):
|
||||
self.lang = CURRENT_LANG
|
||||
@@ -283,6 +424,10 @@ class SharePointApp(wx.Frame):
|
||||
icon_path = os.path.join(RESOURCE_DIR, "icon.ico")
|
||||
if os.path.exists(icon_path):
|
||||
self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO))
|
||||
|
||||
# Start indlæsning (Check for konfiguration)
|
||||
if not is_configured(settings):
|
||||
wx.CallAfter(self.on_settings_clicked, None)
|
||||
def get_txt(self, key, **kwargs):
|
||||
text = STRINGS[self.lang].get(key, key)
|
||||
if kwargs:
|
||||
@@ -359,11 +504,10 @@ class SharePointApp(wx.Frame):
|
||||
self.login_btn.Bind(wx.EVT_BUTTON, self.login)
|
||||
nav_hbox.Add(self.login_btn, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
|
||||
|
||||
# SPROG VÆLGER
|
||||
self.lang_choice = wx.Choice(nav_panel, choices=["Dansk", "English"])
|
||||
self.lang_choice.SetSelection(0 if self.lang == "da" else 1)
|
||||
self.lang_choice.Bind(wx.EVT_CHOICE, self.on_language_changed)
|
||||
nav_hbox.Add(self.lang_choice, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
|
||||
# INDSTILLINGER KNAP
|
||||
self.settings_btn = wx.Button(nav_panel, label=self.get_txt("btn_settings"), size=(120, 30))
|
||||
self.settings_btn.Bind(wx.EVT_BUTTON, self.on_settings_clicked)
|
||||
nav_hbox.Add(self.settings_btn, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 10)
|
||||
|
||||
nav_panel.SetSizer(nav_hbox)
|
||||
vbox.Add(nav_panel, 0, wx.EXPAND | wx.ALL, 5)
|
||||
@@ -724,15 +868,52 @@ class SharePointApp(wx.Frame):
|
||||
self.PopupMenu(menu)
|
||||
menu.Destroy()
|
||||
|
||||
def on_language_changed(self, event):
|
||||
selection = self.lang_choice.GetSelection()
|
||||
self.lang = "da" if selection == 0 else "en"
|
||||
|
||||
# Gem til settings
|
||||
settings["language"] = self.lang
|
||||
save_settings(settings)
|
||||
|
||||
# Opdater UI tekster med det samme
|
||||
def on_settings_clicked(self, event):
|
||||
dlg = SettingsDialog(self, settings)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
global CLIENT_ID, TENANT_ID, AUTHORITY, TEMP_DIR, CURRENT_LANG
|
||||
new_settings = dlg.settings
|
||||
|
||||
# Check if IDs changed (need refresh)
|
||||
ids_changed = (new_settings["client_id"] != settings["client_id"] or
|
||||
new_settings["tenant_id"] != settings["tenant_id"])
|
||||
|
||||
# Save
|
||||
save_settings(new_settings)
|
||||
|
||||
# Update global variables for current session
|
||||
settings.update(new_settings)
|
||||
CLIENT_ID = settings["client_id"]
|
||||
TENANT_ID = settings["tenant_id"]
|
||||
AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}"
|
||||
TEMP_DIR = settings["temp_dir"]
|
||||
|
||||
# Apply language
|
||||
if CURRENT_LANG != new_settings["language"]:
|
||||
CURRENT_LANG = new_settings["language"]
|
||||
self.lang = CURRENT_LANG
|
||||
self.refresh_ui_texts()
|
||||
|
||||
# Update MSAL App if IDs changed
|
||||
if ids_changed:
|
||||
self.msal_app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY)
|
||||
self.access_token = None
|
||||
self.headers = {}
|
||||
self.login_btn.Enable()
|
||||
self.login_btn.SetLabel(self.get_txt("btn_login"))
|
||||
self.login_btn.SetBackgroundColour(wx.Colour(40, 167, 100))
|
||||
self.show_info(self.get_txt("msg_restart_required"), wx.ICON_INFORMATION)
|
||||
|
||||
# Ensure temp dir exists
|
||||
if not os.path.exists(TEMP_DIR):
|
||||
os.makedirs(TEMP_DIR)
|
||||
|
||||
self.show_info(self.get_txt("msg_settings_saved"))
|
||||
|
||||
dlg.Destroy()
|
||||
|
||||
def refresh_ui_texts(self):
|
||||
# Update UI texts for main frame and buttons
|
||||
self.SetTitle(self.get_txt("title"))
|
||||
self.back_btn.SetLabel(self.get_txt("btn_back"))
|
||||
self.home_btn.SetLabel(self.get_txt("btn_home"))
|
||||
@@ -741,19 +922,14 @@ class SharePointApp(wx.Frame):
|
||||
self.upload_folder_btn.SetLabel(self.get_txt("btn_upload_folder"))
|
||||
self.new_folder_btn.SetLabel(self.get_txt("btn_new_folder"))
|
||||
self.refresh_btn.SetLabel(self.get_txt("btn_refresh"))
|
||||
self.settings_btn.SetLabel(self.get_txt("btn_settings"))
|
||||
|
||||
if self.access_token:
|
||||
self.login_btn.SetLabel(self.get_txt("btn_logged_in"))
|
||||
else:
|
||||
self.login_btn.SetLabel(self.get_txt("btn_login"))
|
||||
|
||||
# Opdater kolonner i ListCtrl
|
||||
self.list_ctrl.SetColumnWidth(0, 450) # Refresh widths
|
||||
item = self.list_ctrl.GetColumn(0)
|
||||
self.list_ctrl.SetColumn(0, wx.ListItem()) # Reset column header logic could be complex in wx,
|
||||
# but the simplest is to just re-insert columns or set text
|
||||
|
||||
# Re-set headers (Fix: explicitly set image to -1 to avoid icons in headers)
|
||||
# Re-set headers for ListCtrl
|
||||
cols = [self.get_txt("col_name"), self.get_txt("col_type"), self.get_txt("col_size"), self.get_txt("col_modified")]
|
||||
for i, text in enumerate(cols):
|
||||
info = self.list_ctrl.GetColumn(i)
|
||||
@@ -762,7 +938,11 @@ class SharePointApp(wx.Frame):
|
||||
self.list_ctrl.SetColumn(i, info)
|
||||
|
||||
self.set_status(self.get_txt("status_ready"))
|
||||
self._refresh_current_view() # Gendanner list-item tekster (Mappe/Fil)
|
||||
self._refresh_current_view()
|
||||
|
||||
def on_language_changed(self, event):
|
||||
# Deprecated: use on_settings_clicked instead if you want or keep for quick switch
|
||||
pass # We'll just remove or redirect it later
|
||||
|
||||
def on_close_window(self, event):
|
||||
if self.active_edits:
|
||||
|
||||
Reference in New Issue
Block a user