From 1d3fe81ff79d09d36106cdcbc965323fd6f1a9d4 Mon Sep 17 00:00:00 2001 From: bbedward Date: Sat, 29 Nov 2025 10:00:05 -0500 Subject: [PATCH] network: big feature enrichment - Dedicated view in settings - VPN profile management - Ethernet disconnection - Turn prompts into floating windows --- core/internal/mocks/network/mock_Backend.go | 409 ++++ core/internal/server/loginctl/manager_test.go | 2 +- core/internal/server/loginctl/types_test.go | 25 +- .../server/network/agent_networkmanager.go | 199 +- core/internal/server/network/backend.go | 9 + .../network/backend_hybrid_iwd_networkd.go | 33 + .../network/backend_iwd_unimplemented.go | 32 + .../server/network/backend_networkd.go | 33 + .../network/backend_networkd_ethernet.go | 10 + .../server/network/backend_networkd_test.go | 22 + .../network/backend_networkd_unimplemented.go | 24 + .../server/network/backend_networkmanager.go | 71 +- .../backend_networkmanager_ethernet.go | 85 + .../backend_networkmanager_ethernet_test.go | 50 + .../network/backend_networkmanager_signals.go | 191 ++ .../network/backend_networkmanager_state.go | 45 +- .../network/backend_networkmanager_vpn.go | 807 +++++++- .../network/backend_networkmanager_wifi.go | 40 +- core/internal/server/network/handlers.go | 174 +- core/internal/server/network/manager.go | 58 + .../server/network/subscription_broker.go | 1 + core/internal/server/network/types.go | 124 +- core/internal/server/network/wired_test.go | 28 + core/internal/server/server.go | 9 +- quickshell/DMSShell.qml | 13 +- quickshell/Modals/PolkitAuthModal.qml | 487 ++--- .../Modals/Settings/SettingsContent.qml | 27 +- quickshell/Modals/Settings/SettingsModal.qml | 2 +- .../Modals/Settings/SettingsSidebar.qml | 55 +- quickshell/Modals/WifiPasswordModal.qml | 1107 +++++----- .../BuiltinPlugins/VpnWidget.qml | 232 +-- .../ControlCenter/ControlCenterPopout.qml | 9 +- .../ControlCenter/Details/NetworkDetail.qml | 29 +- .../Modules/DankBar/Popouts/VpnPopout.qml | 383 +--- quickshell/Modules/Settings/NetworkTab.qml | 1839 +++++++++++++++++ quickshell/Services/DMSNetworkService.qml | 17 +- quickshell/Services/IdleService.qml | 9 - quickshell/Services/NetworkService.qml | 9 +- quickshell/Services/PopoutService.qml | 141 +- quickshell/Services/VPNService.qml | 220 ++ quickshell/Widgets/DankPopout.qml | 7 +- quickshell/Widgets/VpnDetailContent.qml | 476 +++++ quickshell/translations/en.json | 1746 ++++++++++------ quickshell/translations/poexports/it.json | 360 +++- quickshell/translations/poexports/ja.json | 346 +++- quickshell/translations/poexports/pl.json | 346 +++- quickshell/translations/poexports/pt.json | 288 +++ quickshell/translations/poexports/tr.json | 346 +++- quickshell/translations/poexports/zh_CN.json | 346 +++- quickshell/translations/poexports/zh_TW.json | 288 +++ quickshell/translations/template.json | 698 ++++++- 51 files changed, 9807 insertions(+), 2500 deletions(-) create mode 100644 quickshell/Modules/Settings/NetworkTab.qml create mode 100644 quickshell/Services/VPNService.qml create mode 100644 quickshell/Widgets/VpnDetailContent.qml diff --git a/core/internal/mocks/network/mock_Backend.go b/core/internal/mocks/network/mock_Backend.go index 8f5a789a..a4db08b9 100644 --- a/core/internal/mocks/network/mock_Backend.go +++ b/core/internal/mocks/network/mock_Backend.go @@ -328,6 +328,52 @@ func (_c *MockBackend_ConnectWiFi_Call) RunAndReturn(run func(network.Connection return _c } +// DeleteVPN provides a mock function with given fields: uuidOrName +func (_m *MockBackend) DeleteVPN(uuidOrName string) error { + ret := _m.Called(uuidOrName) + + if len(ret) == 0 { + panic("no return value specified for DeleteVPN") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(uuidOrName) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBackend_DeleteVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteVPN' +type MockBackend_DeleteVPN_Call struct { + *mock.Call +} + +// DeleteVPN is a helper method to define mock.On call +// - uuidOrName string +func (_e *MockBackend_Expecter) DeleteVPN(uuidOrName interface{}) *MockBackend_DeleteVPN_Call { + return &MockBackend_DeleteVPN_Call{Call: _e.mock.On("DeleteVPN", uuidOrName)} +} + +func (_c *MockBackend_DeleteVPN_Call) Run(run func(uuidOrName string)) *MockBackend_DeleteVPN_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockBackend_DeleteVPN_Call) Return(_a0 error) *MockBackend_DeleteVPN_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBackend_DeleteVPN_Call) RunAndReturn(run func(string) error) *MockBackend_DeleteVPN_Call { + _c.Call.Return(run) + return _c +} + // DisconnectAllVPN provides a mock function with no fields func (_m *MockBackend) DisconnectAllVPN() error { ret := _m.Called() @@ -418,6 +464,52 @@ func (_c *MockBackend_DisconnectEthernet_Call) RunAndReturn(run func() error) *M return _c } +// DisconnectEthernetDevice provides a mock function with given fields: device +func (_m *MockBackend) DisconnectEthernetDevice(device string) error { + ret := _m.Called(device) + + if len(ret) == 0 { + panic("no return value specified for DisconnectEthernetDevice") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(device) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBackend_DisconnectEthernetDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectEthernetDevice' +type MockBackend_DisconnectEthernetDevice_Call struct { + *mock.Call +} + +// DisconnectEthernetDevice is a helper method to define mock.On call +// - device string +func (_e *MockBackend_Expecter) DisconnectEthernetDevice(device interface{}) *MockBackend_DisconnectEthernetDevice_Call { + return &MockBackend_DisconnectEthernetDevice_Call{Call: _e.mock.On("DisconnectEthernetDevice", device)} +} + +func (_c *MockBackend_DisconnectEthernetDevice_Call) Run(run func(device string)) *MockBackend_DisconnectEthernetDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockBackend_DisconnectEthernetDevice_Call) Return(_a0 error) *MockBackend_DisconnectEthernetDevice_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBackend_DisconnectEthernetDevice_Call) RunAndReturn(run func(string) error) *MockBackend_DisconnectEthernetDevice_Call { + _c.Call.Return(run) + return _c +} + // DisconnectVPN provides a mock function with given fields: uuidOrName func (_m *MockBackend) DisconnectVPN(uuidOrName string) error { ret := _m.Called(uuidOrName) @@ -658,6 +750,53 @@ func (_c *MockBackend_GetCurrentState_Call) RunAndReturn(run func() (*network.Ba return _c } +// GetEthernetDevices provides a mock function with no fields +func (_m *MockBackend) GetEthernetDevices() []network.EthernetDevice { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetEthernetDevices") + } + + var r0 []network.EthernetDevice + if rf, ok := ret.Get(0).(func() []network.EthernetDevice); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]network.EthernetDevice) + } + } + + return r0 +} + +// MockBackend_GetEthernetDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEthernetDevices' +type MockBackend_GetEthernetDevices_Call struct { + *mock.Call +} + +// GetEthernetDevices is a helper method to define mock.On call +func (_e *MockBackend_Expecter) GetEthernetDevices() *MockBackend_GetEthernetDevices_Call { + return &MockBackend_GetEthernetDevices_Call{Call: _e.mock.On("GetEthernetDevices")} +} + +func (_c *MockBackend_GetEthernetDevices_Call) Run(run func()) *MockBackend_GetEthernetDevices_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBackend_GetEthernetDevices_Call) Return(_a0 []network.EthernetDevice) *MockBackend_GetEthernetDevices_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBackend_GetEthernetDevices_Call) RunAndReturn(run func() []network.EthernetDevice) *MockBackend_GetEthernetDevices_Call { + _c.Call.Return(run) + return _c +} + // GetPromptBroker provides a mock function with no fields func (_m *MockBackend) GetPromptBroker() network.PromptBroker { ret := _m.Called() @@ -705,6 +844,64 @@ func (_c *MockBackend_GetPromptBroker_Call) RunAndReturn(run func() network.Prom return _c } +// GetVPNConfig provides a mock function with given fields: uuidOrName +func (_m *MockBackend) GetVPNConfig(uuidOrName string) (*network.VPNConfig, error) { + ret := _m.Called(uuidOrName) + + if len(ret) == 0 { + panic("no return value specified for GetVPNConfig") + } + + var r0 *network.VPNConfig + var r1 error + if rf, ok := ret.Get(0).(func(string) (*network.VPNConfig, error)); ok { + return rf(uuidOrName) + } + if rf, ok := ret.Get(0).(func(string) *network.VPNConfig); ok { + r0 = rf(uuidOrName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*network.VPNConfig) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(uuidOrName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBackend_GetVPNConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVPNConfig' +type MockBackend_GetVPNConfig_Call struct { + *mock.Call +} + +// GetVPNConfig is a helper method to define mock.On call +// - uuidOrName string +func (_e *MockBackend_Expecter) GetVPNConfig(uuidOrName interface{}) *MockBackend_GetVPNConfig_Call { + return &MockBackend_GetVPNConfig_Call{Call: _e.mock.On("GetVPNConfig", uuidOrName)} +} + +func (_c *MockBackend_GetVPNConfig_Call) Run(run func(uuidOrName string)) *MockBackend_GetVPNConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockBackend_GetVPNConfig_Call) Return(_a0 *network.VPNConfig, _a1 error) *MockBackend_GetVPNConfig_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBackend_GetVPNConfig_Call) RunAndReturn(run func(string) (*network.VPNConfig, error)) *MockBackend_GetVPNConfig_Call { + _c.Call.Return(run) + return _c +} + // GetWiFiDevices provides a mock function with no fields func (_m *MockBackend) GetWiFiDevices() []network.WiFiDevice { ret := _m.Called() @@ -980,6 +1177,65 @@ func (_c *MockBackend_GetWiredNetworkDetails_Call) RunAndReturn(run func(string) return _c } +// ImportVPN provides a mock function with given fields: filePath, name +func (_m *MockBackend) ImportVPN(filePath string, name string) (*network.VPNImportResult, error) { + ret := _m.Called(filePath, name) + + if len(ret) == 0 { + panic("no return value specified for ImportVPN") + } + + var r0 *network.VPNImportResult + var r1 error + if rf, ok := ret.Get(0).(func(string, string) (*network.VPNImportResult, error)); ok { + return rf(filePath, name) + } + if rf, ok := ret.Get(0).(func(string, string) *network.VPNImportResult); ok { + r0 = rf(filePath, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*network.VPNImportResult) + } + } + + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(filePath, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBackend_ImportVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ImportVPN' +type MockBackend_ImportVPN_Call struct { + *mock.Call +} + +// ImportVPN is a helper method to define mock.On call +// - filePath string +// - name string +func (_e *MockBackend_Expecter) ImportVPN(filePath interface{}, name interface{}) *MockBackend_ImportVPN_Call { + return &MockBackend_ImportVPN_Call{Call: _e.mock.On("ImportVPN", filePath, name)} +} + +func (_c *MockBackend_ImportVPN_Call) Run(run func(filePath string, name string)) *MockBackend_ImportVPN_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *MockBackend_ImportVPN_Call) Return(_a0 *network.VPNImportResult, _a1 error) *MockBackend_ImportVPN_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBackend_ImportVPN_Call) RunAndReturn(run func(string, string) (*network.VPNImportResult, error)) *MockBackend_ImportVPN_Call { + _c.Call.Return(run) + return _c +} + // Initialize provides a mock function with no fields func (_m *MockBackend) Initialize() error { ret := _m.Called() @@ -1082,6 +1338,63 @@ func (_c *MockBackend_ListActiveVPN_Call) RunAndReturn(run func() ([]network.VPN return _c } +// ListVPNPlugins provides a mock function with no fields +func (_m *MockBackend) ListVPNPlugins() ([]network.VPNPlugin, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ListVPNPlugins") + } + + var r0 []network.VPNPlugin + var r1 error + if rf, ok := ret.Get(0).(func() ([]network.VPNPlugin, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []network.VPNPlugin); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]network.VPNPlugin) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBackend_ListVPNPlugins_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListVPNPlugins' +type MockBackend_ListVPNPlugins_Call struct { + *mock.Call +} + +// ListVPNPlugins is a helper method to define mock.On call +func (_e *MockBackend_Expecter) ListVPNPlugins() *MockBackend_ListVPNPlugins_Call { + return &MockBackend_ListVPNPlugins_Call{Call: _e.mock.On("ListVPNPlugins")} +} + +func (_c *MockBackend_ListVPNPlugins_Call) Run(run func()) *MockBackend_ListVPNPlugins_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBackend_ListVPNPlugins_Call) Return(_a0 []network.VPNPlugin, _a1 error) *MockBackend_ListVPNPlugins_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBackend_ListVPNPlugins_Call) RunAndReturn(run func() ([]network.VPNPlugin, error)) *MockBackend_ListVPNPlugins_Call { + _c.Call.Return(run) + return _c +} + // ListVPNProfiles provides a mock function with no fields func (_m *MockBackend) ListVPNProfiles() ([]network.VPNProfile, error) { ret := _m.Called() @@ -1276,6 +1589,55 @@ func (_c *MockBackend_SetPromptBroker_Call) RunAndReturn(run func(network.Prompt return _c } +// SetVPNCredentials provides a mock function with given fields: uuid, username, password, save +func (_m *MockBackend) SetVPNCredentials(uuid string, username string, password string, save bool) error { + ret := _m.Called(uuid, username, password, save) + + if len(ret) == 0 { + panic("no return value specified for SetVPNCredentials") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, string, bool) error); ok { + r0 = rf(uuid, username, password, save) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBackend_SetVPNCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetVPNCredentials' +type MockBackend_SetVPNCredentials_Call struct { + *mock.Call +} + +// SetVPNCredentials is a helper method to define mock.On call +// - uuid string +// - username string +// - password string +// - save bool +func (_e *MockBackend_Expecter) SetVPNCredentials(uuid interface{}, username interface{}, password interface{}, save interface{}) *MockBackend_SetVPNCredentials_Call { + return &MockBackend_SetVPNCredentials_Call{Call: _e.mock.On("SetVPNCredentials", uuid, username, password, save)} +} + +func (_c *MockBackend_SetVPNCredentials_Call) Run(run func(uuid string, username string, password string, save bool)) *MockBackend_SetVPNCredentials_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string), args[2].(string), args[3].(bool)) + }) + return _c +} + +func (_c *MockBackend_SetVPNCredentials_Call) Return(_a0 error) *MockBackend_SetVPNCredentials_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBackend_SetVPNCredentials_Call) RunAndReturn(run func(string, string, string, bool) error) *MockBackend_SetVPNCredentials_Call { + _c.Call.Return(run) + return _c +} + // SetWiFiAutoconnect provides a mock function with given fields: ssid, autoconnect func (_m *MockBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { ret := _m.Called(ssid, autoconnect) @@ -1495,6 +1857,53 @@ func (_c *MockBackend_SubmitCredentials_Call) RunAndReturn(run func(string, map[ return _c } +// UpdateVPNConfig provides a mock function with given fields: uuid, updates +func (_m *MockBackend) UpdateVPNConfig(uuid string, updates map[string]interface{}) error { + ret := _m.Called(uuid, updates) + + if len(ret) == 0 { + panic("no return value specified for UpdateVPNConfig") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, map[string]interface{}) error); ok { + r0 = rf(uuid, updates) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBackend_UpdateVPNConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateVPNConfig' +type MockBackend_UpdateVPNConfig_Call struct { + *mock.Call +} + +// UpdateVPNConfig is a helper method to define mock.On call +// - uuid string +// - updates map[string]interface{} +func (_e *MockBackend_Expecter) UpdateVPNConfig(uuid interface{}, updates interface{}) *MockBackend_UpdateVPNConfig_Call { + return &MockBackend_UpdateVPNConfig_Call{Call: _e.mock.On("UpdateVPNConfig", uuid, updates)} +} + +func (_c *MockBackend_UpdateVPNConfig_Call) Run(run func(uuid string, updates map[string]interface{})) *MockBackend_UpdateVPNConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(map[string]interface{})) + }) + return _c +} + +func (_c *MockBackend_UpdateVPNConfig_Call) Return(_a0 error) *MockBackend_UpdateVPNConfig_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBackend_UpdateVPNConfig_Call) RunAndReturn(run func(string, map[string]interface{}) error) *MockBackend_UpdateVPNConfig_Call { + _c.Call.Return(run) + return _c +} + // NewMockBackend creates a new instance of MockBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewMockBackend(t interface { diff --git a/core/internal/server/loginctl/manager_test.go b/core/internal/server/loginctl/manager_test.go index f44c787c..148ee609 100644 --- a/core/internal/server/loginctl/manager_test.go +++ b/core/internal/server/loginctl/manager_test.go @@ -287,7 +287,7 @@ func TestNewManager(t *testing.T) { } else { assert.NotNil(t, manager) assert.NotNil(t, manager.state) - assert.NotNil(t, manager.subscribers) + assert.NotNil(t, &manager.subscribers) assert.NotNil(t, manager.stopChan) manager.Close() diff --git a/core/internal/server/loginctl/types_test.go b/core/internal/server/loginctl/types_test.go index d5063ea4..383300fb 100644 --- a/core/internal/server/loginctl/types_test.go +++ b/core/internal/server/loginctl/types_test.go @@ -17,25 +17,12 @@ func TestEventType_Constants(t *testing.T) { func TestSessionState_Struct(t *testing.T) { state := SessionState{ - SessionID: "1", - SessionPath: "/org/freedesktop/login1/session/_31", - Locked: false, - Active: true, - IdleHint: false, - IdleSinceHint: 0, - LockedHint: false, - SessionType: "wayland", - SessionClass: "user", - User: 1000, - UserName: "testuser", - RemoteHost: "", - Service: "gdm-password", - TTY: "tty2", - Display: ":1", - Remote: false, - Seat: "seat0", - VTNr: 2, - PreparingForSleep: false, + SessionID: "1", + Locked: false, + Active: true, + SessionType: "wayland", + User: 1000, + UserName: "testuser", } assert.Equal(t, "1", state.SessionID) diff --git a/core/internal/server/network/agent_networkmanager.go b/core/internal/server/network/agent_networkmanager.go index 9fde5e2a..597ccf2e 100644 --- a/core/internal/server/network/agent_networkmanager.go +++ b/core/internal/server/network/agent_networkmanager.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strconv" + "strings" "time" "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" @@ -176,8 +177,8 @@ func (a *SecretAgent) GetSecrets( return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) } - log.Infof("[SecretAgent] VPN with empty hints but we're connecting - prompting for password") - fields = []string{"password"} + fields = inferVPNFields(conn, vpnSvc) + log.Infof("[SecretAgent] VPN with empty hints but we're connecting - inferred fields: %v", fields) } else { log.Infof("[SecretAgent] VPN with empty hints - deferring to other agents for %s", vpnSvc) return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil) @@ -251,6 +252,35 @@ func (a *SecretAgent) GetSecrets( } } + if settingName == "vpn" && a.backend != nil { + a.backend.cachedVPNCredsMu.Lock() + cached := a.backend.cachedVPNCreds + if cached != nil && cached.ConnectionUUID == connUuid { + a.backend.cachedVPNCreds = nil + a.backend.cachedVPNCredsMu.Unlock() + + log.Infof("[SecretAgent] Using cached password from pre-activation prompt") + + out := nmSettingMap{} + sec := nmVariantMap{} + sec["password"] = dbus.MakeVariant(cached.Password) + out[settingName] = sec + + if cached.SavePassword { + a.backend.pendingVPNSaveMu.Lock() + a.backend.pendingVPNSave = &pendingVPNCredentials{ + ConnectionPath: string(path), + Password: cached.Password, + SavePassword: true, + } + a.backend.pendingVPNSaveMu.Unlock() + } + + return out, nil + } + a.backend.cachedVPNCredsMu.Unlock() + } + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() @@ -261,6 +291,7 @@ func (a *SecretAgent) GetSecrets( VpnService: vpnSvc, SettingName: settingName, Fields: fields, + FieldsInfo: buildFieldsInfo(settingName, fields, vpnSvc), Hints: hints, Reason: reason, ConnectionId: connId, @@ -283,6 +314,7 @@ func (a *SecretAgent) GetSecrets( wasConnecting := a.backend.state.IsConnecting wasConnectingVPN := a.backend.state.IsConnectingVPN cancelledSSID := a.backend.state.ConnectingSSID + cancelledVPNUUID := a.backend.state.ConnectingVPNUUID if wasConnecting || wasConnectingVPN { log.Infof("[SecretAgent] Clearing connecting state due to cancelled prompt") a.backend.state.IsConnecting = false @@ -301,6 +333,14 @@ func (a *SecretAgent) GetSecrets( } } + // If this was a VPN connection that was cancelled, deactivate it + if wasConnectingVPN && cancelledVPNUUID != "" { + log.Infof("[SecretAgent] Deactivating cancelled VPN connection: %s", cancelledVPNUUID) + if err := a.backend.DisconnectVPN(cancelledVPNUUID); err != nil { + log.Warnf("[SecretAgent] Failed to deactivate cancelled VPN: %v", err) + } + } + if (wasConnecting || wasConnectingVPN) && a.backend.onStateChange != nil { a.backend.onStateChange() } @@ -320,7 +360,12 @@ func (a *SecretAgent) GetSecrets( out := nmSettingMap{} sec := nmVariantMap{} + + var vpnUsername string for k, v := range reply.Secrets { + if settingName == "vpn" && k == "username" { + vpnUsername = v + } sec[k] = dbus.MakeVariant(v) } out[settingName] = sec @@ -332,13 +377,22 @@ func (a *SecretAgent) GetSecrets( log.Infof("[SecretAgent] Returning VPN secrets with %d fields for %s", len(sec), vpnSvc) } - // If save=true, persist secrets in background after returning to NetworkManager - // This MUST happen after we return secrets, in a goroutine - if reply.Save { + if settingName == "vpn" && a.backend != nil && (vpnUsername != "" || reply.Save) { + pw, _ := reply.Secrets["password"] + a.backend.pendingVPNSaveMu.Lock() + a.backend.pendingVPNSave = &pendingVPNCredentials{ + ConnectionPath: string(path), + Username: vpnUsername, + Password: pw, + SavePassword: reply.Save, + } + a.backend.pendingVPNSaveMu.Unlock() + log.Infof("[SecretAgent] Queued credentials persist for after connection succeeds") + } else if reply.Save && settingName != "vpn" { + // Non-VPN save logic go func() { log.Infof("[SecretAgent] Persisting secrets with Update2: path=%s, setting=%s", path, settingName) - // Get existing connection settings connObj := a.conn.Object("org.freedesktop.NetworkManager", path) var existingSettings map[string]map[string]dbus.Variant if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil { @@ -346,49 +400,12 @@ func (a *SecretAgent) GetSecrets( return } - // Build minimal settings with ONLY the section we're updating - // This avoids D-Bus type serialization issues with complex types like IPv6 addresses settings := make(map[string]map[string]dbus.Variant) - - // Copy connection section (required for Update2) if connSection, ok := existingSettings["connection"]; ok { settings["connection"] = connSection } - // Update settings based on type switch settingName { - case "vpn": - vpn, ok := existingSettings["vpn"] - if !ok { - vpn = make(map[string]dbus.Variant) - } - - var data map[string]string - if dataVariant, ok := vpn["data"]; ok { - if dm, ok := dataVariant.Value().(map[string]string); ok { - data = make(map[string]string) - for k, v := range dm { - data[k] = v - } - } else { - data = make(map[string]string) - } - } else { - data = make(map[string]string) - } - - data["password-flags"] = "0" - vpn["data"] = dbus.MakeVariant(data) - - secs := make(map[string]string) - for k, v := range reply.Secrets { - secs[k] = v - } - vpn["secrets"] = dbus.MakeVariant(secs) - settings["vpn"] = vpn - - log.Infof("[SecretAgent] Updated VPN settings: password-flags=0, secrets with %d fields", len(secs)) - case "802-11-wireless-security": wifiSec, ok := existingSettings["802-11-wireless-security"] if !ok { @@ -514,6 +531,102 @@ func fieldsNeeded(setting string, hints []string) []string { } } +func buildFieldsInfo(setting string, fields []string, vpnService string) []FieldInfo { + result := make([]FieldInfo, 0, len(fields)) + for _, f := range fields { + info := FieldInfo{Name: f} + switch setting { + case "802-11-wireless-security": + info.Label = "Password" + info.IsSecret = true + case "802-1x": + switch f { + case "identity": + info.Label = "Username" + info.IsSecret = false + case "password": + info.Label = "Password" + info.IsSecret = true + default: + info.Label = f + info.IsSecret = true + } + case "vpn": + info.Label, info.IsSecret = vpnFieldMeta(f, vpnService) + default: + info.Label = f + info.IsSecret = true + } + result = append(result, info) + } + return result +} + +func inferVPNFields(conn map[string]nmVariantMap, vpnService string) []string { + fields := []string{"password"} + + vpnSettings, ok := conn["vpn"] + if !ok { + return fields + } + + dataVariant, ok := vpnSettings["data"] + if !ok { + return fields + } + + dataMap, ok := dataVariant.Value().(map[string]string) + if !ok { + return fields + } + + connType := dataMap["connection-type"] + + switch { + case strings.Contains(vpnService, "openvpn"): + if connType == "password" || connType == "password-tls" { + if dataMap["username"] == "" { + fields = []string{"username", "password"} + } + } + case strings.Contains(vpnService, "vpnc"), strings.Contains(vpnService, "l2tp"), + strings.Contains(vpnService, "pptp"), strings.Contains(vpnService, "openconnect"): + if dataMap["username"] == "" { + fields = []string{"username", "password"} + } + } + + return fields +} + +func vpnFieldMeta(field, vpnService string) (label string, isSecret bool) { + switch field { + case "password": + return "Password", true + case "Xauth password": + return "IPSec Password", true + case "IPSec secret": + return "IPSec Pre-Shared Key", true + case "cert-pass": + return "Certificate Password", true + case "http-proxy-password": + return "HTTP Proxy Password", true + case "username": + return "Username", false + case "Xauth username": + return "IPSec Username", false + case "proxy-password": + return "Proxy Password", true + case "private-key-password": + return "Private Key Password", true + } + if strings.HasSuffix(field, "password") || strings.HasSuffix(field, "secret") || + strings.HasSuffix(field, "pass") || strings.HasSuffix(field, "psk") { + return strings.Title(strings.ReplaceAll(field, "-", " ")), true + } + return strings.Title(strings.ReplaceAll(field, "-", " ")), false +} + func readVPNPasswordFlags(conn map[string]nmVariantMap, settingName string) uint32 { if settingName != "vpn" { return 0xFFFF diff --git a/core/internal/server/network/backend.go b/core/internal/server/network/backend.go index f5e88df9..59bb3b3a 100644 --- a/core/internal/server/network/backend.go +++ b/core/internal/server/network/backend.go @@ -18,10 +18,12 @@ type Backend interface { ForgetWiFiNetwork(ssid string) error SetWiFiAutoconnect(ssid string, autoconnect bool) error + GetEthernetDevices() []EthernetDevice GetWiredConnections() ([]WiredConnection, error) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) ConnectEthernet() error DisconnectEthernet() error + DisconnectEthernetDevice(device string) error ActivateWiredConnection(uuid string) error ListVPNProfiles() ([]VPNProfile, error) @@ -30,6 +32,12 @@ type Backend interface { DisconnectVPN(uuidOrName string) error DisconnectAllVPN() error ClearVPNCredentials(uuidOrName string) error + ListVPNPlugins() ([]VPNPlugin, error) + ImportVPN(filePath string, name string) (*VPNImportResult, error) + GetVPNConfig(uuidOrName string) (*VPNConfig, error) + UpdateVPNConfig(uuid string, updates map[string]interface{}) error + SetVPNCredentials(uuid string, username string, password string, save bool) error + DeleteVPN(uuidOrName string) error GetCurrentState() (*BackendState, error) @@ -49,6 +57,7 @@ type BackendState struct { EthernetDevice string EthernetConnected bool EthernetConnectionUuid string + EthernetDevices []EthernetDevice WiFiIP string WiFiDevice string WiFiConnected bool diff --git a/core/internal/server/network/backend_hybrid_iwd_networkd.go b/core/internal/server/network/backend_hybrid_iwd_networkd.go index 1942d13e..cd03640c 100644 --- a/core/internal/server/network/backend_hybrid_iwd_networkd.go +++ b/core/internal/server/network/backend_hybrid_iwd_networkd.go @@ -84,6 +84,7 @@ func (b *HybridIwdNetworkdBackend) GetCurrentState() (*BackendState, error) { merged.EthernetDevice = ls.EthernetDevice merged.EthernetConnectionUuid = ls.EthernetConnectionUuid merged.WiredConnections = ls.WiredConnections + merged.EthernetDevices = ls.EthernetDevices if ls.EthernetConnected && ls.EthernetIP != "" { merged.NetworkStatus = StatusEthernet @@ -149,6 +150,14 @@ func (b *HybridIwdNetworkdBackend) DisconnectEthernet() error { return b.l3.DisconnectEthernet() } +func (b *HybridIwdNetworkdBackend) DisconnectEthernetDevice(device string) error { + return b.l3.DisconnectEthernetDevice(device) +} + +func (b *HybridIwdNetworkdBackend) GetEthernetDevices() []EthernetDevice { + return b.l3.GetEthernetDevices() +} + func (b *HybridIwdNetworkdBackend) ActivateWiredConnection(uuid string) error { return b.l3.ActivateWiredConnection(uuid) } @@ -177,6 +186,26 @@ func (b *HybridIwdNetworkdBackend) ClearVPNCredentials(uuidOrName string) error return fmt.Errorf("VPN not supported in hybrid mode") } +func (b *HybridIwdNetworkdBackend) ListVPNPlugins() ([]VPNPlugin, error) { + return []VPNPlugin{}, nil +} + +func (b *HybridIwdNetworkdBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { + return nil, fmt.Errorf("VPN not supported in hybrid mode") +} + +func (b *HybridIwdNetworkdBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { + return nil, fmt.Errorf("VPN not supported in hybrid mode") +} + +func (b *HybridIwdNetworkdBackend) UpdateVPNConfig(uuid string, updates map[string]interface{}) error { + return fmt.Errorf("VPN not supported in hybrid mode") +} + +func (b *HybridIwdNetworkdBackend) DeleteVPN(uuidOrName string) error { + return fmt.Errorf("VPN not supported in hybrid mode") +} + func (b *HybridIwdNetworkdBackend) GetPromptBroker() PromptBroker { return b.wifi.GetPromptBroker() } @@ -208,3 +237,7 @@ func (b *HybridIwdNetworkdBackend) DisconnectWiFiDevice(device string) error { func (b *HybridIwdNetworkdBackend) GetWiFiDevices() []WiFiDevice { return b.wifi.GetWiFiDevices() } + +func (b *HybridIwdNetworkdBackend) SetVPNCredentials(uuid, username, password string, save bool) error { + return fmt.Errorf("VPN not supported in hybrid mode") +} diff --git a/core/internal/server/network/backend_iwd_unimplemented.go b/core/internal/server/network/backend_iwd_unimplemented.go index 50d5c2bc..94003220 100644 --- a/core/internal/server/network/backend_iwd_unimplemented.go +++ b/core/internal/server/network/backend_iwd_unimplemented.go @@ -18,6 +18,14 @@ func (b *IWDBackend) DisconnectEthernet() error { return fmt.Errorf("wired connections not supported by iwd") } +func (b *IWDBackend) DisconnectEthernetDevice(device string) error { + return fmt.Errorf("wired connections not supported by iwd") +} + +func (b *IWDBackend) GetEthernetDevices() []EthernetDevice { + return []EthernetDevice{} +} + func (b *IWDBackend) ActivateWiredConnection(uuid string) error { return fmt.Errorf("wired connections not supported by iwd") } @@ -46,6 +54,30 @@ func (b *IWDBackend) ClearVPNCredentials(uuidOrName string) error { return fmt.Errorf("VPN not supported by iwd backend") } +func (b *IWDBackend) ListVPNPlugins() ([]VPNPlugin, error) { + return nil, fmt.Errorf("VPN not supported by iwd backend") +} + +func (b *IWDBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { + return nil, fmt.Errorf("VPN not supported by iwd backend") +} + +func (b *IWDBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { + return nil, fmt.Errorf("VPN not supported by iwd backend") +} + +func (b *IWDBackend) UpdateVPNConfig(uuid string, updates map[string]interface{}) error { + return fmt.Errorf("VPN not supported by iwd backend") +} + +func (b *IWDBackend) DeleteVPN(uuidOrName string) error { + return fmt.Errorf("VPN not supported by iwd backend") +} + +func (b *IWDBackend) SetVPNCredentials(uuid, username, password string, save bool) error { + return fmt.Errorf("VPN not supported by iwd backend") +} + func (b *IWDBackend) ScanWiFiDevice(device string) error { return b.ScanWiFi() } diff --git a/core/internal/server/network/backend_networkd.go b/core/internal/server/network/backend_networkd.go index 2f30e044..802cbf02 100644 --- a/core/internal/server/network/backend_networkd.go +++ b/core/internal/server/network/backend_networkd.go @@ -138,6 +138,7 @@ func (b *SystemdNetworkdBackend) updateState() error { } var wiredConns []WiredConnection + var ethernetDevices []EthernetDevice for name, link := range b.links { if b.isVirtualInterface(name) || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") { continue @@ -151,6 +152,37 @@ func (b *SystemdNetworkdBackend) updateState() error { Type: "ethernet", IsActive: active, }) + + var ip string + var hwAddr string + if iface, err := net.InterfaceByName(name); err == nil { + hwAddr = iface.HardwareAddr.String() + if addrs := b.getAddresses(name); len(addrs) > 0 { + ip = addrs[0] + } + } + + stateStr := "disconnected" + switch link.opState { + case "routable": + stateStr = "routable" + case "carrier": + stateStr = "carrier" + case "degraded": + stateStr = "degraded" + case "no-carrier": + stateStr = "no-carrier" + case "off": + stateStr = "off" + } + + ethernetDevices = append(ethernetDevices, EthernetDevice{ + Name: name, + HwAddress: hwAddr, + State: stateStr, + Connected: active, + IP: ip, + }) } b.stateMutex.Lock() @@ -162,6 +194,7 @@ func (b *SystemdNetworkdBackend) updateState() error { b.state.WiFiConnected = false b.state.WiFiIP = "" b.state.WiredConnections = wiredConns + b.state.EthernetDevices = ethernetDevices if wiredIface != nil { b.state.EthernetDevice = wiredIface.name diff --git a/core/internal/server/network/backend_networkd_ethernet.go b/core/internal/server/network/backend_networkd_ethernet.go index d0c9b948..8f9b225f 100644 --- a/core/internal/server/network/backend_networkd_ethernet.go +++ b/core/internal/server/network/backend_networkd_ethernet.go @@ -108,3 +108,13 @@ func (b *SystemdNetworkdBackend) ActivateWiredConnection(id string) error { linkObj := b.conn.Object(networkdBusName, link.path) return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err } + +func (b *SystemdNetworkdBackend) GetEthernetDevices() []EthernetDevice { + b.stateMutex.RLock() + defer b.stateMutex.RUnlock() + return append([]EthernetDevice(nil), b.state.EthernetDevices...) +} + +func (b *SystemdNetworkdBackend) DisconnectEthernetDevice(device string) error { + return fmt.Errorf("not supported by networkd backend") +} diff --git a/core/internal/server/network/backend_networkd_test.go b/core/internal/server/network/backend_networkd_test.go index 383c775c..18c5281c 100644 --- a/core/internal/server/network/backend_networkd_test.go +++ b/core/internal/server/network/backend_networkd_test.go @@ -123,3 +123,25 @@ func TestSystemdNetworkdBackend_DisconnectEthernet(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "not supported") } + +func TestSystemdNetworkdBackend_GetEthernetDevices(t *testing.T) { + backend, _ := NewSystemdNetworkdBackend() + + backend.state.EthernetDevices = []EthernetDevice{ + {Name: "enp0s3", State: "routable", Connected: true}, + {Name: "enp0s8", State: "no-carrier", Connected: false}, + } + + devices := backend.GetEthernetDevices() + assert.Len(t, devices, 2) + assert.Equal(t, "enp0s3", devices[0].Name) + assert.True(t, devices[0].Connected) +} + +func TestSystemdNetworkdBackend_DisconnectEthernetDevice(t *testing.T) { + backend, _ := NewSystemdNetworkdBackend() + + err := backend.DisconnectEthernetDevice("enp0s3") + assert.Error(t, err) + assert.Contains(t, err.Error(), "not supported") +} diff --git a/core/internal/server/network/backend_networkd_unimplemented.go b/core/internal/server/network/backend_networkd_unimplemented.go index dbbf574e..1b3c267a 100644 --- a/core/internal/server/network/backend_networkd_unimplemented.go +++ b/core/internal/server/network/backend_networkd_unimplemented.go @@ -54,6 +54,30 @@ func (b *SystemdNetworkdBackend) ClearVPNCredentials(uuidOrName string) error { return fmt.Errorf("VPN not supported by networkd backend") } +func (b *SystemdNetworkdBackend) ListVPNPlugins() ([]VPNPlugin, error) { + return []VPNPlugin{}, nil +} + +func (b *SystemdNetworkdBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { + return nil, fmt.Errorf("VPN not supported by networkd backend") +} + +func (b *SystemdNetworkdBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { + return nil, fmt.Errorf("VPN not supported by networkd backend") +} + +func (b *SystemdNetworkdBackend) UpdateVPNConfig(uuid string, updates map[string]interface{}) error { + return fmt.Errorf("VPN not supported by networkd backend") +} + +func (b *SystemdNetworkdBackend) DeleteVPN(uuidOrName string) error { + return fmt.Errorf("VPN not supported by networkd backend") +} + +func (b *SystemdNetworkdBackend) SetVPNCredentials(uuid, username, password string, save bool) error { + return fmt.Errorf("VPN not supported by networkd backend") +} + func (b *SystemdNetworkdBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error { return fmt.Errorf("WiFi autoconnect not supported by networkd backend") } diff --git a/core/internal/server/network/backend_networkmanager.go b/core/internal/server/network/backend_networkmanager.go index 53f373d0..b5f5fb91 100644 --- a/core/internal/server/network/backend_networkmanager.go +++ b/core/internal/server/network/backend_networkmanager.go @@ -37,13 +37,21 @@ type wifiDeviceInfo struct { hwAddress string } +type ethernetDeviceInfo struct { + device gonetworkmanager.Device + wired gonetworkmanager.DeviceWired + name string + hwAddress string +} + type NetworkManagerBackend struct { - nmConn interface{} - ethernetDevice interface{} - wifiDevice interface{} - settings interface{} - wifiDev interface{} - wifiDevices map[string]*wifiDeviceInfo + nmConn interface{} + ethernetDevice interface{} + ethernetDevices map[string]*ethernetDeviceInfo + wifiDevice interface{} + settings interface{} + wifiDev interface{} + wifiDevices map[string]*wifiDeviceInfo dbusConn *dbus.Conn signals chan *dbus.Signal @@ -60,9 +68,27 @@ type NetworkManagerBackend struct { lastFailedTime int64 failedMutex sync.RWMutex + pendingVPNSave *pendingVPNCredentials + pendingVPNSaveMu sync.Mutex + cachedVPNCreds *cachedVPNCredentials + cachedVPNCredsMu sync.Mutex + onStateChange func() } +type pendingVPNCredentials struct { + ConnectionPath string + Username string + Password string + SavePassword bool +} + +type cachedVPNCredentials struct { + ConnectionUUID string + Password string + SavePassword bool +} + func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*NetworkManagerBackend, error) { var nm gonetworkmanager.NetworkManager var err error @@ -79,9 +105,10 @@ func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*Netwo } backend := &NetworkManagerBackend{ - nmConn: nm, - stopChan: make(chan struct{}), - wifiDevices: make(map[string]*wifiDeviceInfo), + nmConn: nm, + stopChan: make(chan struct{}), + ethernetDevices: make(map[string]*ethernetDeviceInfo), + wifiDevices: make(map[string]*wifiDeviceInfo), state: &BackendState{ Backend: "networkmanager", }, @@ -113,11 +140,30 @@ func (b *NetworkManagerBackend) Initialize() error { if managed, _ := dev.GetPropertyManaged(); !managed { continue } - b.ethernetDevice = dev + iface, err := dev.GetPropertyInterface() + if err != nil { + continue + } + w, err := gonetworkmanager.NewDeviceWired(dev.GetPath()) + if err != nil { + continue + } + hwAddr, _ := w.GetPropertyHwAddress() + + b.ethernetDevices[iface] = ðernetDeviceInfo{ + device: dev, + wired: w, + name: iface, + hwAddress: hwAddr, + } + + if b.ethernetDevice == nil { + b.ethernetDevice = dev + } if err := b.updateEthernetState(); err != nil { continue } - _, err := b.listEthernetConnections() + _, err = b.listEthernetConnections() if err != nil { return fmt.Errorf("failed to get wired configurations: %w", err) } @@ -165,6 +211,8 @@ func (b *NetworkManagerBackend) Initialize() error { b.updateAllWiFiDevices() } + b.updateAllEthernetDevices() + if err := b.updatePrimaryConnection(); err != nil { return err } @@ -197,6 +245,7 @@ func (b *NetworkManagerBackend) GetCurrentState() (*BackendState, error) { state.WiFiNetworks = append([]WiFiNetwork(nil), b.state.WiFiNetworks...) state.WiFiDevices = append([]WiFiDevice(nil), b.state.WiFiDevices...) state.WiredConnections = append([]WiredConnection(nil), b.state.WiredConnections...) + state.EthernetDevices = append([]EthernetDevice(nil), b.state.EthernetDevices...) state.VPNProfiles = append([]VPNProfile(nil), b.state.VPNProfiles...) state.VPNActive = append([]VPNActive(nil), b.state.VPNActive...) diff --git a/core/internal/server/network/backend_networkmanager_ethernet.go b/core/internal/server/network/backend_networkmanager_ethernet.go index 4803e9a9..83a530a9 100644 --- a/core/internal/server/network/backend_networkmanager_ethernet.go +++ b/core/internal/server/network/backend_networkmanager_ethernet.go @@ -315,3 +315,88 @@ func (b *NetworkManagerBackend) listEthernetConnections() ([]WiredConnection, er return wiredConfigs, nil } + +func (b *NetworkManagerBackend) GetEthernetDevices() []EthernetDevice { + b.stateMutex.RLock() + defer b.stateMutex.RUnlock() + return append([]EthernetDevice(nil), b.state.EthernetDevices...) +} + +func (b *NetworkManagerBackend) DisconnectEthernetDevice(device string) error { + info, ok := b.ethernetDevices[device] + if !ok { + return fmt.Errorf("ethernet device %s not found", device) + } + + if err := info.device.Disconnect(); err != nil { + return fmt.Errorf("failed to disconnect %s: %w", device, err) + } + + b.updateAllEthernetDevices() + b.updateEthernetState() + b.listEthernetConnections() + b.updatePrimaryConnection() + + if b.onStateChange != nil { + b.onStateChange() + } + + return nil +} + +func (b *NetworkManagerBackend) updateAllEthernetDevices() { + devices := make([]EthernetDevice, 0, len(b.ethernetDevices)) + + for name, info := range b.ethernetDevices { + state, _ := info.device.GetPropertyState() + connected := state == gonetworkmanager.NmDeviceStateActivated + driver, _ := info.device.GetPropertyDriver() + + var ip string + var speed uint32 = 0 + if connected { + ip = b.getDeviceIP(info.device) + } + if info.wired != nil { + speed, _ = info.wired.GetPropertySpeed() + } + + stateStr := "disconnected" + switch state { + case gonetworkmanager.NmDeviceStateActivated: + stateStr = "activated" + case gonetworkmanager.NmDeviceStatePrepare: + stateStr = "preparing" + case gonetworkmanager.NmDeviceStateConfig: + stateStr = "configuring" + case gonetworkmanager.NmDeviceStateIpConfig: + stateStr = "ip-config" + case gonetworkmanager.NmDeviceStateIpCheck: + stateStr = "ip-check" + case gonetworkmanager.NmDeviceStateSecondaries: + stateStr = "secondaries" + case gonetworkmanager.NmDeviceStateDeactivating: + stateStr = "deactivating" + case gonetworkmanager.NmDeviceStateFailed: + stateStr = "failed" + case gonetworkmanager.NmDeviceStateUnavailable: + stateStr = "unavailable" + case gonetworkmanager.NmDeviceStateUnmanaged: + stateStr = "unmanaged" + } + + devices = append(devices, EthernetDevice{ + Name: name, + HwAddress: info.hwAddress, + State: stateStr, + Connected: connected, + IP: ip, + Speed: speed, + Driver: driver, + }) + } + + b.stateMutex.Lock() + b.state.EthernetDevices = devices + b.stateMutex.Unlock() +} diff --git a/core/internal/server/network/backend_networkmanager_ethernet_test.go b/core/internal/server/network/backend_networkmanager_ethernet_test.go index da6df566..09019133 100644 --- a/core/internal/server/network/backend_networkmanager_ethernet_test.go +++ b/core/internal/server/network/backend_networkmanager_ethernet_test.go @@ -82,3 +82,53 @@ func TestNetworkManagerBackend_ListEthernetConnections_NoDevice(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "no ethernet device available") } + +func TestNetworkManagerBackend_GetEthernetDevices_Empty(t *testing.T) { + mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) + + backend, err := NewNetworkManagerBackend(mockNM) + assert.NoError(t, err) + + devices := backend.GetEthernetDevices() + assert.Empty(t, devices) +} + +func TestNetworkManagerBackend_GetEthernetDevices_WithState(t *testing.T) { + mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) + + backend, err := NewNetworkManagerBackend(mockNM) + assert.NoError(t, err) + + backend.state.EthernetDevices = []EthernetDevice{ + {Name: "enp0s3", HwAddress: "00:11:22:33:44:55", State: "activated", Connected: true, IP: "192.168.1.100"}, + {Name: "enp0s8", HwAddress: "00:11:22:33:44:66", State: "disconnected", Connected: false}, + } + + devices := backend.GetEthernetDevices() + assert.Len(t, devices, 2) + assert.Equal(t, "enp0s3", devices[0].Name) + assert.True(t, devices[0].Connected) + assert.Equal(t, "enp0s8", devices[1].Name) + assert.False(t, devices[1].Connected) +} + +func TestNetworkManagerBackend_DisconnectEthernetDevice_NotFound(t *testing.T) { + mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) + + backend, err := NewNetworkManagerBackend(mockNM) + assert.NoError(t, err) + + err = backend.DisconnectEthernetDevice("nonexistent") + assert.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func TestNetworkManagerBackend_UpdateAllEthernetDevices_Empty(t *testing.T) { + mockNM := mock_gonetworkmanager.NewMockNetworkManager(t) + + backend, err := NewNetworkManagerBackend(mockNM) + assert.NoError(t, err) + + backend.updateAllEthernetDevices() + assert.Empty(t, backend.state.EthernetDevices) +} diff --git a/core/internal/server/network/backend_networkmanager_signals.go b/core/internal/server/network/backend_networkmanager_signals.go index 153a9d83..2a0a158c 100644 --- a/core/internal/server/network/backend_networkmanager_signals.go +++ b/core/internal/server/network/backend_networkmanager_signals.go @@ -61,6 +61,26 @@ func (b *NetworkManagerBackend) startSignalPump() error { return err } + if err := conn.AddMatchSignal( + dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), + dbus.WithMatchInterface(dbusNMInterface), + dbus.WithMatchMember("DeviceAdded"), + ); err != nil { + conn.RemoveSignal(signals) + conn.Close() + return err + } + + if err := conn.AddMatchSignal( + dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)), + dbus.WithMatchInterface(dbusNMInterface), + dbus.WithMatchMember("DeviceRemoved"), + ); err != nil { + conn.RemoveSignal(signals) + conn.Close() + return err + } + if b.wifiDevice != nil { dev := b.wifiDevice.(gonetworkmanager.Device) if err := conn.AddMatchSignal( @@ -175,6 +195,24 @@ func (b *NetworkManagerBackend) handleDBusSignal(sig *dbus.Signal) { return } + if sig.Name == "org.freedesktop.NetworkManager.DeviceAdded" { + if len(sig.Body) >= 1 { + if devicePath, ok := sig.Body[0].(dbus.ObjectPath); ok { + b.handleDeviceAdded(devicePath) + } + } + return + } + + if sig.Name == "org.freedesktop.NetworkManager.DeviceRemoved" { + if len(sig.Body) >= 1 { + if devicePath, ok := sig.Body[0].(dbus.ObjectPath); ok { + b.handleDeviceRemoved(devicePath) + } + } + return + } + if len(sig.Body) < 2 { return } @@ -319,3 +357,156 @@ func (b *NetworkManagerBackend) handleAccessPointChange(changes map[string]dbus. } } } + +func (b *NetworkManagerBackend) handleDeviceAdded(devicePath dbus.ObjectPath) { + dev, err := gonetworkmanager.NewDevice(devicePath) + if err != nil { + return + } + + devType, err := dev.GetPropertyDeviceType() + if err != nil { + return + } + + managed, _ := dev.GetPropertyManaged() + if !managed { + return + } + + iface, err := dev.GetPropertyInterface() + if err != nil { + return + } + + switch devType { + case gonetworkmanager.NmDeviceTypeEthernet: + w, err := gonetworkmanager.NewDeviceWired(devicePath) + if err != nil { + return + } + hwAddr, _ := w.GetPropertyHwAddress() + + b.ethernetDevices[iface] = ðernetDeviceInfo{ + device: dev, + wired: w, + name: iface, + hwAddress: hwAddr, + } + + if b.ethernetDevice == nil { + b.ethernetDevice = dev + } + + if b.dbusConn != nil { + b.dbusConn.AddMatchSignal( + dbus.WithMatchObjectPath(devicePath), + dbus.WithMatchInterface(dbusPropsInterface), + dbus.WithMatchMember("PropertiesChanged"), + ) + } + + b.updateAllEthernetDevices() + b.updateEthernetState() + b.listEthernetConnections() + b.updatePrimaryConnection() + + case gonetworkmanager.NmDeviceTypeWifi: + w, err := gonetworkmanager.NewDeviceWireless(devicePath) + if err != nil { + return + } + hwAddr, _ := w.GetPropertyHwAddress() + + b.wifiDevices[iface] = &wifiDeviceInfo{ + device: dev, + wireless: w, + name: iface, + hwAddress: hwAddr, + } + + if b.wifiDevice == nil { + b.wifiDevice = dev + b.wifiDev = w + } + + if b.dbusConn != nil { + b.dbusConn.AddMatchSignal( + dbus.WithMatchObjectPath(devicePath), + dbus.WithMatchInterface(dbusPropsInterface), + dbus.WithMatchMember("PropertiesChanged"), + ) + } + + b.updateAllWiFiDevices() + b.updateWiFiState() + } + + if b.onStateChange != nil { + b.onStateChange() + } +} + +func (b *NetworkManagerBackend) handleDeviceRemoved(devicePath dbus.ObjectPath) { + if b.dbusConn != nil { + b.dbusConn.RemoveMatchSignal( + dbus.WithMatchObjectPath(devicePath), + dbus.WithMatchInterface(dbusPropsInterface), + dbus.WithMatchMember("PropertiesChanged"), + ) + } + + for iface, info := range b.ethernetDevices { + if info.device.GetPath() == devicePath { + delete(b.ethernetDevices, iface) + + if b.ethernetDevice != nil { + dev := b.ethernetDevice.(gonetworkmanager.Device) + if dev.GetPath() == devicePath { + b.ethernetDevice = nil + for _, remaining := range b.ethernetDevices { + b.ethernetDevice = remaining.device + break + } + } + } + + b.updateAllEthernetDevices() + b.updateEthernetState() + b.listEthernetConnections() + b.updatePrimaryConnection() + + if b.onStateChange != nil { + b.onStateChange() + } + return + } + } + + for iface, info := range b.wifiDevices { + if info.device.GetPath() == devicePath { + delete(b.wifiDevices, iface) + + if b.wifiDevice != nil { + dev := b.wifiDevice.(gonetworkmanager.Device) + if dev.GetPath() == devicePath { + b.wifiDevice = nil + b.wifiDev = nil + for _, remaining := range b.wifiDevices { + b.wifiDevice = remaining.device + b.wifiDev = remaining.wireless + break + } + } + } + + b.updateAllWiFiDevices() + b.updateWiFiState() + + if b.onStateChange != nil { + b.onStateChange() + } + return + } + } +} diff --git a/core/internal/server/network/backend_networkmanager_state.go b/core/internal/server/network/backend_networkmanager_state.go index ac5e5688..5d3c9d9a 100644 --- a/core/internal/server/network/backend_networkmanager_state.go +++ b/core/internal/server/network/backend_networkmanager_state.go @@ -72,33 +72,34 @@ func (b *NetworkManagerBackend) updatePrimaryConnection() error { } func (b *NetworkManagerBackend) updateEthernetState() error { - if b.ethernetDevice == nil { - return nil + var connectedDevice string + var connectedIP string + var anyConnected bool + + for name, info := range b.ethernetDevices { + state, err := info.device.GetPropertyState() + if err != nil { + continue + } + + if state == gonetworkmanager.NmDeviceStateActivated { + anyConnected = true + connectedDevice = name + connectedIP = b.getDeviceIP(info.device) + break + } } - dev := b.ethernetDevice.(gonetworkmanager.Device) - - iface, err := dev.GetPropertyInterface() - if err != nil { - return err - } - - state, err := dev.GetPropertyState() - if err != nil { - return err - } - - connected := state == gonetworkmanager.NmDeviceStateActivated - - var ip string - if connected { - ip = b.getDeviceIP(dev) + if !anyConnected && b.ethernetDevice != nil { + dev := b.ethernetDevice.(gonetworkmanager.Device) + iface, _ := dev.GetPropertyInterface() + connectedDevice = iface } b.stateMutex.Lock() - b.state.EthernetDevice = iface - b.state.EthernetConnected = connected - b.state.EthernetIP = ip + b.state.EthernetDevice = connectedDevice + b.state.EthernetConnected = anyConnected + b.state.EthernetIP = connectedIP b.stateMutex.Unlock() return nil diff --git a/core/internal/server/network/backend_networkmanager_vpn.go b/core/internal/server/network/backend_networkmanager_vpn.go index a6a442a4..d9900124 100644 --- a/core/internal/server/network/backend_networkmanager_vpn.go +++ b/core/internal/server/network/backend_networkmanager_vpn.go @@ -1,13 +1,19 @@ package network import ( + "bufio" + "context" "fmt" + "os" + "os/exec" + "path/filepath" "sort" "strings" "time" "github.com/AvengeMedia/DankMaterialShell/core/internal/log" "github.com/Wifx/gonetworkmanager/v2" + "github.com/godbus/dbus/v5" ) func (b *NetworkManagerBackend) ListVPNProfiles() ([]VPNProfile, error) { @@ -46,11 +52,13 @@ func (b *NetworkManagerBackend) ListVPNProfiles() ([]VPNProfile, error) { connID, _ := connMeta["id"].(string) connUUID, _ := connMeta["uuid"].(string) + autoconnect, _ := connMeta["autoconnect"].(bool) profile := VPNProfile{ - Name: connID, - UUID: connUUID, - Type: connType, + Name: connID, + UUID: connUUID, + Type: connType, + Autoconnect: autoconnect, } if connType == "vpn" { @@ -58,6 +66,16 @@ func (b *NetworkManagerBackend) ListVPNProfiles() ([]VPNProfile, error) { if svcType, ok := vpnSettings["service-type"].(string); ok { profile.ServiceType = svcType } + // Get full data map + if data, ok := vpnSettings["data"].(map[string]string); ok { + profile.Data = data + if remote, ok := data["remote"]; ok { + profile.RemoteHost = remote + } + if username, ok := data["username"]; ok { + profile.Username = username + } + } } } @@ -120,6 +138,31 @@ func (b *NetworkManagerBackend) ListActiveVPN() ([]VPNActive, error) { Plugin: "", } + // Get VPN device + devices, _ := activeConn.GetPropertyDevices() + if len(devices) > 0 { + if iface, err := devices[0].GetPropertyInterface(); err == nil { + vpnActive.Device = iface + } + } + + // Get VPN IP from IP4Config + if ip4Config, err := activeConn.GetPropertyIP4Config(); err == nil && ip4Config != nil { + if addrData, err := ip4Config.GetPropertyAddressData(); err == nil && len(addrData) > 0 { + vpnActive.IP = addrData[0].Address + } + if gw, err := ip4Config.GetPropertyGateway(); err == nil { + vpnActive.Gateway = gw + } + } + + // Get MTU from device + if len(devices) > 0 { + if mtu, err := devices[0].GetPropertyMtu(); err == nil { + vpnActive.MTU = mtu + } + } + if connType == "vpn" { conn, _ := activeConn.GetPropertyConnection() if conn != nil { @@ -129,6 +172,16 @@ func (b *NetworkManagerBackend) ListActiveVPN() ([]VPNActive, error) { if svcType, ok := vpnSettings["service-type"].(string); ok { vpnActive.Plugin = svcType } + // Get full data map + if data, ok := vpnSettings["data"].(map[string]string); ok { + vpnActive.Data = data + if remote, ok := data["remote"]; ok { + vpnActive.RemoteHost = remote + } + if username, ok := data["username"]; ok { + vpnActive.Username = username + } + } } } } @@ -219,10 +272,122 @@ func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool) } var targetUUID string + var connName string if connMeta, ok := targetSettings["connection"]; ok { if uuid, ok := connMeta["uuid"].(string); ok { targetUUID = uuid } + if id, ok := connMeta["id"].(string); ok { + connName = id + } + } + + needsUsernamePrePrompt := false + var vpnServiceType string + if vpnSettings, ok := targetSettings["vpn"]; ok { + if svc, ok := vpnSettings["service-type"].(string); ok { + vpnServiceType = svc + } + if data, ok := vpnSettings["data"].(map[string]string); ok { + connType := data["connection-type"] + username := data["username"] + // OpenVPN password auth needs username in vpn.data + if strings.Contains(vpnServiceType, "openvpn") && + (connType == "password" || connType == "password-tls") && + username == "" { + needsUsernamePrePrompt = true + } + } + } + + // If username is needed but missing, prompt for it before activating + if needsUsernamePrePrompt && b.promptBroker != nil { + log.Infof("[ConnectVPN] OpenVPN requires username in vpn.data - prompting before activation") + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + token, err := b.promptBroker.Ask(ctx, PromptRequest{ + Name: connName, + ConnType: "vpn", + VpnService: vpnServiceType, + SettingName: "vpn", + Fields: []string{"username", "password"}, + FieldsInfo: []FieldInfo{{Name: "username", Label: "Username", IsSecret: false}, {Name: "password", Label: "Password", IsSecret: true}}, + Reason: "required", + ConnectionId: connName, + ConnectionUuid: targetUUID, + ConnectionPath: string(targetConn.GetPath()), + }) + if err != nil { + return fmt.Errorf("failed to request credentials: %w", err) + } + + reply, err := b.promptBroker.Wait(ctx, token) + if err != nil { + return fmt.Errorf("credentials prompt failed: %w", err) + } + + username := reply.Secrets["username"] + password := reply.Secrets["password"] + if username != "" { + connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", targetConn.GetPath()) + var existingSettings map[string]map[string]dbus.Variant + if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil { + return fmt.Errorf("failed to get settings for username save: %w", err) + } + + settings := make(map[string]map[string]dbus.Variant) + if connSection, ok := existingSettings["connection"]; ok { + settings["connection"] = connSection + } + vpn := existingSettings["vpn"] + var data map[string]string + if dataVariant, ok := vpn["data"]; ok { + if dm, ok := dataVariant.Value().(map[string]string); ok { + data = make(map[string]string) + for k, v := range dm { + data[k] = v + } + } else { + data = make(map[string]string) + } + } else { + data = make(map[string]string) + } + data["username"] = username + + if reply.Save && password != "" { + data["password-flags"] = "0" + secs := make(map[string]string) + secs["password"] = password + vpn["secrets"] = dbus.MakeVariant(secs) + log.Infof("[ConnectVPN] Saving username and password to vpn.data") + } else { + log.Infof("[ConnectVPN] Saving username to vpn.data (password will be prompted)") + } + + vpn["data"] = dbus.MakeVariant(data) + settings["vpn"] = vpn + + var result map[string]dbus.Variant + if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0, + settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil { + return fmt.Errorf("failed to save username: %w", err) + } + log.Infof("[ConnectVPN] Username saved to connection, now activating") + + if password != "" && !reply.Save { + b.cachedVPNCredsMu.Lock() + b.cachedVPNCreds = &cachedVPNCredentials{ + ConnectionUUID: targetUUID, + Password: password, + SavePassword: reply.Save, + } + b.cachedVPNCredsMu.Unlock() + log.Infof("[ConnectVPN] Cached password for GetSecrets") + } + } } b.stateMutex.Lock() @@ -470,7 +635,7 @@ func (b *NetworkManagerBackend) updateVPNConnectionState() { continue } - uuid, err := activeConn.GetPropertyUUID() + connUUID, err := activeConn.GetPropertyUUID() if err != nil { continue } @@ -478,20 +643,29 @@ func (b *NetworkManagerBackend) updateVPNConnectionState() { state, _ := activeConn.GetPropertyState() stateReason, _ := activeConn.GetPropertyStateFlags() - if uuid == connectingVPNUUID { + if connUUID == connectingVPNUUID { foundConnection = true switch state { case 2: - log.Infof("[updateVPNConnectionState] VPN connection successful: %s", uuid) + log.Infof("[updateVPNConnectionState] VPN connection successful: %s", connUUID) b.stateMutex.Lock() b.state.IsConnectingVPN = false b.state.ConnectingVPNUUID = "" b.state.LastError = "" b.stateMutex.Unlock() + + b.pendingVPNSaveMu.Lock() + pending := b.pendingVPNSave + b.pendingVPNSave = nil + b.pendingVPNSaveMu.Unlock() + + if pending != nil { + go b.saveVPNCredentials(pending) + } return case 4: - log.Warnf("[updateVPNConnectionState] VPN connection failed/deactivated: %s (state=%d, flags=%d)", uuid, state, stateReason) + log.Warnf("[updateVPNConnectionState] VPN connection failed/deactivated: %s (state=%d, flags=%d)", connUUID, state, stateReason) b.stateMutex.Lock() b.state.IsConnectingVPN = false b.state.ConnectingVPNUUID = "" @@ -511,3 +685,622 @@ func (b *NetworkManagerBackend) updateVPNConnectionState() { b.stateMutex.Unlock() } } + +func (b *NetworkManagerBackend) saveVPNCredentials(creds *pendingVPNCredentials) { + log.Infof("[saveVPNCredentials] Saving credentials for %s (username=%v, savePassword=%v)", + creds.ConnectionPath, creds.Username != "", creds.SavePassword) + + connObj := b.dbusConn.Object("org.freedesktop.NetworkManager", dbus.ObjectPath(creds.ConnectionPath)) + var existingSettings map[string]map[string]dbus.Variant + if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil { + log.Warnf("[saveVPNCredentials] GetSettings failed: %v", err) + return + } + + settings := make(map[string]map[string]dbus.Variant) + if connSection, ok := existingSettings["connection"]; ok { + settings["connection"] = connSection + } + + vpn, ok := existingSettings["vpn"] + if !ok { + vpn = make(map[string]dbus.Variant) + } + + // Get existing data map + var data map[string]string + if dataVariant, ok := vpn["data"]; ok { + if dm, ok := dataVariant.Value().(map[string]string); ok { + data = make(map[string]string) + for k, v := range dm { + data[k] = v + } + } else { + data = make(map[string]string) + } + } else { + data = make(map[string]string) + } + + // Always save username if provided + if creds.Username != "" { + data["username"] = creds.Username + log.Infof("[saveVPNCredentials] Saving username") + } + + // Save password if requested + if creds.SavePassword { + data["password-flags"] = "0" + secs := make(map[string]string) + secs["password"] = creds.Password + vpn["secrets"] = dbus.MakeVariant(secs) + log.Infof("[saveVPNCredentials] Saving password with password-flags=0") + } + + vpn["data"] = dbus.MakeVariant(data) + settings["vpn"] = vpn + + var result map[string]dbus.Variant + if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0, + settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result); err != nil { + log.Warnf("[saveVPNCredentials] Update2 failed: %v", err) + } else { + log.Infof("[saveVPNCredentials] Successfully saved credentials") + } +} + +func (b *NetworkManagerBackend) ListVPNPlugins() ([]VPNPlugin, error) { + plugins := []VPNPlugin{} + pluginDirs := []string{ + "/usr/lib/NetworkManager/VPN", + "/usr/lib64/NetworkManager/VPN", + "/etc/NetworkManager/VPN", + } + + seen := make(map[string]bool) + + for _, dir := range pluginDirs { + entries, err := os.ReadDir(dir) + if err != nil { + continue + } + + for _, entry := range entries { + if !strings.HasSuffix(entry.Name(), ".name") { + continue + } + + filePath := filepath.Join(dir, entry.Name()) + plugin, err := parseVPNPluginFile(filePath) + if err != nil { + log.Debugf("Failed to parse VPN plugin file %s: %v", filePath, err) + continue + } + + if seen[plugin.ServiceType] { + continue + } + seen[plugin.ServiceType] = true + plugins = append(plugins, *plugin) + } + } + + sort.Slice(plugins, func(i, j int) bool { + return strings.ToLower(plugins[i].Name) < strings.ToLower(plugins[j].Name) + }) + + return plugins, nil +} + +func parseVPNPluginFile(path string) (*VPNPlugin, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + plugin := &VPNPlugin{} + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "[") { + continue + } + + parts := strings.SplitN(line, "=", 2) + if len(parts) != 2 { + continue + } + + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + + switch key { + case "name": + plugin.Name = value + case "service": + plugin.ServiceType = value + case "program": + plugin.Program = value + case "supports": + plugin.Supports = strings.Split(value, ",") + for i := range plugin.Supports { + plugin.Supports[i] = strings.TrimSpace(plugin.Supports[i]) + } + } + } + + if plugin.ServiceType == "" { + return nil, fmt.Errorf("plugin file missing service type") + } + + plugin.FileExtensions = getVPNFileExtensions(plugin.ServiceType) + + return plugin, nil +} + +func getVPNFileExtensions(serviceType string) []string { + switch { + case strings.Contains(serviceType, "openvpn"): + return []string{".ovpn", ".conf"} + case strings.Contains(serviceType, "wireguard"): + return []string{".conf"} + case strings.Contains(serviceType, "vpnc"), strings.Contains(serviceType, "cisco"): + return []string{".pcf", ".conf"} + case strings.Contains(serviceType, "openconnect"): + return []string{".conf"} + case strings.Contains(serviceType, "pptp"): + return []string{".conf"} + case strings.Contains(serviceType, "l2tp"): + return []string{".conf"} + case strings.Contains(serviceType, "strongswan"), strings.Contains(serviceType, "ipsec"): + return []string{".conf", ".sswan"} + default: + return []string{".conf"} + } +} + +func (b *NetworkManagerBackend) ImportVPN(filePath string, name string) (*VPNImportResult, error) { + if _, err := os.Stat(filePath); os.IsNotExist(err) { + return &VPNImportResult{ + Success: false, + Error: fmt.Sprintf("file not found: %s", filePath), + }, nil + } + + ext := strings.ToLower(filepath.Ext(filePath)) + + switch ext { + case ".ovpn", ".conf": + return b.importVPNWithNmcli(filePath, name) + default: + return b.importVPNWithNmcli(filePath, name) + } +} + +func (b *NetworkManagerBackend) importVPNWithNmcli(filePath string, name string) (*VPNImportResult, error) { + args := []string{"connection", "import", "type", "openvpn", "file", filePath} + cmd := exec.Command("nmcli", args...) + output, err := cmd.CombinedOutput() + + if err != nil { + outputStr := string(output) + if strings.Contains(outputStr, "vpnc") || strings.Contains(outputStr, "unknown connection type") { + for _, vpnType := range []string{"vpnc", "pptp", "l2tp", "openconnect", "strongswan", "wireguard"} { + args = []string{"connection", "import", "type", vpnType, "file", filePath} + cmd = exec.Command("nmcli", args...) + output, err = cmd.CombinedOutput() + if err == nil { + break + } + } + } + + if err != nil { + return &VPNImportResult{ + Success: false, + Error: fmt.Sprintf("import failed: %s", strings.TrimSpace(string(output))), + }, nil + } + } + + outputStr := string(output) + var connUUID, connName string + + lines := strings.Split(outputStr, "\n") + for _, line := range lines { + if strings.Contains(line, "successfully added") { + parts := strings.Fields(line) + for i, part := range parts { + if part == "(" && i+1 < len(parts) { + connUUID = strings.TrimSuffix(parts[i+1], ")") + break + } + } + } + } + + if name != "" && connUUID != "" { + renameCmd := exec.Command("nmcli", "connection", "modify", connUUID, "connection.id", name) + if err := renameCmd.Run(); err != nil { + log.Warnf("Failed to rename imported VPN: %v", err) + } else { + connName = name + } + } + + if connUUID == "" { + s := b.settings + if s == nil { + var settingsErr error + s, settingsErr = gonetworkmanager.NewSettings() + if settingsErr == nil { + b.settings = s + } + } + + if s != nil { + settingsMgr := s.(gonetworkmanager.Settings) + connections, _ := settingsMgr.ListConnections() + baseName := strings.TrimSuffix(filepath.Base(filePath), filepath.Ext(filePath)) + + for _, conn := range connections { + settings, err := conn.GetSettings() + if err != nil { + continue + } + connMeta, ok := settings["connection"] + if !ok { + continue + } + connType, _ := connMeta["type"].(string) + if connType != "vpn" && connType != "wireguard" { + continue + } + connID, _ := connMeta["id"].(string) + if strings.Contains(connID, baseName) || (name != "" && connID == name) { + connUUID, _ = connMeta["uuid"].(string) + connName = connID + break + } + } + } + } + + b.ListVPNProfiles() + + if b.onStateChange != nil { + b.onStateChange() + } + + return &VPNImportResult{ + Success: true, + UUID: connUUID, + Name: connName, + }, nil +} + +func (b *NetworkManagerBackend) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { + s := b.settings + if s == nil { + var err error + s, err = gonetworkmanager.NewSettings() + if err != nil { + return nil, fmt.Errorf("failed to get settings: %w", err) + } + b.settings = s + } + + settingsMgr := s.(gonetworkmanager.Settings) + connections, err := settingsMgr.ListConnections() + if err != nil { + return nil, fmt.Errorf("failed to get connections: %w", err) + } + + for _, conn := range connections { + settings, err := conn.GetSettings() + if err != nil { + continue + } + + connMeta, ok := settings["connection"] + if !ok { + continue + } + + connType, _ := connMeta["type"].(string) + if connType != "vpn" && connType != "wireguard" { + continue + } + + connID, _ := connMeta["id"].(string) + connUUID, _ := connMeta["uuid"].(string) + + if connUUID != uuidOrName && connID != uuidOrName { + continue + } + + autoconnect := true + if ac, ok := connMeta["autoconnect"].(bool); ok { + autoconnect = ac + } + + config := &VPNConfig{ + UUID: connUUID, + Name: connID, + Type: connType, + Autoconnect: autoconnect, + Data: make(map[string]string), + } + + if connType == "vpn" { + if vpnSettings, ok := settings["vpn"]; ok { + if svcType, ok := vpnSettings["service-type"].(string); ok { + config.ServiceType = svcType + } + if dataMap, ok := vpnSettings["data"].(map[string]string); ok { + for k, v := range dataMap { + if !strings.Contains(strings.ToLower(k), "password") && + !strings.Contains(strings.ToLower(k), "secret") && + !strings.Contains(strings.ToLower(k), "key") { + config.Data[k] = v + } + } + } + } + } + + return config, nil + } + + return nil, fmt.Errorf("VPN connection not found: %s", uuidOrName) +} + +func (b *NetworkManagerBackend) UpdateVPNConfig(connUUID string, updates map[string]interface{}) error { + s := b.settings + if s == nil { + var err error + s, err = gonetworkmanager.NewSettings() + if err != nil { + return fmt.Errorf("failed to get settings: %w", err) + } + b.settings = s + } + + settingsMgr := s.(gonetworkmanager.Settings) + connections, err := settingsMgr.ListConnections() + if err != nil { + return fmt.Errorf("failed to get connections: %w", err) + } + + for _, conn := range connections { + settings, err := conn.GetSettings() + if err != nil { + continue + } + + connMeta, ok := settings["connection"] + if !ok { + continue + } + + connType, _ := connMeta["type"].(string) + if connType != "vpn" && connType != "wireguard" { + continue + } + + existingUUID, _ := connMeta["uuid"].(string) + if existingUUID != connUUID { + continue + } + + if name, ok := updates["name"].(string); ok && name != "" { + connMeta["id"] = name + } + + if autoconnect, ok := updates["autoconnect"].(bool); ok { + connMeta["autoconnect"] = autoconnect + } + + if data, ok := updates["data"].(map[string]interface{}); ok { + if vpnSettings, ok := settings["vpn"]; ok { + existingData, _ := vpnSettings["data"].(map[string]string) + if existingData == nil { + existingData = make(map[string]string) + } + for k, v := range data { + if strVal, ok := v.(string); ok { + existingData[k] = strVal + } + } + vpnSettings["data"] = existingData + } + } + + if ipv4, ok := settings["ipv4"]; ok { + delete(ipv4, "addresses") + delete(ipv4, "routes") + delete(ipv4, "dns") + } + if ipv6, ok := settings["ipv6"]; ok { + delete(ipv6, "addresses") + delete(ipv6, "routes") + delete(ipv6, "dns") + } + + if err := conn.Update(settings); err != nil { + return fmt.Errorf("failed to update connection: %w", err) + } + + b.ListVPNProfiles() + + if b.onStateChange != nil { + b.onStateChange() + } + + return nil + } + + return fmt.Errorf("VPN connection not found: %s", connUUID) +} + +func (b *NetworkManagerBackend) SetVPNCredentials(connUUID string, username string, password string, saveToKeyring bool) error { + s := b.settings + if s == nil { + var err error + s, err = gonetworkmanager.NewSettings() + if err != nil { + return fmt.Errorf("failed to get settings: %w", err) + } + b.settings = s + } + + settingsMgr := s.(gonetworkmanager.Settings) + connections, err := settingsMgr.ListConnections() + if err != nil { + return fmt.Errorf("failed to get connections: %w", err) + } + + for _, conn := range connections { + settings, err := conn.GetSettings() + if err != nil { + continue + } + + connMeta, ok := settings["connection"] + if !ok { + continue + } + + connType, _ := connMeta["type"].(string) + if connType != "vpn" && connType != "wireguard" { + continue + } + + existingUUID, _ := connMeta["uuid"].(string) + if existingUUID != connUUID { + continue + } + + vpnSettings, ok := settings["vpn"] + if !ok { + vpnSettings = make(map[string]interface{}) + settings["vpn"] = vpnSettings + } + + existingData, _ := vpnSettings["data"].(map[string]string) + if existingData == nil { + existingData = make(map[string]string) + } + + if username != "" { + existingData["username"] = username + } + + if saveToKeyring { + existingData["password-flags"] = "0" + } else { + existingData["password-flags"] = "2" + } + + vpnSettings["data"] = existingData + + if password != "" { + secrets := make(map[string]string) + secrets["password"] = password + vpnSettings["secrets"] = secrets + } + + if ipv4, ok := settings["ipv4"]; ok { + delete(ipv4, "addresses") + delete(ipv4, "routes") + delete(ipv4, "dns") + } + if ipv6, ok := settings["ipv6"]; ok { + delete(ipv6, "addresses") + delete(ipv6, "routes") + delete(ipv6, "dns") + } + + if err := conn.Update(settings); err != nil { + return fmt.Errorf("failed to update connection: %w", err) + } + + log.Infof("Updated VPN credentials for %s (save=%v)", connUUID, saveToKeyring) + + if b.onStateChange != nil { + b.onStateChange() + } + + return nil + } + + return fmt.Errorf("VPN connection not found: %s", connUUID) +} + +func (b *NetworkManagerBackend) DeleteVPN(uuidOrName string) error { + active, _ := b.ListActiveVPN() + for _, vpn := range active { + if vpn.UUID == uuidOrName || vpn.Name == uuidOrName { + if err := b.DisconnectVPN(uuidOrName); err != nil { + log.Warnf("Failed to disconnect VPN before deletion: %v", err) + } + time.Sleep(200 * time.Millisecond) + break + } + } + + s := b.settings + if s == nil { + var err error + s, err = gonetworkmanager.NewSettings() + if err != nil { + return fmt.Errorf("failed to get settings: %w", err) + } + b.settings = s + } + + settingsMgr := s.(gonetworkmanager.Settings) + connections, err := settingsMgr.ListConnections() + if err != nil { + return fmt.Errorf("failed to get connections: %w", err) + } + + for _, conn := range connections { + settings, err := conn.GetSettings() + if err != nil { + continue + } + + connMeta, ok := settings["connection"] + if !ok { + continue + } + + connType, _ := connMeta["type"].(string) + if connType != "vpn" && connType != "wireguard" { + continue + } + + connID, _ := connMeta["id"].(string) + connUUID, _ := connMeta["uuid"].(string) + + if connUUID == uuidOrName || connID == uuidOrName { + if err := conn.Delete(); err != nil { + return fmt.Errorf("failed to delete VPN: %w", err) + } + + b.ListVPNProfiles() + + if b.onStateChange != nil { + b.onStateChange() + } + + log.Infof("Deleted VPN connection: %s (%s)", connID, connUUID) + return nil + } + } + + return fmt.Errorf("VPN connection not found: %s", uuidOrName) +} diff --git a/core/internal/server/network/backend_networkmanager_wifi.go b/core/internal/server/network/backend_networkmanager_wifi.go index fe52acae..4c5d38c9 100644 --- a/core/internal/server/network/backend_networkmanager_wifi.go +++ b/core/internal/server/network/backend_networkmanager_wifi.go @@ -579,31 +579,59 @@ func (b *NetworkManagerBackend) createAndConnectWiFiOnDevice(req ConnectionReque "key-mgmt": "wpa-eap", } + eapMethod := "peap" + if req.EAPMethod != "" { + eapMethod = req.EAPMethod + } + + phase2Auth := "mschapv2" + if req.Phase2Auth != "" { + phase2Auth = req.Phase2Auth + } + + useSystemCACerts := false + if req.UseSystemCACerts != nil { + useSystemCACerts = *req.UseSystemCACerts + } + x := map[string]interface{}{ - "eap": []string{"peap"}, - "phase2-auth": "mschapv2", - "system-ca-certs": false, + "eap": []string{eapMethod}, + "system-ca-certs": useSystemCACerts, "password-flags": uint32(0), } + switch eapMethod { + case "peap", "ttls": + x["phase2-auth"] = phase2Auth + case "tls": + if req.ClientCertPath != "" { + x["client-cert"] = []byte("file://" + req.ClientCertPath) + } + if req.PrivateKeyPath != "" { + x["private-key"] = []byte("file://" + req.PrivateKeyPath) + } + } + if req.Username != "" { x["identity"] = req.Username } if req.Password != "" { x["password"] = req.Password } - if req.AnonymousIdentity != "" { x["anonymous-identity"] = req.AnonymousIdentity } if req.DomainSuffixMatch != "" { x["domain-suffix-match"] = req.DomainSuffixMatch } + if req.CACertPath != "" { + x["ca-cert"] = []byte("file://" + req.CACertPath) + } settings["802-1x"] = x - log.Infof("[createAndConnectWiFi] WPA-EAP settings: eap=peap, phase2-auth=mschapv2, identity=%s, interactive=%v, system-ca-certs=%v, domain-suffix-match=%q", - req.Username, req.Interactive, x["system-ca-certs"], req.DomainSuffixMatch) + log.Infof("[createAndConnectWiFi] WPA-EAP settings: eap=%s, phase2-auth=%s, identity=%s, interactive=%v, system-ca-certs=%v, domain-suffix-match=%q", + eapMethod, phase2Auth, req.Username, req.Interactive, useSystemCACerts, req.DomainSuffixMatch) case isPsk: sec := map[string]interface{}{ diff --git a/core/internal/server/network/handlers.go b/core/internal/server/network/handlers.go index 2d896c99..6bfbadab 100644 --- a/core/internal/server/network/handlers.go +++ b/core/internal/server/network/handlers.go @@ -70,6 +70,18 @@ func HandleRequest(conn net.Conn, req Request, manager *Manager) { handleDisconnectAllVPN(conn, req, manager) case "network.vpn.clearCredentials": handleClearVPNCredentials(conn, req, manager) + case "network.vpn.plugins": + handleListVPNPlugins(conn, req, manager) + case "network.vpn.import": + handleImportVPN(conn, req, manager) + case "network.vpn.getConfig": + handleGetVPNConfig(conn, req, manager) + case "network.vpn.updateConfig": + handleUpdateVPNConfig(conn, req, manager) + case "network.vpn.delete": + handleDeleteVPN(conn, req, manager) + case "network.vpn.setCredentials": + handleSetVPNCredentials(conn, req, manager) case "network.wifi.setAutoconnect": handleSetWiFiAutoconnect(conn, req, manager) default: @@ -200,6 +212,24 @@ func handleConnectWiFi(conn net.Conn, req Request, manager *Manager) { if domainSuffixMatch, ok := req.Params["domainSuffixMatch"].(string); ok { connReq.DomainSuffixMatch = domainSuffixMatch } + if eapMethod, ok := req.Params["eapMethod"].(string); ok { + connReq.EAPMethod = eapMethod + } + if phase2Auth, ok := req.Params["phase2Auth"].(string); ok { + connReq.Phase2Auth = phase2Auth + } + if caCertPath, ok := req.Params["caCertPath"].(string); ok { + connReq.CACertPath = caCertPath + } + if clientCertPath, ok := req.Params["clientCertPath"].(string); ok { + connReq.ClientCertPath = clientCertPath + } + if privateKeyPath, ok := req.Params["privateKeyPath"].(string); ok { + connReq.PrivateKeyPath = privateKeyPath + } + if useSystemCACerts, ok := req.Params["useSystemCACerts"].(bool); ok { + connReq.UseSystemCACerts = &useSystemCACerts + } if err := manager.ConnectWiFi(connReq); err != nil { models.RespondError(conn, req.ID, err.Error()) @@ -287,7 +317,14 @@ func handleConnectEthernet(conn net.Conn, req Request, manager *Manager) { } func handleDisconnectEthernet(conn net.Conn, req Request, manager *Manager) { - if err := manager.DisconnectEthernet(); err != nil { + device, _ := req.Params["device"].(string) + var err error + if device != "" { + err = manager.DisconnectEthernetDevice(device) + } else { + err = manager.DisconnectEthernet() + } + if err != nil { models.RespondError(conn, req.ID, err.Error()) return } @@ -502,3 +539,138 @@ func handleSetWiFiAutoconnect(conn net.Conn, req Request, manager *Manager) { models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "autoconnect updated"}) } + +func handleListVPNPlugins(conn net.Conn, req Request, manager *Manager) { + plugins, err := manager.ListVPNPlugins() + if err != nil { + log.Warnf("handleListVPNPlugins: failed to list plugins: %v", err) + models.RespondError(conn, req.ID, fmt.Sprintf("failed to list VPN plugins: %v", err)) + return + } + + models.Respond(conn, req.ID, plugins) +} + +func handleImportVPN(conn net.Conn, req Request, manager *Manager) { + filePath, ok := req.Params["file"].(string) + if !ok { + filePath, ok = req.Params["path"].(string) + } + if !ok { + models.RespondError(conn, req.ID, "missing 'file' or 'path' parameter") + return + } + + name, _ := req.Params["name"].(string) + + result, err := manager.ImportVPN(filePath, name) + if err != nil { + log.Warnf("handleImportVPN: failed to import: %v", err) + models.RespondError(conn, req.ID, fmt.Sprintf("failed to import VPN: %v", err)) + return + } + + models.Respond(conn, req.ID, result) +} + +func handleGetVPNConfig(conn net.Conn, req Request, manager *Manager) { + uuidOrName, ok := req.Params["uuid"].(string) + if !ok { + uuidOrName, ok = req.Params["name"].(string) + } + if !ok { + uuidOrName, ok = req.Params["uuidOrName"].(string) + } + if !ok { + models.RespondError(conn, req.ID, "missing 'uuid', 'name', or 'uuidOrName' parameter") + return + } + + config, err := manager.GetVPNConfig(uuidOrName) + if err != nil { + log.Warnf("handleGetVPNConfig: failed to get config: %v", err) + models.RespondError(conn, req.ID, fmt.Sprintf("failed to get VPN config: %v", err)) + return + } + + models.Respond(conn, req.ID, config) +} + +func handleUpdateVPNConfig(conn net.Conn, req Request, manager *Manager) { + connUUID, ok := req.Params["uuid"].(string) + if !ok { + models.RespondError(conn, req.ID, "missing 'uuid' parameter") + return + } + + updates := make(map[string]interface{}) + + if name, ok := req.Params["name"].(string); ok { + updates["name"] = name + } + if autoconnect, ok := req.Params["autoconnect"].(bool); ok { + updates["autoconnect"] = autoconnect + } + if data, ok := req.Params["data"].(map[string]interface{}); ok { + updates["data"] = data + } + + if len(updates) == 0 { + models.RespondError(conn, req.ID, "no updates provided") + return + } + + if err := manager.UpdateVPNConfig(connUUID, updates); err != nil { + log.Warnf("handleUpdateVPNConfig: failed to update: %v", err) + models.RespondError(conn, req.ID, fmt.Sprintf("failed to update VPN config: %v", err)) + return + } + + models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "VPN config updated"}) +} + +func handleDeleteVPN(conn net.Conn, req Request, manager *Manager) { + uuidOrName, ok := req.Params["uuid"].(string) + if !ok { + uuidOrName, ok = req.Params["name"].(string) + } + if !ok { + uuidOrName, ok = req.Params["uuidOrName"].(string) + } + if !ok { + models.RespondError(conn, req.ID, "missing 'uuid', 'name', or 'uuidOrName' parameter") + return + } + + if err := manager.DeleteVPN(uuidOrName); err != nil { + log.Warnf("handleDeleteVPN: failed to delete: %v", err) + models.RespondError(conn, req.ID, fmt.Sprintf("failed to delete VPN: %v", err)) + return + } + + models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "VPN deleted"}) +} + +func handleSetVPNCredentials(conn net.Conn, req Request, manager *Manager) { + connUUID, ok := req.Params["uuid"].(string) + if !ok { + models.RespondError(conn, req.ID, "missing 'uuid' parameter") + return + } + + username, _ := req.Params["username"].(string) + password, _ := req.Params["password"].(string) + + save := true + if saveParam, ok := req.Params["save"].(bool); ok { + save = saveParam + } + + if err := manager.SetVPNCredentials(connUUID, username, password, save); err != nil { + log.Warnf("handleSetVPNCredentials: failed to set credentials: %v", err) + models.RespondError(conn, req.ID, fmt.Sprintf("failed to set VPN credentials: %v", err)) + return + } + + models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "VPN credentials set"}) +} diff --git a/core/internal/server/network/manager.go b/core/internal/server/network/manager.go index 3d17da40..bfc778f3 100644 --- a/core/internal/server/network/manager.go +++ b/core/internal/server/network/manager.go @@ -109,6 +109,7 @@ func (m *Manager) syncStateFromBackend() error { m.state.EthernetDevice = backendState.EthernetDevice m.state.EthernetConnected = backendState.EthernetConnected m.state.EthernetConnectionUuid = backendState.EthernetConnectionUuid + m.state.EthernetDevices = backendState.EthernetDevices m.state.WiFiIP = backendState.WiFiIP m.state.WiFiDevice = backendState.WiFiDevice m.state.WiFiConnected = backendState.WiFiConnected @@ -155,6 +156,7 @@ func (m *Manager) snapshotState() NetworkState { s.WiFiNetworks = append([]WiFiNetwork(nil), m.state.WiFiNetworks...) s.WiFiDevices = append([]WiFiDevice(nil), m.state.WiFiDevices...) s.WiredConnections = append([]WiredConnection(nil), m.state.WiredConnections...) + s.EthernetDevices = append([]EthernetDevice(nil), m.state.EthernetDevices...) s.VPNProfiles = append([]VPNProfile(nil), m.state.VPNProfiles...) s.VPNActive = append([]VPNActive(nil), m.state.VPNActive...) return s @@ -213,6 +215,9 @@ func stateChangedMeaningfully(old, new *NetworkState) bool { if len(old.WiredConnections) != len(new.WiredConnections) { return true } + if len(old.EthernetDevices) != len(new.EthernetDevices) { + return true + } for i := range old.WiFiNetworks { oldNet := &old.WiFiNetworks[i] @@ -242,6 +247,23 @@ func stateChangedMeaningfully(old, new *NetworkState) bool { } } + for i := range old.EthernetDevices { + oldDev := &old.EthernetDevices[i] + newDev := &new.EthernetDevices[i] + if oldDev.Name != newDev.Name { + return true + } + if oldDev.Connected != newDev.Connected { + return true + } + if oldDev.State != newDev.State { + return true + } + if oldDev.IP != newDev.IP { + return true + } + } + // Check VPN profiles count if len(old.VPNProfiles) != len(new.VPNProfiles) { return true @@ -480,6 +502,18 @@ func (m *Manager) DisconnectEthernet() error { return m.backend.DisconnectEthernet() } +func (m *Manager) DisconnectEthernetDevice(device string) error { + return m.backend.DisconnectEthernetDevice(device) +} + +func (m *Manager) GetEthernetDevices() []EthernetDevice { + m.stateMutex.RLock() + defer m.stateMutex.RUnlock() + devices := make([]EthernetDevice, len(m.state.EthernetDevices)) + copy(devices, m.state.EthernetDevices) + return devices +} + func (m *Manager) activateConnection(uuid string) error { return m.backend.ActivateWiredConnection(uuid) } @@ -508,6 +542,30 @@ func (m *Manager) ClearVPNCredentials(uuidOrName string) error { return m.backend.ClearVPNCredentials(uuidOrName) } +func (m *Manager) ListVPNPlugins() ([]VPNPlugin, error) { + return m.backend.ListVPNPlugins() +} + +func (m *Manager) ImportVPN(filePath string, name string) (*VPNImportResult, error) { + return m.backend.ImportVPN(filePath, name) +} + +func (m *Manager) GetVPNConfig(uuidOrName string) (*VPNConfig, error) { + return m.backend.GetVPNConfig(uuidOrName) +} + +func (m *Manager) UpdateVPNConfig(uuid string, updates map[string]interface{}) error { + return m.backend.UpdateVPNConfig(uuid, updates) +} + +func (m *Manager) DeleteVPN(uuidOrName string) error { + return m.backend.DeleteVPN(uuidOrName) +} + +func (m *Manager) SetVPNCredentials(uuid, username, password string, save bool) error { + return m.backend.SetVPNCredentials(uuid, username, password, save) +} + func (m *Manager) SetWiFiAutoconnect(ssid string, autoconnect bool) error { return m.backend.SetWiFiAutoconnect(ssid, autoconnect) } diff --git a/core/internal/server/network/subscription_broker.go b/core/internal/server/network/subscription_broker.go index b925209b..1b150a26 100644 --- a/core/internal/server/network/subscription_broker.go +++ b/core/internal/server/network/subscription_broker.go @@ -49,6 +49,7 @@ func (b *SubscriptionBroker) Ask(ctx context.Context, req PromptRequest) (string VpnService: req.VpnService, Setting: req.SettingName, Fields: req.Fields, + FieldsInfo: req.FieldsInfo, Hints: req.Hints, Reason: req.Reason, ConnectionId: req.ConnectionId, diff --git a/core/internal/server/network/types.go b/core/internal/server/network/types.go index 11b92874..8957f761 100644 --- a/core/internal/server/network/types.go +++ b/core/internal/server/network/types.go @@ -52,20 +52,40 @@ type WiFiDevice struct { Networks []WiFiNetwork `json:"networks"` } +type EthernetDevice struct { + Name string `json:"name"` + HwAddress string `json:"hwAddress"` + State string `json:"state"` + Connected bool `json:"connected"` + IP string `json:"ip,omitempty"` + Speed uint32 `json:"speed,omitempty"` + Driver string `json:"driver,omitempty"` +} + type VPNProfile struct { - Name string `json:"name"` - UUID string `json:"uuid"` - Type string `json:"type"` - ServiceType string `json:"serviceType"` + Name string `json:"name"` + UUID string `json:"uuid"` + Type string `json:"type"` + ServiceType string `json:"serviceType"` + RemoteHost string `json:"remoteHost,omitempty"` + Username string `json:"username,omitempty"` + Autoconnect bool `json:"autoconnect"` + Data map[string]string `json:"data,omitempty"` } type VPNActive struct { - Name string `json:"name"` - UUID string `json:"uuid"` - Device string `json:"device,omitempty"` - State string `json:"state,omitempty"` - Type string `json:"type"` - Plugin string `json:"serviceType"` + Name string `json:"name"` + UUID string `json:"uuid"` + Device string `json:"device,omitempty"` + State string `json:"state,omitempty"` + Type string `json:"type"` + Plugin string `json:"serviceType"` + IP string `json:"ip,omitempty"` + Gateway string `json:"gateway,omitempty"` + RemoteHost string `json:"remoteHost,omitempty"` + Username string `json:"username,omitempty"` + MTU uint32 `json:"mtu,omitempty"` + Data map[string]string `json:"data,omitempty"` } type VPNState struct { @@ -81,6 +101,7 @@ type NetworkState struct { EthernetDevice string `json:"ethernetDevice"` EthernetConnected bool `json:"ethernetConnected"` EthernetConnectionUuid string `json:"ethernetConnectionUuid"` + EthernetDevices []EthernetDevice `json:"ethernetDevices"` WiFiIP string `json:"wifiIP"` WiFiDevice string `json:"wifiDevice"` WiFiConnected bool `json:"wifiConnected"` @@ -107,6 +128,12 @@ type ConnectionRequest struct { DomainSuffixMatch string `json:"domainSuffixMatch,omitempty"` Interactive bool `json:"interactive,omitempty"` Device string `json:"device,omitempty"` + EAPMethod string `json:"eapMethod,omitempty"` + Phase2Auth string `json:"phase2Auth,omitempty"` + CACertPath string `json:"caCertPath,omitempty"` + ClientCertPath string `json:"clientCertPath,omitempty"` + PrivateKeyPath string `json:"privateKeyPath,omitempty"` + UseSystemCACerts *bool `json:"useSystemCACerts,omitempty"` } type WiredConnection struct { @@ -150,17 +177,18 @@ type NetworkEvent struct { } type PromptRequest struct { - Name string `json:"name"` - SSID string `json:"ssid"` - ConnType string `json:"connType"` - VpnService string `json:"vpnService"` - SettingName string `json:"setting"` - Fields []string `json:"fields"` - Hints []string `json:"hints"` - Reason string `json:"reason"` - ConnectionId string `json:"connectionId"` - ConnectionUuid string `json:"connectionUuid"` - ConnectionPath string `json:"connectionPath"` + Name string `json:"name"` + SSID string `json:"ssid"` + ConnType string `json:"connType"` + VpnService string `json:"vpnService"` + SettingName string `json:"setting"` + Fields []string `json:"fields"` + FieldsInfo []FieldInfo `json:"fieldsInfo"` + Hints []string `json:"hints"` + Reason string `json:"reason"` + ConnectionId string `json:"connectionId"` + ConnectionUuid string `json:"connectionUuid"` + ConnectionPath string `json:"connectionPath"` } type PromptReply struct { @@ -169,18 +197,25 @@ type PromptReply struct { Cancel bool `json:"cancel"` } +type FieldInfo struct { + Name string `json:"name"` + Label string `json:"label"` + IsSecret bool `json:"isSecret"` +} + type CredentialPrompt struct { - Token string `json:"token"` - Name string `json:"name"` - SSID string `json:"ssid"` - ConnType string `json:"connType"` - VpnService string `json:"vpnService"` - Setting string `json:"setting"` - Fields []string `json:"fields"` - Hints []string `json:"hints"` - Reason string `json:"reason"` - ConnectionId string `json:"connectionId"` - ConnectionUuid string `json:"connectionUuid"` + Token string `json:"token"` + Name string `json:"name"` + SSID string `json:"ssid"` + ConnType string `json:"connType"` + VpnService string `json:"vpnService"` + Setting string `json:"setting"` + Fields []string `json:"fields"` + FieldsInfo []FieldInfo `json:"fieldsInfo"` + Hints []string `json:"hints"` + Reason string `json:"reason"` + ConnectionId string `json:"connectionId"` + ConnectionUuid string `json:"connectionUuid"` } type NetworkInfoResponse struct { @@ -203,3 +238,28 @@ type WiredIPConfig struct { Gateway string `json:"gateway"` DNS string `json:"dns"` } + +type VPNPlugin struct { + Name string `json:"name"` + ServiceType string `json:"serviceType"` + Program string `json:"program,omitempty"` + Supports []string `json:"supports,omitempty"` + FileExtensions []string `json:"fileExtensions"` +} + +type VPNConfig struct { + UUID string `json:"uuid"` + Name string `json:"name"` + Type string `json:"type"` + ServiceType string `json:"serviceType,omitempty"` + Autoconnect bool `json:"autoconnect"` + Data map[string]string `json:"data,omitempty"` +} + +type VPNImportResult struct { + Success bool `json:"success"` + UUID string `json:"uuid,omitempty"` + Name string `json:"name,omitempty"` + ServiceType string `json:"serviceType,omitempty"` + Error string `json:"error,omitempty"` +} diff --git a/core/internal/server/network/wired_test.go b/core/internal/server/network/wired_test.go index 175b3439..5c346e7a 100644 --- a/core/internal/server/network/wired_test.go +++ b/core/internal/server/network/wired_test.go @@ -21,3 +21,31 @@ func TestManager_GetWiredConfigs(t *testing.T) { assert.Len(t, configs, 1) assert.Equal(t, "Test", configs[0].ID) } + +func TestManager_GetEthernetDevices(t *testing.T) { + manager := &Manager{ + state: &NetworkState{ + EthernetDevices: []EthernetDevice{ + {Name: "enp0s3", Connected: true, IP: "192.168.1.100"}, + {Name: "enp0s8", Connected: false}, + }, + }, + } + + devices := manager.GetEthernetDevices() + + assert.Len(t, devices, 2) + assert.Equal(t, "enp0s3", devices[0].Name) + assert.True(t, devices[0].Connected) + assert.Equal(t, "enp0s8", devices[1].Name) + assert.False(t, devices[1].Connected) +} + +func TestManager_GetEthernetDevices_Empty(t *testing.T) { + manager := &Manager{ + state: &NetworkState{}, + } + + devices := manager.GetEthernetDevices() + assert.Empty(t, devices) +} diff --git a/core/internal/server/server.go b/core/internal/server/server.go index 8eb1f794..ce238d2b 100644 --- a/core/internal/server/server.go +++ b/core/internal/server/server.go @@ -31,7 +31,7 @@ import ( "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" ) -const APIVersion = 20 +const APIVersion = 21 type Capabilities struct { Capabilities []string `json:"capabilities"` @@ -1073,7 +1073,7 @@ func Start(printDocs bool) error { log.Info(" network.getState - Get current network state") log.Info(" network.wifi.scan - Scan for WiFi networks (params: device?)") log.Info(" network.wifi.networks - Get WiFi network list") - log.Info(" network.wifi.connect - Connect to WiFi (params: ssid, password?, username?, device?)") + log.Info(" network.wifi.connect - Connect to WiFi (params: ssid, password?, username?, device?, eapMethod?, phase2Auth?, caCertPath?, clientCertPath?, privateKeyPath?, useSystemCACerts?)") log.Info(" network.wifi.disconnect - Disconnect WiFi (params: device?)") log.Info(" network.wifi.forget - Forget network (params: ssid)") log.Info(" network.wifi.toggle - Toggle WiFi radio") @@ -1089,6 +1089,11 @@ func Start(printDocs bool) error { log.Info(" network.vpn.disconnect - Disconnect VPN (params: uuidOrName|name|uuid)") log.Info(" network.vpn.disconnectAll - Disconnect all VPNs") log.Info(" network.vpn.clearCredentials - Clear saved VPN credentials (params: uuidOrName|name|uuid)") + log.Info(" network.vpn.plugins - List available VPN plugins") + log.Info(" network.vpn.import - Import VPN from file (params: file|path, name?)") + log.Info(" network.vpn.getConfig - Get VPN configuration (params: uuid|name|uuidOrName)") + log.Info(" network.vpn.updateConfig - Update VPN configuration (params: uuid, name?, autoconnect?, data?)") + log.Info(" network.vpn.delete - Delete VPN connection (params: uuid|name|uuidOrName)") log.Info(" network.preference.set - Set preference (params: preference [auto|wifi|ethernet])") log.Info(" network.info - Get network info (params: ssid)") log.Info(" network.credentials.submit - Submit credentials for prompt (params: token, secrets, save?)") diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml index a464c1fc..4b9209ed 100644 --- a/quickshell/DMSShell.qml +++ b/quickshell/DMSShell.qml @@ -3,7 +3,6 @@ import Quickshell import qs.Common import qs.Modals import qs.Modals.Clipboard -import qs.Modals.Common import qs.Modals.Settings import qs.Modals.Spotlight import qs.Modules @@ -253,6 +252,10 @@ Item { PolkitAuthModal { id: polkitAuthModal + + Component.onCompleted: { + PopoutService.polkitAuthModal = polkitAuthModal; + } } BluetoothPairingModal { @@ -269,21 +272,21 @@ Item { Connections { target: NetworkService - function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) { + function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo) { const now = Date.now(); const timeSinceLastPrompt = now - lastCredentialsTime; - if (wifiPasswordModal.shouldBeVisible && timeSinceLastPrompt < 1000) { + if (wifiPasswordModal.visible && timeSinceLastPrompt < 1000) { NetworkService.cancelCredentials(lastCredentialsToken); lastCredentialsToken = token; lastCredentialsTime = now; - wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService); + wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo); return; } lastCredentialsToken = token; lastCredentialsTime = now; - wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService); + wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo); } } diff --git a/quickshell/Modals/PolkitAuthModal.qml b/quickshell/Modals/PolkitAuthModal.qml index 5c2e4be9..21f06691 100644 --- a/quickshell/Modals/PolkitAuthModal.qml +++ b/quickshell/Modals/PolkitAuthModal.qml @@ -1,71 +1,62 @@ import QtQuick -import Quickshell.Hyprland +import Quickshell import qs.Common -import qs.Modals.Common import qs.Services import qs.Widgets -DankModal { +FloatingWindow { id: root - layerNamespace: "dms:polkit" - - HyprlandFocusGrab { - windows: [root.contentWindow] - active: CompositorService.isHyprland && root.shouldHaveFocus - } - property string passwordInput: "" property var currentFlow: PolkitService.agent?.flow property bool isLoading: false - property real minHeight: 240 + property int calculatedHeight: Math.max(240, headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM * 3) + + function focusPasswordField() { + passwordField.forceActiveFocus(); + } function show() { passwordInput = ""; isLoading = false; - open(); - Qt.callLater(() => { - if (contentLoader.item && contentLoader.item.passwordField) { - contentLoader.item.passwordField.forceActiveFocus(); - } - }); + visible = true; + Qt.callLater(focusPasswordField); } - shouldBeVisible: false - modalWidth: 420 - modalHeight: Math.max(minHeight, contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 240) + function hide() { + visible = false; + } - Connections { - target: contentLoader.item - function onImplicitHeightChanged() { - if (shouldBeVisible && contentLoader.item) { - const newHeight = contentLoader.item.implicitHeight + Theme.spacingM * 2; - if (newHeight > minHeight) { - minHeight = newHeight; - } - } + function submitAuth() { + if (passwordInput.length === 0 || !currentFlow || isLoading) + return; + isLoading = true; + currentFlow.submit(passwordInput); + passwordInput = ""; + } + + function cancelAuth() { + if (!currentFlow || isLoading) + return; + currentFlow.cancelAuthenticationRequest(); + } + + objectName: "polkitAuthModal" + title: I18n.tr("Authentication") + minimumSize: Qt.size(420, calculatedHeight) + maximumSize: Qt.size(420, calculatedHeight) + color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) + visible: false + + onVisibleChanged: { + if (visible) { + Qt.callLater(focusPasswordField); + return; } - } - - onOpened: { - Qt.callLater(() => { - if (contentLoader.item && contentLoader.item.passwordField) { - contentLoader.item.passwordField.forceActiveFocus(); - } - }); - } - - onDialogClosed: { passwordInput = ""; isLoading = false; } - onBackgroundClicked: () => { - if (currentFlow && !isLoading) { - currentFlow.cancelAuthenticationRequest(); - } - } - Connections { target: PolkitService.agent enabled: PolkitService.polkitAvailable @@ -75,9 +66,8 @@ DankModal { } function onIsActiveChanged() { - if (!(PolkitService.agent?.isActive ?? false)) { - close(); - } + if (!(PolkitService.agent?.isActive ?? false)) + hide(); } } @@ -86,17 +76,15 @@ DankModal { enabled: currentFlow !== null function onIsResponseRequiredChanged() { - if (currentFlow.isResponseRequired) { - isLoading = false; - passwordInput = ""; - if (contentLoader.item && contentLoader.item.passwordField) { - contentLoader.item.passwordField.forceActiveFocus(); - } - } + if (!currentFlow.isResponseRequired) + return; + isLoading = false; + passwordInput = ""; + passwordField.forceActiveFocus(); } function onAuthenticationSucceeded() { - close(); + hide(); } function onAuthenticationFailed() { @@ -104,166 +92,138 @@ DankModal { } function onAuthenticationRequestCancelled() { - close(); + hide(); } } - content: Component { - FocusScope { - id: authContent + FocusScope { + id: contentFocusScope - property alias passwordField: passwordField + anchors.fill: parent + focus: true - anchors.fill: parent - focus: true - implicitHeight: headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM + Keys.onEscapePressed: event => { + cancelAuth(); + event.accepted = true; + } - Keys.onEscapePressed: event => { - if (currentFlow && !isLoading) { - currentFlow.cancelAuthenticationRequest(); + Row { + id: headerRow + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.leftMargin: Theme.spacingM + anchors.rightMargin: Theme.spacingM + anchors.topMargin: Theme.spacingM + + Column { + width: parent.width - 40 + spacing: Theme.spacingXS + + StyledText { + text: I18n.tr("Authentication Required") + font.pixelSize: Theme.fontSizeLarge + color: Theme.surfaceText + font.weight: Font.Medium } - event.accepted = true; - } - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingM Column { - width: parent.width - 40 + width: parent.width spacing: Theme.spacingXS StyledText { - text: I18n.tr("Authentication Required") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - Column { + text: currentFlow?.message ?? "" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceTextMedium width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: currentFlow?.message ?? "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - } - - StyledText { - visible: (currentFlow?.supplementaryMessage ?? "") !== "" - text: currentFlow?.supplementaryMessage ?? "" - font.pixelSize: Theme.fontSizeSmall - color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8 - } + wrapMode: Text.Wrap } - } - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - enabled: !isLoading - opacity: enabled ? 1 : 0.5 - onClicked: () => { - if (currentFlow) { - currentFlow.cancelAuthenticationRequest(); - } + StyledText { + visible: (currentFlow?.supplementaryMessage ?? "") !== "" + text: currentFlow?.supplementaryMessage ?? "" + font.pixelSize: Theme.fontSizeSmall + color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium + width: parent.width + wrapMode: Text.Wrap + opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8 } } } - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.bottomMargin: Theme.spacingM - spacing: Theme.spacingM + DankActionButton { + iconName: "close" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + enabled: !isLoading + opacity: enabled ? 1 : 0.5 + onClicked: cancelAuth() + } + } + + Column { + id: mainColumn + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.leftMargin: Theme.spacingM + anchors.rightMargin: Theme.spacingM + anchors.bottomMargin: Theme.spacingM + spacing: Theme.spacingM + + StyledText { + text: currentFlow?.inputPrompt ?? "" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + width: parent.width + visible: (currentFlow?.inputPrompt ?? "") !== "" + } + + Rectangle { + width: parent.width + height: 50 + radius: Theme.cornerRadius + color: Theme.surfaceHover + border.color: passwordField.activeFocus ? Theme.primary : Theme.outlineStrong + border.width: passwordField.activeFocus ? 2 : 1 + opacity: isLoading ? 0.5 : 1 + + MouseArea { + anchors.fill: parent + enabled: !isLoading + onClicked: passwordField.forceActiveFocus() + } + + DankTextField { + id: passwordField + + anchors.fill: parent + font.pixelSize: Theme.fontSizeMedium + textColor: Theme.surfaceText + text: passwordInput + echoMode: (currentFlow?.responseVisible ?? false) ? TextInput.Normal : TextInput.Password + placeholderText: "" + backgroundColor: "transparent" + enabled: !isLoading + onTextEdited: passwordInput = text + onAccepted: submitAuth() + } + } + + Item { + width: parent.width + height: (currentFlow?.failed ?? false) ? failedText.implicitHeight : 0 + visible: height > 0 StyledText { - text: currentFlow?.inputPrompt ?? "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText + id: failedText + text: I18n.tr("Authentication failed, please try again") + font.pixelSize: Theme.fontSizeSmall + color: Theme.error width: parent.width - visible: (currentFlow?.inputPrompt ?? "") !== "" - } + opacity: (currentFlow?.failed ?? false) ? 1 : 0 - Rectangle { - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: passwordField.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: passwordField.activeFocus ? 2 : 1 - opacity: isLoading ? 0.5 : 1 - - MouseArea { - anchors.fill: parent - enabled: !isLoading - onClicked: () => { - passwordField.forceActiveFocus(); - } - } - - DankTextField { - id: passwordField - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: passwordInput - echoMode: (currentFlow?.responseVisible ?? false) ? TextInput.Normal : TextInput.Password - placeholderText: "" - backgroundColor: "transparent" - enabled: !isLoading - onTextEdited: () => { - passwordInput = text; - } - onAccepted: () => { - if (passwordInput.length > 0 && currentFlow && !isLoading) { - isLoading = true; - currentFlow.submit(passwordInput); - passwordInput = ""; - } - } - } - } - - Item { - width: parent.width - height: (currentFlow?.failed ?? false) ? failedText.implicitHeight : 0 - visible: height > 0 - - StyledText { - id: failedText - text: I18n.tr("Authentication failed, please try again") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - width: parent.width - opacity: (currentFlow?.failed ?? false) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on height { + Behavior on opacity { NumberAnimation { duration: Theme.shortDuration easing.type: Theme.standardEasing @@ -271,89 +231,82 @@ DankModal { } } - Item { - width: parent.width - height: 40 + Behavior on height { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } + } - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM + Item { + width: parent.width + height: 40 - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - enabled: !isLoading - opacity: enabled ? 1 : 0.5 + Row { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingM - StyledText { - id: cancelText + Rectangle { + width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) + height: 36 + radius: Theme.cornerRadius + color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" + border.color: Theme.surfaceVariantAlpha + border.width: 1 + enabled: !isLoading + opacity: enabled ? 1 : 0.5 - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: () => { - if (currentFlow) { - currentFlow.cancelAuthenticationRequest(); - } - } - } + StyledText { + id: cancelText + anchors.centerIn: parent + text: I18n.tr("Cancel") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + font.weight: Font.Medium } - Rectangle { - width: Math.max(80, authText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: authArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - enabled: !isLoading && (passwordInput.length > 0 || !(currentFlow?.isResponseRequired ?? true)) - opacity: enabled ? 1 : 0.5 + MouseArea { + id: cancelArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + enabled: parent.enabled + onClicked: cancelAuth() + } + } - StyledText { - id: authText + Rectangle { + width: Math.max(80, authText.contentWidth + Theme.spacingM * 2) + height: 36 + radius: Theme.cornerRadius + color: authArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary + enabled: !isLoading && (passwordInput.length > 0 || !(currentFlow?.isResponseRequired ?? true)) + opacity: enabled ? 1 : 0.5 - anchors.centerIn: parent - text: I18n.tr("Authenticate") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } + StyledText { + id: authText + anchors.centerIn: parent + text: I18n.tr("Authenticate") + font.pixelSize: Theme.fontSizeMedium + color: Theme.background + font.weight: Font.Medium + } - MouseArea { - id: authArea + MouseArea { + id: authArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + enabled: parent.enabled + onClicked: submitAuth() + } - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: () => { - if (currentFlow && !isLoading) { - isLoading = true; - currentFlow.submit(passwordInput); - passwordInput = ""; - } - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } + Behavior on color { + ColorAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing } } } diff --git a/quickshell/Modals/Settings/SettingsContent.qml b/quickshell/Modals/Settings/SettingsContent.qml index fb574a20..d15e16c9 100644 --- a/quickshell/Modals/Settings/SettingsContent.qml +++ b/quickshell/Modals/Settings/SettingsContent.qml @@ -129,13 +129,30 @@ FocusScope { } Loader { - id: launcherLoader + id: networkLoader anchors.fill: parent active: root.currentIndex === 6 visible: active focus: active + sourceComponent: NetworkTab {} + + onActiveChanged: { + if (active && item) { + Qt.callLater(() => item.forceActiveFocus()); + } + } + } + + Loader { + id: launcherLoader + + anchors.fill: parent + active: root.currentIndex === 7 + visible: active + focus: active + sourceComponent: LauncherTab {} onActiveChanged: { @@ -149,7 +166,7 @@ FocusScope { id: themeColorsLoader anchors.fill: parent - active: root.currentIndex === 7 + active: root.currentIndex === 8 visible: active focus: active @@ -166,7 +183,7 @@ FocusScope { id: powerLoader anchors.fill: parent - active: root.currentIndex === 8 + active: root.currentIndex === 9 visible: active focus: active @@ -183,7 +200,7 @@ FocusScope { id: pluginsLoader anchors.fill: parent - active: root.currentIndex === 9 + active: root.currentIndex === 10 visible: active focus: active @@ -202,7 +219,7 @@ FocusScope { id: aboutLoader anchors.fill: parent - active: root.currentIndex === 10 + active: root.currentIndex === 11 visible: active focus: active diff --git a/quickshell/Modals/Settings/SettingsModal.qml b/quickshell/Modals/Settings/SettingsModal.qml index 67608e48..9c1ef27e 100644 --- a/quickshell/Modals/Settings/SettingsModal.qml +++ b/quickshell/Modals/Settings/SettingsModal.qml @@ -112,7 +112,7 @@ FloatingWindow { focus: true Keys.onPressed: event => { - const tabCount = 11; + const tabCount = 12; if (event.key === Qt.Key_Escape) { hide(); event.accepted = true; diff --git a/quickshell/Modals/Settings/SettingsSidebar.qml b/quickshell/Modals/Settings/SettingsSidebar.qml index 229ed344..d5430a7f 100644 --- a/quickshell/Modals/Settings/SettingsSidebar.qml +++ b/quickshell/Modals/Settings/SettingsSidebar.qml @@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound import QtQuick import qs.Common import qs.Modals.Settings +import qs.Services import qs.Widgets Rectangle { @@ -10,59 +11,81 @@ Rectangle { property int currentIndex: 0 property var parentModal: null - readonly property var sidebarItems: [ + readonly property var allSidebarItems: [ { "text": I18n.tr("Personalization"), - "icon": "person" + "icon": "person", + "tabIndex": 0 }, { "text": I18n.tr("Time & Weather"), - "icon": "schedule" + "icon": "schedule", + "tabIndex": 1 }, { "text": I18n.tr("Dank Bar"), - "icon": "toolbar" + "icon": "toolbar", + "tabIndex": 2 }, { "text": I18n.tr("Widgets"), - "icon": "widgets" + "icon": "widgets", + "tabIndex": 3 }, { "text": I18n.tr("Dock"), - "icon": "dock_to_bottom" + "icon": "dock_to_bottom", + "tabIndex": 4 }, { "text": I18n.tr("Displays"), - "icon": "monitor" + "icon": "monitor", + "tabIndex": 5 + }, + { + "text": I18n.tr("Network"), + "icon": "wifi", + "dmsOnly": true, + "tabIndex": 6 }, { "text": I18n.tr("Launcher"), - "icon": "apps" + "icon": "apps", + "tabIndex": 7 }, { "text": I18n.tr("Theme & Colors"), - "icon": "palette" + "icon": "palette", + "tabIndex": 8 }, { "text": I18n.tr("Power & Security"), - "icon": "power" + "icon": "power", + "tabIndex": 9 }, { "text": I18n.tr("Plugins"), - "icon": "extension" + "icon": "extension", + "tabIndex": 10 }, { "text": I18n.tr("About"), - "icon": "info" + "icon": "info", + "tabIndex": 11 } ] + readonly property var sidebarItems: allSidebarItems.filter(item => !item.dmsOnly || !NetworkService.usingLegacy) function navigateNext() { - currentIndex = (currentIndex + 1) % sidebarItems.length; + const currentItemIndex = sidebarItems.findIndex(item => item.tabIndex === currentIndex); + const nextIndex = (currentItemIndex + 1) % sidebarItems.length; + currentIndex = sidebarItems[nextIndex].tabIndex; } function navigatePrevious() { - currentIndex = (currentIndex - 1 + sidebarItems.length) % sidebarItems.length; + const currentItemIndex = sidebarItems.findIndex(item => item.tabIndex === currentIndex); + const prevIndex = (currentItemIndex - 1 + sidebarItems.length) % sidebarItems.length; + currentIndex = sidebarItems[prevIndex].tabIndex; } width: 270 @@ -111,7 +134,7 @@ Rectangle { required property int index required property var modelData - property bool isActive: sidebarContainer.currentIndex === index + property bool isActive: sidebarContainer.currentIndex === modelData.tabIndex width: parent.width - parent.leftPadding - parent.rightPadding height: 44 @@ -147,7 +170,7 @@ Rectangle { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: () => { - sidebarContainer.currentIndex = index; + sidebarContainer.currentIndex = modelData.tabIndex; } } diff --git a/quickshell/Modals/WifiPasswordModal.qml b/quickshell/Modals/WifiPasswordModal.qml index 92b942e5..d3736a0a 100644 --- a/quickshell/Modals/WifiPasswordModal.qml +++ b/quickshell/Modals/WifiPasswordModal.qml @@ -1,21 +1,12 @@ import QtQuick -import Quickshell.Hyprland +import Quickshell import qs.Common -import qs.Modals.Common import qs.Services import qs.Widgets -DankModal { +FloatingWindow { id: root - layerNamespace: "dms:wifi-password" - keepPopoutsOpen: true - - HyprlandFocusGrab { - windows: [root.contentWindow] - active: CompositorService.isHyprland && root.shouldHaveFocus - } - property string wifiPasswordSSID: "" property string wifiPasswordInput: "" property string wifiUsernameInput: "" @@ -34,6 +25,34 @@ DankModal { property string connectionName: "" property string vpnServiceType: "" property string connectionType: "" + property var fieldsInfo: [] + property var secretValues: ({}) + + property int calculatedHeight: { + if (fieldsInfo.length > 0) + return 180 + (fieldsInfo.length * 60); + if (requiresEnterprise) + return 430; + if (isVpnPrompt) + return 260; + return 230; + } + + function focusFirstField() { + if (fieldsInfo.length > 0) { + if (dynamicFieldsRepeater.count > 0) { + const firstItem = dynamicFieldsRepeater.itemAt(0); + if (firstItem) + firstItem.children[0].forceActiveFocus(); + } + return; + } + if (requiresEnterprise && !isVpnPrompt) { + usernameInput.forceActiveFocus(); + return; + } + passwordInput.forceActiveFocus(); + } function show(ssid) { wifiPasswordSSID = ssid; @@ -50,23 +69,17 @@ DankModal { connectionName = ""; vpnServiceType = ""; connectionType = ""; + fieldsInfo = []; + secretValues = {}; const network = NetworkService.wifiNetworks.find(n => n.ssid === ssid); requiresEnterprise = network?.enterprise || false; - open(); - Qt.callLater(() => { - if (contentLoader.item) { - if (requiresEnterprise && contentLoader.item.usernameInput) { - contentLoader.item.usernameInput.forceActiveFocus(); - } else if (contentLoader.item.passwordInput) { - contentLoader.item.passwordInput.forceActiveFocus(); - } - } - }); + visible = true; + Qt.callLater(focusFirstField); } - function showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) { + function showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fInfo) { isPromptMode = true; promptToken = token; promptReason = reason; @@ -75,573 +88,579 @@ DankModal { connectionType = connType || "802-11-wireless"; connectionName = connName || ssid || ""; vpnServiceType = vpnService || ""; + fieldsInfo = fInfo || []; + secretValues = {}; isVpnPrompt = (connectionType === "vpn" || connectionType === "wireguard"); wifiPasswordSSID = isVpnPrompt ? connectionName : ssid; requiresEnterprise = setting === "802-1x"; - if (reason === "wrong-password") { - wifiPasswordInput = ""; - wifiUsernameInput = ""; - } else { - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - } - - open(); - Qt.callLater(() => { - if (contentLoader.item) { - if (reason === "wrong-password" && contentLoader.item.passwordInput) { - contentLoader.item.passwordInput.text = ""; - contentLoader.item.passwordInput.forceActiveFocus(); - } else if (requiresEnterprise && contentLoader.item.usernameInput) { - contentLoader.item.usernameInput.forceActiveFocus(); - } else if (contentLoader.item.passwordInput) { - contentLoader.item.passwordInput.forceActiveFocus(); - } - } - }); - } - - shouldBeVisible: false - modalWidth: 420 - modalHeight: { - if (requiresEnterprise) - return 430; - if (isVpnPrompt) - return 260; - return 230; - } - onShouldBeVisibleChanged: () => { - if (!shouldBeVisible) { - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - } - } - onOpened: { - Qt.callLater(() => { - if (contentLoader.item) { - if (requiresEnterprise && contentLoader.item.usernameInput) { - contentLoader.item.usernameInput.forceActiveFocus(); - } else if (contentLoader.item.passwordInput) { - contentLoader.item.passwordInput.forceActiveFocus(); - } - } - }); - } - onBackgroundClicked: () => { - if (isPromptMode) { - NetworkService.cancelCredentials(promptToken); - } - close(); wifiPasswordInput = ""; wifiUsernameInput = ""; wifiAnonymousIdentityInput = ""; wifiDomainInput = ""; + + visible = true; + Qt.callLater(() => { + if (reason === "wrong-password" && fieldsInfo.length === 0) { + passwordInput.text = ""; + } + focusFirstField(); + }); + } + + function hide() { + visible = false; + } + + function getFieldLabel(fieldName) { + switch (fieldName) { + case "username": + case "identity": + return I18n.tr("Username"); + case "password": + return I18n.tr("Password"); + case "cert-pass": + case "certpass": + return I18n.tr("Certificate Password"); + case "private-key-password": + return I18n.tr("Private Key Password"); + case "pin": + return I18n.tr("PIN"); + case "psk": + return I18n.tr("Password"); + case "anonymous-identity": + return I18n.tr("Anonymous Identity"); + default: + return fieldName.charAt(0).toUpperCase() + fieldName.slice(1).replace(/-/g, " "); + } + } + + function submitCredentialsAndClose() { + if (fieldsInfo.length > 0) { + NetworkService.submitCredentials(promptToken, secretValues, savePasswordCheckbox.checked); + hide(); + secretValues = {}; + return; + } + + if (isPromptMode) { + const secrets = {}; + if (isVpnPrompt) { + if (passwordInput.text) + secrets["password"] = passwordInput.text; + } else if (promptSetting === "802-11-wireless-security") { + secrets["psk"] = passwordInput.text; + } else if (promptSetting === "802-1x") { + if (usernameInput.text) + secrets["identity"] = usernameInput.text; + if (passwordInput.text) + secrets["password"] = passwordInput.text; + if (wifiAnonymousIdentityInput) + secrets["anonymous-identity"] = wifiAnonymousIdentityInput; + } + NetworkService.submitCredentials(promptToken, secrets, savePasswordCheckbox.checked); + } else { + const username = requiresEnterprise ? usernameInput.text : ""; + NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text, username, wifiAnonymousIdentityInput, wifiDomainInput); + } + + hide(); + wifiPasswordInput = ""; + wifiUsernameInput = ""; + wifiAnonymousIdentityInput = ""; + wifiDomainInput = ""; + passwordInput.text = ""; + if (requiresEnterprise) + usernameInput.text = ""; + } + + function clearAndClose() { + if (isPromptMode) + NetworkService.cancelCredentials(promptToken); + hide(); + wifiPasswordInput = ""; + wifiUsernameInput = ""; + wifiAnonymousIdentityInput = ""; + wifiDomainInput = ""; + secretValues = {}; + } + + objectName: "wifiPasswordModal" + title: isVpnPrompt ? I18n.tr("VPN Password") : I18n.tr("Wi-Fi Password") + minimumSize: Qt.size(420, calculatedHeight) + maximumSize: Qt.size(420, calculatedHeight) + color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) + visible: false + + onVisibleChanged: { + if (visible) { + Qt.callLater(focusFirstField); + return; + } + wifiPasswordInput = ""; + wifiUsernameInput = ""; + wifiAnonymousIdentityInput = ""; + wifiDomainInput = ""; + secretValues = {}; + passwordInput.text = ""; + usernameInput.text = ""; + anonInput.text = ""; + domainMatchInput.text = ""; + for (let i = 0; i < dynamicFieldsRepeater.count; i++) { + const item = dynamicFieldsRepeater.itemAt(i); + if (item?.children[0]) + item.children[0].text = ""; + } } Connections { target: NetworkService function onPasswordDialogShouldReopenChanged() { - if (NetworkService.passwordDialogShouldReopen && NetworkService.connectingSSID !== "") { - wifiPasswordSSID = NetworkService.connectingSSID; - wifiPasswordInput = ""; - open(); - NetworkService.passwordDialogShouldReopen = false; - } + if (!NetworkService.passwordDialogShouldReopen || NetworkService.connectingSSID === "") + return; + wifiPasswordSSID = NetworkService.connectingSSID; + wifiPasswordInput = ""; + visible = true; + NetworkService.passwordDialogShouldReopen = false; } } - content: Component { - FocusScope { - id: wifiContent + FocusScope { + id: contentFocusScope - property alias usernameInput: usernameInput - property alias passwordInput: passwordInput + anchors.fill: parent + focus: true - anchors.fill: parent - focus: true - Keys.onEscapePressed: event => { - if (isPromptMode) { - NetworkService.cancelCredentials(promptToken); - } - close(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - event.accepted = true; - } + Keys.onEscapePressed: event => { + clearAndClose(); + event.accepted = true; + } - Column { - anchors.centerIn: parent - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingM + Column { + id: contentCol + anchors.centerIn: parent + width: parent.width - Theme.spacingM * 2 + spacing: Theme.spacingM - Row { - width: parent.width + Row { + width: contentCol.width + + Column { + width: parent.width - 40 + spacing: Theme.spacingXS + + StyledText { + text: isVpnPrompt ? I18n.tr("Connect to VPN") : I18n.tr("Connect to Wi-Fi") + font.pixelSize: Theme.fontSizeLarge + color: Theme.surfaceText + font.weight: Font.Medium + } Column { - width: parent.width - 40 + width: parent.width spacing: Theme.spacingXS StyledText { text: { - if (isVpnPrompt) { - return I18n.tr("Connect to VPN"); - } - return I18n.tr("Connect to Wi-Fi"); + if (fieldsInfo.length > 0) + return I18n.tr("Enter credentials for ") + wifiPasswordSSID; + if (isVpnPrompt) + return I18n.tr("Enter password for ") + wifiPasswordSSID; + const prefix = requiresEnterprise ? I18n.tr("Enter credentials for ") : I18n.tr("Enter password for "); + return prefix + wifiPasswordSSID; } - font.pixelSize: Theme.fontSizeLarge + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceTextMedium + width: parent.width + elide: Text.ElideRight + } + + StyledText { + visible: isPromptMode && promptReason === "wrong-password" + text: I18n.tr("Incorrect password") + font.pixelSize: Theme.fontSizeSmall + color: Theme.error + width: parent.width + } + } + } + + DankActionButton { + iconName: "close" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + onClicked: clearAndClose() + } + } + + Repeater { + id: dynamicFieldsRepeater + model: fieldsInfo + + delegate: Rectangle { + required property var modelData + required property int index + + width: contentCol.width + height: 50 + radius: Theme.cornerRadius + color: Theme.surfaceHover + border.color: fieldInput.activeFocus ? Theme.primary : Theme.outlineStrong + border.width: fieldInput.activeFocus ? 2 : 1 + + DankTextField { + id: fieldInput + anchors.fill: parent + font.pixelSize: Theme.fontSizeMedium + textColor: Theme.surfaceText + echoMode: modelData.isSecret ? TextInput.Password : TextInput.Normal + placeholderText: getFieldLabel(modelData.name) + backgroundColor: "transparent" + enabled: root.visible + + Keys.onTabPressed: event => { + if (index < fieldsInfo.length - 1) { + const nextItem = dynamicFieldsRepeater.itemAt(index + 1); + if (nextItem) + nextItem.children[0].forceActiveFocus(); + } else { + const firstItem = dynamicFieldsRepeater.itemAt(0); + if (firstItem) + firstItem.children[0].forceActiveFocus(); + } + event.accepted = true; + } + + Keys.onBacktabPressed: event => { + if (index > 0) { + const prevItem = dynamicFieldsRepeater.itemAt(index - 1); + if (prevItem) + prevItem.children[0].forceActiveFocus(); + } else { + const lastItem = dynamicFieldsRepeater.itemAt(fieldsInfo.length - 1); + if (lastItem) + lastItem.children[0].forceActiveFocus(); + } + event.accepted = true; + } + + onTextEdited: { + let updated = Object.assign({}, root.secretValues); + updated[modelData.name] = text; + root.secretValues = updated; + } + + onAccepted: { + if (index < fieldsInfo.length - 1) { + const nextItem = dynamicFieldsRepeater.itemAt(index + 1); + if (nextItem) + nextItem.children[0].forceActiveFocus(); + return; + } + submitCredentialsAndClose(); + } + } + } + } + + Rectangle { + width: parent.width + height: 50 + radius: Theme.cornerRadius + color: Theme.surfaceHover + border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong + border.width: usernameInput.activeFocus ? 2 : 1 + visible: requiresEnterprise && !isVpnPrompt && fieldsInfo.length === 0 + + MouseArea { + anchors.fill: parent + onClicked: usernameInput.forceActiveFocus() + } + + DankTextField { + id: usernameInput + + anchors.fill: parent + font.pixelSize: Theme.fontSizeMedium + textColor: Theme.surfaceText + text: wifiUsernameInput + placeholderText: I18n.tr("Username") + backgroundColor: "transparent" + enabled: root.visible + keyNavigationTab: passwordInput + keyNavigationBacktab: domainMatchInput + onTextEdited: wifiUsernameInput = text + onAccepted: passwordInput.forceActiveFocus() + } + } + + Rectangle { + width: parent.width + height: 50 + radius: Theme.cornerRadius + color: Theme.surfaceHover + border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong + border.width: passwordInput.activeFocus ? 2 : 1 + visible: fieldsInfo.length === 0 + + MouseArea { + anchors.fill: parent + onClicked: passwordInput.forceActiveFocus() + } + + DankTextField { + id: passwordInput + + anchors.fill: parent + font.pixelSize: Theme.fontSizeMedium + textColor: Theme.surfaceText + text: wifiPasswordInput + echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password + placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : "" + backgroundColor: "transparent" + enabled: root.visible + keyNavigationTab: (requiresEnterprise && !isVpnPrompt) ? anonInput : null + keyNavigationBacktab: (requiresEnterprise && !isVpnPrompt) ? usernameInput : null + onTextEdited: wifiPasswordInput = text + onAccepted: { + if (requiresEnterprise && !isVpnPrompt) { + anonInput.forceActiveFocus(); + return; + } + submitCredentialsAndClose(); + } + } + } + + Rectangle { + visible: requiresEnterprise && !isVpnPrompt + width: parent.width + height: 50 + radius: Theme.cornerRadius + color: Theme.surfaceHover + border.color: anonInput.activeFocus ? Theme.primary : Theme.outlineStrong + border.width: anonInput.activeFocus ? 2 : 1 + + MouseArea { + anchors.fill: parent + onClicked: anonInput.forceActiveFocus() + } + + DankTextField { + id: anonInput + + anchors.fill: parent + font.pixelSize: Theme.fontSizeMedium + textColor: Theme.surfaceText + text: wifiAnonymousIdentityInput + placeholderText: I18n.tr("Anonymous Identity (optional)") + backgroundColor: "transparent" + enabled: root.visible + keyNavigationTab: domainMatchInput + keyNavigationBacktab: passwordInput + onTextEdited: wifiAnonymousIdentityInput = text + onAccepted: domainMatchInput.forceActiveFocus() + } + } + + Rectangle { + visible: requiresEnterprise && !isVpnPrompt + width: parent.width + height: 50 + radius: Theme.cornerRadius + color: Theme.surfaceHover + border.color: domainMatchInput.activeFocus ? Theme.primary : Theme.outlineStrong + border.width: domainMatchInput.activeFocus ? 2 : 1 + + MouseArea { + anchors.fill: parent + onClicked: domainMatchInput.forceActiveFocus() + } + + DankTextField { + id: domainMatchInput + + anchors.fill: parent + font.pixelSize: Theme.fontSizeMedium + textColor: Theme.surfaceText + text: wifiDomainInput + placeholderText: I18n.tr("Domain (optional)") + backgroundColor: "transparent" + enabled: root.visible + keyNavigationTab: usernameInput + keyNavigationBacktab: anonInput + onTextEdited: wifiDomainInput = text + onAccepted: submitCredentialsAndClose() + } + } + + Column { + spacing: Theme.spacingS + width: parent.width + + Row { + spacing: Theme.spacingS + visible: fieldsInfo.length === 0 + + Rectangle { + id: showPasswordCheckbox + + property bool checked: false + + width: 20 + height: 20 + radius: 4 + color: checked ? Theme.primary : "transparent" + border.color: checked ? Theme.primary : Theme.outlineButton + border.width: 2 + + DankIcon { + anchors.centerIn: parent + name: "check" + size: 12 + color: Theme.background + visible: parent.checked + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: showPasswordCheckbox.checked = !showPasswordCheckbox.checked + } + } + + StyledText { + text: I18n.tr("Show password") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + Row { + spacing: Theme.spacingS + visible: isVpnPrompt || fieldsInfo.length > 0 + + Rectangle { + id: savePasswordCheckbox + + property bool checked: false + + width: 20 + height: 20 + radius: 4 + color: checked ? Theme.primary : "transparent" + border.color: checked ? Theme.primary : Theme.outlineButton + border.width: 2 + + DankIcon { + anchors.centerIn: parent + name: "check" + size: 12 + color: Theme.background + visible: parent.checked + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked + } + } + + StyledText { + text: I18n.tr("Save password") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + } + + Item { + width: parent.width + height: 40 + + Row { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingM + + Rectangle { + width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) + height: 36 + radius: Theme.cornerRadius + color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" + border.color: Theme.surfaceVariantAlpha + border.width: 1 + + StyledText { + id: cancelText + anchors.centerIn: parent + text: I18n.tr("Cancel") + font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceText font.weight: Font.Medium } - Column { - width: parent.width - spacing: Theme.spacingXS + MouseArea { + id: cancelArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: clearAndClose() + } + } - StyledText { - text: { - if (isVpnPrompt) { - return I18n.tr("Enter password for ") + wifiPasswordSSID; - } - const prefix = requiresEnterprise ? I18n.tr("Enter credentials for ") : I18n.tr("Enter password for "); - return prefix + wifiPasswordSSID; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - elide: Text.ElideRight - } - - StyledText { - visible: isPromptMode && promptReason === "wrong-password" - text: I18n.tr("Incorrect password") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - width: parent.width - } - } - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: () => { - if (isPromptMode) { - NetworkService.cancelCredentials(promptToken); - } - close(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - } - } - } - - Rectangle { - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: usernameInput.activeFocus ? 2 : 1 - visible: requiresEnterprise && !isVpnPrompt - - MouseArea { - anchors.fill: parent - onClicked: () => { - usernameInput.forceActiveFocus(); - } - } - - DankTextField { - id: usernameInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiUsernameInput - placeholderText: I18n.tr("Username") - backgroundColor: "transparent" - enabled: root.shouldBeVisible - onTextEdited: () => { - wifiUsernameInput = text; - } - onAccepted: () => { - if (passwordInput) { - passwordInput.forceActiveFocus(); - } - } - } - } - - Rectangle { - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: passwordInput.activeFocus ? 2 : 1 - - MouseArea { - anchors.fill: parent - onClicked: () => { - passwordInput.forceActiveFocus(); - } - } - - DankTextField { - id: passwordInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiPasswordInput - echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password - placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : "" - backgroundColor: "transparent" - focus: !requiresEnterprise - enabled: root.shouldBeVisible - onTextEdited: () => { - wifiPasswordInput = text; - } - onAccepted: () => { - if (isPromptMode) { - const secrets = {}; - if (isVpnPrompt) { - if (passwordInput.text) - secrets["password"] = passwordInput.text; - } else if (promptSetting === "802-11-wireless-security") { - secrets["psk"] = passwordInput.text; - } else if (promptSetting === "802-1x") { - if (usernameInput.text) - secrets["identity"] = usernameInput.text; - if (passwordInput.text) - secrets["password"] = passwordInput.text; - if (wifiAnonymousIdentityInput) - secrets["anonymous-identity"] = wifiAnonymousIdentityInput; - } - NetworkService.submitCredentials(promptToken, secrets, savePasswordCheckbox.checked); - } else { - const username = requiresEnterprise ? usernameInput.text : ""; - NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text, username, wifiAnonymousIdentityInput, wifiDomainInput); - } - close(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - passwordInput.text = ""; - if (requiresEnterprise) - usernameInput.text = ""; - } - Component.onCompleted: () => { - if (root.shouldBeVisible && !requiresEnterprise) - focusDelayTimer.start(); - } - - Timer { - id: focusDelayTimer - - interval: 100 - repeat: false - onTriggered: () => { - if (root.shouldBeVisible) { - if (requiresEnterprise && usernameInput) { - usernameInput.forceActiveFocus(); - } else { - passwordInput.forceActiveFocus(); - } - } - } - } - - Connections { - target: root - - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) - focusDelayTimer.start(); - } - } - } - } - - Rectangle { - visible: requiresEnterprise && !isVpnPrompt - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: anonInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: anonInput.activeFocus ? 2 : 1 - - MouseArea { - anchors.fill: parent - onClicked: () => { - anonInput.forceActiveFocus(); - } - } - - DankTextField { - id: anonInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiAnonymousIdentityInput - placeholderText: I18n.tr("Anonymous Identity (optional)") - backgroundColor: "transparent" - enabled: root.shouldBeVisible - onTextEdited: () => { - wifiAnonymousIdentityInput = text; - } - } - } - - Rectangle { - visible: requiresEnterprise && !isVpnPrompt - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceHover - border.color: domainMatchInput.activeFocus ? Theme.primary : Theme.outlineStrong - border.width: domainMatchInput.activeFocus ? 2 : 1 - - MouseArea { - anchors.fill: parent - onClicked: () => { - domainMatchInput.forceActiveFocus(); - } - } - - DankTextField { - id: domainMatchInput - - anchors.fill: parent - font.pixelSize: Theme.fontSizeMedium - textColor: Theme.surfaceText - text: wifiDomainInput - placeholderText: I18n.tr("Domain (optional)") - backgroundColor: "transparent" - enabled: root.shouldBeVisible - onTextEdited: () => { - wifiDomainInput = text; - } - } - } - - Column { - spacing: Theme.spacingS - width: parent.width - - Row { - spacing: Theme.spacingS - - Rectangle { - id: showPasswordCheckbox - - property bool checked: false - - width: 20 - height: 20 - radius: 4 - color: checked ? Theme.primary : "transparent" - border.color: checked ? Theme.primary : Theme.outlineButton - border.width: 2 - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 12 - color: Theme.background - visible: parent.checked - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - showPasswordCheckbox.checked = !showPasswordCheckbox.checked; + Rectangle { + width: Math.max(80, connectText.contentWidth + Theme.spacingM * 2) + height: 36 + radius: Theme.cornerRadius + color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary + enabled: { + if (fieldsInfo.length > 0) { + for (let i = 0; i < fieldsInfo.length; i++) { + if (!fieldsInfo[i].isSecret) + continue; + const fieldName = fieldsInfo[i].name; + if (!secretValues[fieldName] || secretValues[fieldName].length === 0) + return false; } + return true; } + if (isVpnPrompt) + return passwordInput.text.length > 0; + return requiresEnterprise ? (usernameInput.text.length > 0 && passwordInput.text.length > 0) : passwordInput.text.length > 0; } + opacity: enabled ? 1 : 0.5 StyledText { - text: I18n.tr("Show password") + id: connectText + anchors.centerIn: parent + text: I18n.tr("Connect") font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - spacing: Theme.spacingS - visible: isVpnPrompt - - Rectangle { - id: savePasswordCheckbox - - property bool checked: false - - width: 20 - height: 20 - radius: 4 - color: checked ? Theme.primary : "transparent" - border.color: checked ? Theme.primary : Theme.outlineButton - border.width: 2 - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 12 - color: Theme.background - visible: parent.checked - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - savePasswordCheckbox.checked = !savePasswordCheckbox.checked; - } - } + color: Theme.background + font.weight: Font.Medium } - StyledText { - text: I18n.tr("Save password") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Item { - width: parent.width - height: 40 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: cancelText - - anchors.centerIn: parent - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: cancelArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - if (isPromptMode) { - NetworkService.cancelCredentials(promptToken); - } - close(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - } - } + MouseArea { + id: connectArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + enabled: parent.enabled + onClicked: submitCredentialsAndClose() } - Rectangle { - width: Math.max(80, connectText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - enabled: { - if (isVpnPrompt) { - return passwordInput.text.length > 0; - } - return requiresEnterprise ? (usernameInput.text.length > 0 && passwordInput.text.length > 0) : passwordInput.text.length > 0; - } - opacity: enabled ? 1 : 0.5 - - StyledText { - id: connectText - - anchors.centerIn: parent - text: I18n.tr("Connect") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: connectArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: () => { - if (isPromptMode) { - const secrets = {}; - if (isVpnPrompt) { - if (passwordInput.text) - secrets["password"] = passwordInput.text; - } else if (promptSetting === "802-11-wireless-security") { - secrets["psk"] = passwordInput.text; - } else if (promptSetting === "802-1x") { - if (usernameInput.text) - secrets["identity"] = usernameInput.text; - if (passwordInput.text) - secrets["password"] = passwordInput.text; - if (wifiAnonymousIdentityInput) - secrets["anonymous-identity"] = wifiAnonymousIdentityInput; - } - NetworkService.submitCredentials(promptToken, secrets, savePasswordCheckbox.checked); - } else { - const username = requiresEnterprise ? usernameInput.text : ""; - NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text, username, wifiAnonymousIdentityInput, wifiDomainInput); - } - close(); - wifiPasswordInput = ""; - wifiUsernameInput = ""; - wifiAnonymousIdentityInput = ""; - wifiDomainInput = ""; - passwordInput.text = ""; - if (requiresEnterprise) - usernameInput.text = ""; - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } + Behavior on color { + ColorAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing } } } diff --git a/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml b/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml index 0c34d123..57850c40 100644 --- a/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml +++ b/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml @@ -1,6 +1,4 @@ import QtQuick -import QtQuick.Layouts -import Quickshell import qs.Common import qs.Services import qs.Widgets @@ -13,239 +11,23 @@ PluginComponent { service: DMSNetworkService } - ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off") ccWidgetPrimaryText: "VPN" ccWidgetSecondaryText: { if (!DMSNetworkService.connected) - return "Disconnected" - const names = DMSNetworkService.activeNames || [] + return I18n.tr("Disconnected"); + const names = DMSNetworkService.activeNames || []; if (names.length <= 1) - return names[0] || "Connected" - return names[0] + " +" + (names.length - 1) + return names[0] || I18n.tr("Connected"); + return names[0] + " +" + (names.length - 1); } ccWidgetIsActive: DMSNetworkService.connected - onCcWidgetToggled: { - DMSNetworkService.toggleVpn() - } + onCcWidgetToggled: DMSNetworkService.toggleVpn() ccDetailContent: Component { - Rectangle { - id: detailRoot - implicitHeight: detailColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Column { - id: detailColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - RowLayout { - spacing: Theme.spacingS - width: parent.width - - StyledText { - text: { - if (!DMSNetworkService.connected) - return "Active: None" - const names = DMSNetworkService.activeNames || [] - if (names.length <= 1) - return "Active: " + (names[0] || "VPN") - return "Active: " + names[0] + " +" + (names.length - 1) - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - Layout.fillWidth: true - Layout.maximumWidth: parent.width - 120 - } - - Rectangle { - height: 28 - radius: 14 - color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: DMSNetworkService.connected - width: 110 - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "link_off" - size: Theme.fontSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Disconnect") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: discAllArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.disconnectAllActive() - } - } - } - - Rectangle { - height: 1 - width: parent.width - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - DankFlickable { - width: parent.width - height: 160 - contentHeight: listCol.height - clip: true - - Column { - id: listCol - width: parent.width - spacing: Theme.spacingXS - - Item { - width: parent.width - height: DMSNetworkService.profiles.length === 0 ? 120 : 0 - visible: height > 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "playlist_remove" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No VPN profiles found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Add a VPN in NetworkManager") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Repeater { - model: DMSNetworkService.profiles - - delegate: Rectangle { - required property var modelData - - width: parent ? parent.width : 300 - height: 50 - radius: Theme.cornerRadius - color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight) - border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1 - border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: DMSNetworkService.isActiveUuid(modelData.uuid) ? "vpn_lock" : "vpn_key_off" - size: Theme.iconSize - 4 - color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText - Layout.alignment: Qt.AlignVCenter - } - - Column { - spacing: 2 - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - if (modelData.type === "wireguard") - return "WireGuard" - const svc = modelData.serviceType || "" - if (svc.indexOf("openvpn") !== -1) - return "OpenVPN" - if (svc.indexOf("wireguard") !== -1) - return "WireGuard (plugin)" - if (svc.indexOf("openconnect") !== -1) - return "OpenConnect" - if (svc.indexOf("fortissl") !== -1 || svc.indexOf("forti") !== -1) - return "Fortinet" - if (svc.indexOf("strongswan") !== -1) - return "IPsec (strongSwan)" - if (svc.indexOf("libreswan") !== -1) - return "IPsec (Libreswan)" - if (svc.indexOf("l2tp") !== -1) - return "L2TP/IPsec" - if (svc.indexOf("pptp") !== -1) - return "PPTP" - if (svc.indexOf("vpnc") !== -1) - return "Cisco (vpnc)" - if (svc.indexOf("sstp") !== -1) - return "SSTP" - if (svc) - return svc.split('.').pop() - return "VPN" - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Item { - Layout.fillWidth: true - } - } - - MouseArea { - id: rowArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.toggle(modelData.uuid) - } - } - } - } - } - } + VpnDetailContent { + listHeight: 180 } } } diff --git a/quickshell/Modules/ControlCenter/ControlCenterPopout.qml b/quickshell/Modules/ControlCenter/ControlCenterPopout.qml index c41c37f5..ff240c62 100644 --- a/quickshell/Modules/ControlCenter/ControlCenterPopout.qml +++ b/quickshell/Modules/ControlCenter/ControlCenterPopout.qml @@ -65,13 +65,16 @@ DankPopout { shouldBeVisible: false property bool credentialsPromptOpen: NetworkService.credentialsRequested + property bool wifiPasswordModalOpen: PopoutService.wifiPasswordModal?.visible ?? false + property bool polkitModalOpen: PopoutService.polkitAuthModal?.visible ?? false + property bool anyModalOpen: credentialsPromptOpen || wifiPasswordModalOpen || polkitModalOpen || powerMenuOpen + + backgroundInteractive: !anyModalOpen customKeyboardFocus: { if (!shouldBeVisible) return WlrKeyboardFocus.None; - if (powerMenuOpen) - return WlrKeyboardFocus.None; - if (credentialsPromptOpen) + if (anyModalOpen) return WlrKeyboardFocus.None; if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand; diff --git a/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml b/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml index fd5cc62a..9509154e 100644 --- a/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml +++ b/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml @@ -353,8 +353,9 @@ Rectangle { } MenuItem { - text: "Activate" + text: I18n.tr("Activate") height: !wiredNetworkContextMenu.currentConnected ? 32 : 0 + visible: !wiredNetworkContextMenu.currentConnected contentItem: StyledText { text: parent.text @@ -370,15 +371,39 @@ Rectangle { } onTriggered: { - if (!networkContextMenu.currentConnected) { + if (!wiredNetworkContextMenu.currentConnected) { NetworkService.connectToSpecificWiredConfig(wiredNetworkContextMenu.currentUUID); } } } + MenuItem { + text: I18n.tr("Disconnect") + height: wiredNetworkContextMenu.currentConnected ? 32 : 0 + visible: wiredNetworkContextMenu.currentConnected + + contentItem: StyledText { + text: parent.text + font.pixelSize: Theme.fontSizeSmall + color: Theme.error + leftPadding: Theme.spacingS + verticalAlignment: Text.AlignVCenter + } + + background: Rectangle { + color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" + radius: Theme.cornerRadius / 2 + } + + onTriggered: { + NetworkService.toggleNetworkConnection("ethernet"); + } + } + MenuItem { text: I18n.tr("Network Info") height: wiredNetworkContextMenu.currentConnected ? 32 : 0 + visible: wiredNetworkContextMenu.currentConnected contentItem: StyledText { text: parent.text diff --git a/quickshell/Modules/DankBar/Popouts/VpnPopout.qml b/quickshell/Modules/DankBar/Popouts/VpnPopout.qml index d0b14ad0..10755688 100644 --- a/quickshell/Modules/DankBar/Popouts/VpnPopout.qml +++ b/quickshell/Modules/DankBar/Popouts/VpnPopout.qml @@ -1,11 +1,5 @@ -// No external details import; content inlined for consistency - import QtQuick -import QtQuick.Controls import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets import qs.Common import qs.Services import qs.Widgets @@ -20,22 +14,21 @@ DankPopout { } property bool wasVisible: false - - onShouldBeVisibleChanged: { - if (shouldBeVisible && !wasVisible) { - DMSNetworkService.getState() - } - wasVisible = shouldBeVisible - } - property var triggerScreen: null - popupWidth: 360 - popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260) + popupWidth: 380 + popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 320) triggerWidth: 70 screen: triggerScreen shouldBeVisible: false + onShouldBeVisibleChanged: { + if (shouldBeVisible && !wasVisible) { + DMSNetworkService.getState(); + } + wasVisible = shouldBeVisible; + } + onBackgroundClicked: close() content: Component { @@ -47,46 +40,15 @@ DankPopout { radius: Theme.cornerRadius border.color: Theme.outlineMedium border.width: 0 - antialiasing: true - smooth: true focus: true - Keys.onPressed: function(event) { + + Keys.onPressed: event => { if (event.key === Qt.Key_Escape) { root.close(); event.accepted = true; } } - // Outer subtle shadow rings to match BatteryPopout - Rectangle { - anchors.fill: parent - anchors.margins: -3 - color: "transparent" - radius: parent.radius + 3 - border.color: Qt.rgba(0, 0, 0, 0.05) - border.width: 0 - z: -3 - } - - Rectangle { - anchors.fill: parent - anchors.margins: -2 - color: "transparent" - radius: parent.radius + 2 - border.color: Theme.shadowMedium - border.width: 0 - z: -2 - } - - Rectangle { - anchors.fill: parent - color: "transparent" - border.color: Theme.outlineStrong - border.width: 0 - radius: parent.radius - z: -1 - } - Column { id: contentColumn @@ -96,334 +58,33 @@ DankPopout { anchors.margins: Theme.spacingL spacing: Theme.spacingM - Item { + RowLayout { width: parent.width height: 32 + spacing: Theme.spacingS StyledText { text: I18n.tr("VPN Connections") font.pixelSize: Theme.fontSizeLarge color: Theme.surfaceText font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter + Layout.fillWidth: true } - // Close button (matches BatteryPopout) - Rectangle { - width: 32 - height: 32 - radius: 16 - color: closeArea.containsMouse ? Theme.errorHover : "transparent" - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "close" - size: Theme.iconSize - 4 - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: root.close() - } - + DankActionButton { + iconName: "close" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + onClicked: root.close() } - } - // Inlined VPN details - Rectangle { - id: vpnDetail - + VpnDetailContent { width: parent.width - implicitHeight: detailsColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Theme.outlineStrong - border.width: 0 - clip: true - - Column { - id: detailsColumn - - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - RowLayout { - spacing: Theme.spacingS - width: parent.width - - StyledText { - text: { - if (!DMSNetworkService.connected) { - return "Active: None"; - } - - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) { - return "Active: " + (names[0] || "VPN"); - } - - return "Active: " + names[0] + " +" + (names.length - 1); - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - Layout.fillWidth: true - Layout.maximumWidth: parent.width - 140 - } - - // Removed Quick Connect for clarity - Item { - width: 1 - height: 1 - } - - // Disconnect all (shown only when any active) - Rectangle { - height: 28 - radius: 14 - color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: DMSNetworkService.connected - width: 130 - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - border.width: 0 - border.color: Theme.outlineLight - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "link_off" - size: Theme.fontSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Disconnect") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - - } - - MouseArea { - id: discAllArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.disconnectAllActive() - } - - } - - } - - Rectangle { - height: 1 - width: parent.width - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - DankFlickable { - width: parent.width - height: 160 - contentHeight: listCol.height - clip: true - - Column { - id: listCol - - width: parent.width - spacing: Theme.spacingXS - - Item { - width: parent.width - height: DMSNetworkService.profiles.length === 0 ? 120 : 0 - visible: height > 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "playlist_remove" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No VPN profiles found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Add a VPN in NetworkManager") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - } - - } - - Repeater { - model: DMSNetworkService.profiles - - delegate: Rectangle { - required property var modelData - - width: parent ? parent.width : 300 - height: 50 - radius: Theme.cornerRadius - color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight) - border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1 - border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: DMSNetworkService.isActiveUuid(modelData.uuid) ? "vpn_lock" : "vpn_key_off" - size: Theme.iconSize - 4 - color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText - Layout.alignment: Qt.AlignVCenter - } - - Column { - spacing: 2 - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - if (modelData.type === "wireguard") { - return "WireGuard"; - } - - const svc = modelData.serviceType || ""; - if (svc.indexOf("openvpn") !== -1) { - return "OpenVPN"; - } - - if (svc.indexOf("wireguard") !== -1) { - return "WireGuard (plugin)"; - } - - if (svc.indexOf("openconnect") !== -1) { - return "OpenConnect"; - } - - if (svc.indexOf("fortissl") !== -1 || svc.indexOf("forti") !== -1) { - return "Fortinet"; - } - - if (svc.indexOf("strongswan") !== -1) { - return "IPsec (strongSwan)"; - } - - if (svc.indexOf("libreswan") !== -1) { - return "IPsec (Libreswan)"; - } - - if (svc.indexOf("l2tp") !== -1) { - return "L2TP/IPsec"; - } - - if (svc.indexOf("pptp") !== -1) { - return "PPTP"; - } - - if (svc.indexOf("vpnc") !== -1) { - return "Cisco (vpnc)"; - } - - if (svc.indexOf("sstp") !== -1) { - return "SSTP"; - } - - if (svc) { - const parts = svc.split('.'); - return parts[parts.length - 1]; - } - return "VPN"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - - } - - Item { - Layout.fillWidth: true - height: 1 - } - - } - - MouseArea { - id: rowArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.toggle(modelData.uuid) - } - - } - - } - - Item { - height: 1 - width: 1 - } - - } - - } - - } - + listHeight: 200 + parentPopout: root } - } - } - } - } diff --git a/quickshell/Modules/Settings/NetworkTab.qml b/quickshell/Modules/Settings/NetworkTab.qml new file mode 100644 index 00000000..a87d52a7 --- /dev/null +++ b/quickshell/Modules/Settings/NetworkTab.qml @@ -0,0 +1,1839 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Common +import qs.Modals.Common +import qs.Modals.FileBrowser +import qs.Services +import qs.Widgets + +Item { + id: networkTab + + property string expandedVpnUuid: "" + property string expandedWifiSsid: "" + property string expandedEthDevice: "" + + Component.onCompleted: { + NetworkService.addRef(); + } + + Component.onDestruction: { + NetworkService.removeRef(); + } + + FileBrowserSurfaceModal { + id: vpnFileBrowser + browserTitle: I18n.tr("Import VPN") + browserIcon: "vpn_key" + browserType: "vpn" + fileExtensions: VPNService.getFileFilter() + + onFileSelected: path => { + VPNService.importVpn(path.replace("file://", "")); + } + } + + ConfirmModal { + id: deleteVpnConfirm + } + + ConfirmModal { + id: forgetNetworkConfirm + } + + DankFlickable { + anchors.fill: parent + clip: true + contentHeight: mainColumn.height + Theme.spacingXL + contentWidth: width + + Column { + id: mainColumn + + width: Math.min(600, parent.width - Theme.spacingL * 2) + anchors.horizontalCenter: parent.horizontalCenter + spacing: Theme.spacingL + + StyledRect { + width: parent.width + height: overviewSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + + Column { + id: overviewSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: "lan" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - Theme.spacingM + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: I18n.tr("Network Status") + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + } + + StyledText { + text: I18n.tr("Overview of your network connections") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + + Rectangle { + width: parent.width + height: 1 + color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) + } + + Grid { + columns: 2 + columnSpacing: Theme.spacingL + rowSpacing: Theme.spacingS + width: parent.width + + StyledText { + text: I18n.tr("Backend") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + } + StyledText { + text: NetworkService.backend || I18n.tr("Unknown") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + font.weight: Font.Medium + } + + StyledText { + text: I18n.tr("Status") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + } + Row { + spacing: Theme.spacingS + + Rectangle { + width: 8 + height: 8 + radius: 4 + anchors.verticalCenter: parent.verticalCenter + color: { + switch (NetworkService.networkStatus) { + case "ethernet": + case "wifi": + return Theme.success; + case "disconnected": + return Theme.error; + default: + return Theme.warning; + } + } + } + + StyledText { + text: { + switch (NetworkService.networkStatus) { + case "ethernet": + return I18n.tr("Ethernet"); + case "wifi": + return I18n.tr("WiFi"); + case "disconnected": + return I18n.tr("Disconnected"); + default: + return NetworkService.networkStatus || I18n.tr("Unknown"); + } + } + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + font.weight: Font.Medium + } + } + + StyledText { + text: I18n.tr("Primary") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + visible: NetworkService.primaryConnection.length > 0 + } + StyledText { + text: NetworkService.primaryConnection || "-" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + elide: Text.ElideRight + visible: NetworkService.primaryConnection.length > 0 + } + } + + Row { + width: parent.width + spacing: Theme.spacingM + visible: NetworkService.backend === "networkmanager" && NetworkService.ethernetConnected && NetworkService.wifiConnected + + StyledText { + text: I18n.tr("Preference") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + Item { + width: parent.width - preferenceLabel.width - preferenceButtons.width - Theme.spacingM * 2 + height: 1 + } + + DankButtonGroup { + id: preferenceButtons + model: [I18n.tr("Auto"), I18n.tr("Ethernet"), I18n.tr("WiFi")] + currentIndex: { + switch (NetworkService.userPreference) { + case "ethernet": + return 1; + case "wifi": + return 2; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + switch (index) { + case 0: + NetworkService.setNetworkPreference("auto"); + break; + case 1: + NetworkService.setNetworkPreference("ethernet"); + break; + case 2: + NetworkService.setNetworkPreference("wifi"); + break; + } + } + } + } + + StyledText { + id: preferenceLabel + visible: false + text: I18n.tr("Preference") + } + } + } + + StyledRect { + width: parent.width + height: ethernetSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + visible: NetworkService.ethernetConnected || (NetworkService.ethernetDevices?.length ?? 0) > 0 + + Column { + id: ethernetSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: "settings_ethernet" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - Theme.spacingM + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: I18n.tr("Ethernet") + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + } + + StyledText { + text: { + const devices = NetworkService.ethernetDevices; + const connected = devices.filter(d => d.connected).length; + if (devices.length === 0) + return I18n.tr("No adapters"); + if (connected === 0) + return I18n.tr("%1 adapter(s), none connected").arg(devices.length); + return I18n.tr("%1 connected").arg(connected); + } + font.pixelSize: Theme.fontSizeSmall + color: NetworkService.ethernetConnected ? Theme.success : Theme.surfaceVariantText + } + } + } + + Rectangle { + width: parent.width + height: 1 + color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) + } + + Column { + width: parent.width + spacing: 4 + visible: NetworkService.ethernetDevices.length > 0 + + StyledText { + text: I18n.tr("Adapters") + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + color: Theme.surfaceText + } + + Repeater { + model: NetworkService.ethernetDevices + + delegate: Rectangle { + id: ethDeviceDelegate + required property var modelData + required property int index + + readonly property bool isConnected: modelData.connected || false + readonly property bool isExpanded: networkTab.expandedEthDevice === modelData.name + + width: parent.width + height: isExpanded ? 56 + ethExpandedContent.height : 56 + radius: Theme.cornerRadius + color: ethDeviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight + border.width: isConnected ? 2 : 0 + border.color: Theme.primary + clip: true + + Behavior on height { + NumberAnimation { + duration: 150 + easing.type: Easing.OutQuad + } + } + + Column { + anchors.fill: parent + spacing: 0 + + Item { + width: parent.width + height: 56 + + Row { + anchors.left: parent.left + anchors.leftMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + anchors.right: ethDeviceActions.left + anchors.rightMargin: Theme.spacingS + spacing: Theme.spacingS + + DankIcon { + name: "lan" + size: 20 + color: isConnected ? Theme.primary : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: 2 + width: parent.width - 20 - Theme.spacingS + + StyledText { + text: modelData.name || I18n.tr("Unknown") + font.pixelSize: Theme.fontSizeMedium + color: isConnected ? Theme.primary : Theme.surfaceText + font.weight: isConnected ? Font.Medium : Font.Normal + elide: Text.ElideRight + width: parent.width + } + + Row { + spacing: Theme.spacingXS + + StyledText { + text: { + switch (modelData.state) { + case "activated": + return I18n.tr("Connected"); + case "disconnected": + return I18n.tr("Disconnected"); + case "unavailable": + return I18n.tr("Unavailable"); + default: + return modelData.state || I18n.tr("Unknown"); + } + } + font.pixelSize: Theme.fontSizeSmall + color: isConnected ? Theme.primary : Theme.surfaceVariantText + } + + StyledText { + text: "•" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + visible: modelData.ip && modelData.ip.length > 0 + } + + StyledText { + text: modelData.ip || "" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + visible: modelData.ip && modelData.ip.length > 0 + } + + StyledText { + text: "•" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + visible: modelData.speed && modelData.speed > 0 + } + + StyledText { + text: modelData.speed ? modelData.speed + " Mbps" : "" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + visible: modelData.speed && modelData.speed > 0 + } + } + } + } + + Row { + id: ethDeviceActions + anchors.right: parent.right + anchors.rightMargin: Theme.spacingS + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingXS + + Rectangle { + width: 28 + height: 28 + radius: 14 + color: ethExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" + visible: isConnected + + DankIcon { + anchors.centerIn: parent + name: isExpanded ? "expand_less" : "expand_more" + size: 18 + color: Theme.surfaceText + } + + MouseArea { + id: ethExpandBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + if (isExpanded) { + networkTab.expandedEthDevice = ""; + } else { + networkTab.expandedEthDevice = modelData.name; + NetworkService.fetchWiredNetworkInfo(NetworkService.ethernetConnectionUuid); + } + } + } + } + + Rectangle { + width: 28 + height: 28 + radius: 14 + color: ethDisconnectBtn.containsMouse ? Theme.errorHover : "transparent" + visible: isConnected + + DankIcon { + anchors.centerIn: parent + name: "link_off" + size: 18 + color: ethDisconnectBtn.containsMouse ? Theme.error : Theme.surfaceVariantText + } + + MouseArea { + id: ethDisconnectBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: NetworkService.disconnectEthernetDevice(modelData.name) + } + } + } + + MouseArea { + id: ethDeviceMouseArea + anchors.fill: parent + anchors.rightMargin: ethDeviceActions.width + Theme.spacingM + hoverEnabled: true + } + } + + Column { + id: ethExpandedContent + width: parent.width + visible: isExpanded + + Rectangle { + width: parent.width - Theme.spacingM * 2 + height: 1 + x: Theme.spacingM + color: Theme.outlineLight + } + + Item { + width: parent.width + height: ethDetailsColumn.implicitHeight + Theme.spacingM * 2 + + Column { + id: ethDetailsColumn + anchors.fill: parent + anchors.margins: Theme.spacingM + spacing: Theme.spacingS + + Flow { + width: parent.width + spacing: Theme.spacingXS + + Repeater { + model: { + const fields = []; + const dev = modelData; + if (!dev) + return fields; + + if (dev.ip) + fields.push({ + label: I18n.tr("IP"), + value: dev.ip + }); + if (dev.speed && dev.speed > 0) + fields.push({ + label: I18n.tr("Speed"), + value: dev.speed + " Mbps" + }); + if (dev.hwAddress) + fields.push({ + label: I18n.tr("MAC"), + value: dev.hwAddress + }); + if (dev.driver) + fields.push({ + label: I18n.tr("Driver"), + value: dev.driver + }); + fields.push({ + label: I18n.tr("State"), + value: dev.state || I18n.tr("Unknown") + }); + + return fields; + } + + delegate: Rectangle { + required property var modelData + required property int index + + width: ethFieldContent.width + Theme.spacingM * 2 + height: 32 + radius: Theme.cornerRadius - 2 + color: Theme.surfaceContainerHigh + border.width: 1 + border.color: Theme.outlineLight + + Row { + id: ethFieldContent + anchors.centerIn: parent + spacing: Theme.spacingXS + + StyledText { + text: modelData.label + ":" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: modelData.value + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + } + + Item { + width: parent.width + height: NetworkService.networkWiredInfoLoading ? 40 : 0 + visible: NetworkService.networkWiredInfoLoading + + Row { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "sync" + size: 16 + color: Theme.surfaceVariantText + + RotationAnimation on rotation { + running: NetworkService.networkWiredInfoLoading + loops: Animation.Infinite + from: 0 + to: 360 + duration: 1000 + } + } + + StyledText { + text: I18n.tr("Loading...") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + } + } + } + } + } + } + } + + Column { + width: parent.width + spacing: Theme.spacingS + visible: NetworkService.wiredConnections.length > 0 + + Rectangle { + width: parent.width + height: 1 + color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) + } + + StyledText { + text: I18n.tr("Saved Configurations") + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + color: Theme.surfaceText + } + + Repeater { + model: NetworkService.wiredConnections + + delegate: Rectangle { + required property var modelData + required property int index + + width: parent.width + height: 48 + radius: Theme.cornerRadius + color: wiredMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight + border.width: modelData.isActive ? 2 : 0 + border.color: Theme.primary + + Row { + anchors.left: parent.left + anchors.leftMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingS + + DankIcon { + name: "lan" + size: 20 + color: modelData.isActive ? Theme.primary : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: 2 + + StyledText { + text: modelData.id || I18n.tr("Unknown") + font.pixelSize: Theme.fontSizeMedium + color: modelData.isActive ? Theme.primary : Theme.surfaceText + font.weight: modelData.isActive ? Font.Medium : Font.Normal + } + + StyledText { + text: modelData.isActive ? I18n.tr("Active") : "" + font.pixelSize: Theme.fontSizeSmall + color: Theme.primary + visible: modelData.isActive + } + } + } + + MouseArea { + id: wiredMouseArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + if (!modelData.isActive) { + NetworkService.connectToSpecificWiredConfig(modelData.uuid); + } + } + } + } + } + } + } + } + + StyledRect { + width: parent.width + height: wifiSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + + Column { + id: wifiSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: NetworkService.wifiEnabled ? "wifi" : "wifi_off" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - Theme.spacingM - wifiControls.width - Theme.spacingM + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: I18n.tr("WiFi") + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + } + + StyledText { + text: { + if (NetworkService.wifiToggling) + return I18n.tr("Toggling..."); + if (!NetworkService.wifiEnabled) + return I18n.tr("Disabled"); + if (NetworkService.wifiConnected) + return NetworkService.currentWifiSSID; + return I18n.tr("Not connected"); + } + font.pixelSize: Theme.fontSizeSmall + color: NetworkService.wifiConnected ? Theme.success : Theme.surfaceVariantText + } + } + + Row { + id: wifiControls + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingS + + DankActionButton { + iconName: "refresh" + buttonSize: 32 + visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling + enabled: !NetworkService.isScanning + onClicked: NetworkService.scanWifi() + + RotationAnimation on rotation { + running: NetworkService.isScanning + loops: Animation.Infinite + from: 0 + to: 360 + duration: 1000 + } + } + + DankToggle { + checked: NetworkService.wifiEnabled + enabled: !NetworkService.wifiToggling + onToggled: NetworkService.toggleWifiRadio() + } + } + } + + Row { + width: parent.width + spacing: Theme.spacingM + visible: NetworkService.wifiEnabled && (NetworkService.wifiDevices?.length ?? 0) > 1 + + StyledText { + text: I18n.tr("WiFi Device") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + Item { + width: parent.width - wifiDeviceLabel.width - wifiDeviceDropdown.width - Theme.spacingM * 2 + height: 1 + } + + DankDropdown { + id: wifiDeviceDropdown + dropdownWidth: 150 + popupWidth: 180 + currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto") + options: { + const devices = NetworkService.wifiDevices; + if (!devices || devices.length === 0) + return [I18n.tr("Auto")]; + return [I18n.tr("Auto")].concat(devices.map(d => d.name)); + } + onValueChanged: value => { + const deviceName = value === I18n.tr("Auto") ? "" : value; + NetworkService.setWifiDeviceOverride(deviceName); + } + } + } + + StyledText { + id: wifiDeviceLabel + visible: false + text: I18n.tr("WiFi Device") + } + + Rectangle { + width: parent.width + height: 1 + color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) + visible: NetworkService.wifiEnabled + } + + Column { + width: parent.width + spacing: Theme.spacingS + visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling + + Column { + width: parent.width + spacing: Theme.spacingS + visible: NetworkService.wifiInterface.length > 0 + + Row { + width: parent.width + height: 24 + + StyledText { + text: I18n.tr("Interface:") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + width: 100 + anchors.verticalCenter: parent.verticalCenter + } + StyledText { + text: NetworkService.wifiInterface || "-" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + Row { + width: parent.width + height: 24 + visible: NetworkService.wifiIP.length > 0 + + StyledText { + text: I18n.tr("IP Address:") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + width: 100 + anchors.verticalCenter: parent.verticalCenter + } + StyledText { + text: NetworkService.wifiIP || "-" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + } + + Row { + width: parent.width + height: 24 + visible: NetworkService.wifiConnected + + StyledText { + text: I18n.tr("Signal:") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + width: 100 + anchors.verticalCenter: parent.verticalCenter + } + + Row { + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + DankIcon { + name: { + const s = NetworkService.wifiSignalStrength; + if (s >= 50) + return "wifi"; + if (s >= 25) + return "wifi_2_bar"; + return "wifi_1_bar"; + } + size: 18 + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: NetworkService.wifiSignalStrength + "%" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + } + } + } + } + + Item { + width: parent.width + height: Theme.spacingS + } + + Row { + width: parent.width + spacing: Theme.spacingM + + StyledText { + text: I18n.tr("Available Networks") + font.pixelSize: Theme.fontSizeMedium + font.weight: Font.Medium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Item { + width: 1 + height: 1 + Layout.fillWidth: true + } + + StyledText { + text: NetworkService.wifiNetworks?.length ?? 0 + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + } + + Item { + width: parent.width + height: 80 + visible: NetworkService.isScanning && (NetworkService.wifiNetworks?.length ?? 0) === 0 + + Column { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "refresh" + size: 32 + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + + RotationAnimation on rotation { + running: true + loops: Animation.Infinite + from: 0 + to: 360 + duration: 1000 + } + } + + StyledText { + text: I18n.tr("Scanning...") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + } + } + + Column { + width: parent.width + spacing: 4 + visible: (NetworkService.wifiNetworks?.length ?? 0) > 0 + + Repeater { + model: { + const ssid = NetworkService.currentWifiSSID; + const networks = NetworkService.wifiNetworks || []; + const pins = SettingsData.wifiNetworkPins || {}; + const pinnedSSID = pins["preferredWifi"]; + + let sorted = [...networks]; + sorted.sort((a, b) => { + if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID) + return -1; + if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID) + return 1; + if (a.ssid === ssid) + return -1; + if (b.ssid === ssid) + return 1; + return b.signal - a.signal; + }); + return sorted; + } + + delegate: Rectangle { + id: wifiNetworkDelegate + required property var modelData + required property int index + + readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID + readonly property bool isPinned: (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid + readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid + + width: parent.width + height: isExpanded ? 56 + wifiExpandedContent.height : 56 + radius: Theme.cornerRadius + color: wifiNetworkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight + border.width: isConnected ? 2 : 0 + border.color: Theme.primary + clip: true + + Behavior on height { + NumberAnimation { + duration: 150 + easing.type: Easing.OutQuad + } + } + + Column { + anchors.fill: parent + spacing: 0 + + Item { + width: parent.width + height: 56 + + Row { + anchors.left: parent.left + anchors.leftMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + anchors.right: wifiNetworkActions.left + anchors.rightMargin: Theme.spacingS + spacing: Theme.spacingS + + DankIcon { + name: { + const s = modelData.signal || 0; + if (s >= 50) + return "wifi"; + if (s >= 25) + return "wifi_2_bar"; + return "wifi_1_bar"; + } + size: 20 + color: isConnected ? Theme.primary : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: 2 + width: parent.width - 20 - Theme.spacingS + + Row { + spacing: Theme.spacingXS + + StyledText { + text: modelData.ssid || I18n.tr("Unknown") + font.pixelSize: Theme.fontSizeMedium + color: isConnected ? Theme.primary : Theme.surfaceText + font.weight: isConnected ? Font.Medium : Font.Normal + elide: Text.ElideRight + } + + DankIcon { + name: "push_pin" + size: 14 + color: Theme.primary + visible: isPinned + anchors.verticalCenter: parent.verticalCenter + } + } + + Row { + spacing: Theme.spacingXS + + StyledText { + text: isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open")) + font.pixelSize: Theme.fontSizeSmall + color: isConnected ? Theme.primary : Theme.surfaceVariantText + } + + StyledText { + text: "•" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + visible: modelData.saved + } + + StyledText { + text: I18n.tr("Saved") + font.pixelSize: Theme.fontSizeSmall + color: Theme.primary + visible: modelData.saved + } + + StyledText { + text: "•" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + StyledText { + text: modelData.signal + "%" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + } + + Row { + id: wifiNetworkActions + anchors.right: parent.right + anchors.rightMargin: Theme.spacingS + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingXS + + Rectangle { + width: 28 + height: 28 + radius: 14 + color: wifiExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" + visible: isConnected || modelData.saved + + DankIcon { + anchors.centerIn: parent + name: isExpanded ? "expand_less" : "expand_more" + size: 18 + color: Theme.surfaceText + } + + MouseArea { + id: wifiExpandBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + if (isExpanded) { + networkTab.expandedWifiSsid = ""; + } else { + networkTab.expandedWifiSsid = modelData.ssid; + NetworkService.fetchNetworkInfo(modelData.ssid); + } + } + } + } + + DankActionButton { + iconName: isPinned ? "push_pin" : "push_pin" + buttonSize: 28 + iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText + onClicked: { + const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {})); + if (isPinned) { + delete pins["preferredWifi"]; + } else { + pins["preferredWifi"] = modelData.ssid; + } + SettingsData.set("wifiNetworkPins", pins); + } + } + + DankActionButton { + iconName: "delete" + buttonSize: 28 + iconColor: Theme.error + visible: modelData.saved || isConnected + onClicked: { + forgetNetworkConfirm.showWithOptions({ + title: I18n.tr("Forget Network"), + message: I18n.tr("Forget \"") + modelData.ssid + "\"?", + confirmText: I18n.tr("Forget"), + confirmColor: Theme.error, + onConfirm: () => NetworkService.forgetWifiNetwork(modelData.ssid) + }); + } + } + } + + MouseArea { + id: wifiNetworkMouseArea + + anchors.fill: parent + anchors.rightMargin: wifiNetworkActions.width + Theme.spacingM + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + if (isConnected) { + NetworkService.disconnectWifi(); + return; + } + NetworkService.connectToWifi(modelData.ssid); + } + } + } + + Column { + id: wifiExpandedContent + width: parent.width + visible: isExpanded + + Rectangle { + width: parent.width - Theme.spacingM * 2 + height: 1 + x: Theme.spacingM + color: Theme.outlineLight + } + + Item { + width: parent.width + height: wifiDetailsColumn.implicitHeight + Theme.spacingM * 2 + + Column { + id: wifiDetailsColumn + anchors.fill: parent + anchors.margins: Theme.spacingM + spacing: Theme.spacingS + + Item { + width: parent.width + height: NetworkService.networkInfoLoading ? 40 : 0 + visible: NetworkService.networkInfoLoading + + Row { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "sync" + size: 16 + color: Theme.surfaceVariantText + + RotationAnimation on rotation { + running: NetworkService.networkInfoLoading + loops: Animation.Infinite + from: 0 + to: 360 + duration: 1000 + } + } + + StyledText { + text: I18n.tr("Loading...") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + + Flow { + width: parent.width + spacing: Theme.spacingXS + visible: !NetworkService.networkInfoLoading + + Repeater { + model: { + const fields = []; + const net = modelData; + if (!net) + return fields; + + fields.push({ + label: I18n.tr("Signal"), + value: net.signal + "%" + }); + if (net.frequency) + fields.push({ + label: I18n.tr("Frequency"), + value: (net.frequency / 1000).toFixed(1) + " GHz" + }); + if (net.channel) + fields.push({ + label: I18n.tr("Channel"), + value: String(net.channel) + }); + if (net.rate) + fields.push({ + label: I18n.tr("Rate"), + value: net.rate + " Mbps" + }); + if (net.mode) + fields.push({ + label: I18n.tr("Mode"), + value: net.mode + }); + if (net.bssid) + fields.push({ + label: I18n.tr("BSSID"), + value: net.bssid + }); + fields.push({ + label: I18n.tr("Security"), + value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open") + }); + + return fields; + } + + delegate: Rectangle { + required property var modelData + required property int index + + width: wifiFieldContent.width + Theme.spacingM * 2 + height: 32 + radius: Theme.cornerRadius - 2 + color: Theme.surfaceContainerHigh + border.width: 1 + border.color: Theme.outlineLight + + Row { + id: wifiFieldContent + anchors.centerIn: parent + spacing: Theme.spacingXS + + StyledText { + text: modelData.label + ":" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: modelData.value + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + } + + Row { + spacing: Theme.spacingS + visible: (modelData.saved || isConnected) && DMSService.apiVersion > 13 + + DankToggle { + id: autoconnectToggle + text: I18n.tr("Autoconnect") + checked: modelData.autoconnect || false + onToggled: checked => { + NetworkService.setWifiAutoconnect(modelData.ssid, checked); + } + } + } + } + } + } + } + } + } + } + } + } + } + + StyledRect { + width: parent.width + height: vpnSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + visible: DMSNetworkService.vpnAvailable + + Column { + id: vpnSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + Column { + width: parent.width - Theme.iconSize - Theme.spacingM - vpnHeaderControls.width - Theme.spacingM + spacing: Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: I18n.tr("VPN") + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + } + + StyledText { + text: { + if (!DMSNetworkService.connected) + return I18n.tr("Disconnected"); + const names = DMSNetworkService.activeNames || []; + if (names.length <= 1) + return names[0] || I18n.tr("Connected"); + return names[0] + " +" + (names.length - 1); + } + font.pixelSize: Theme.fontSizeSmall + color: DMSNetworkService.connected ? Theme.success : Theme.surfaceVariantText + } + } + + Row { + id: vpnHeaderControls + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingS + + Rectangle { + height: 28 + radius: 14 + width: importVpnRow.width + Theme.spacingM * 2 + color: importVpnArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight + opacity: VPNService.importing ? 0.5 : 1.0 + + Row { + id: importVpnRow + anchors.centerIn: parent + spacing: Theme.spacingXS + + DankIcon { + name: VPNService.importing ? "sync" : "add" + size: Theme.fontSizeSmall + color: Theme.primary + } + + StyledText { + text: I18n.tr("Import") + font.pixelSize: Theme.fontSizeSmall + color: Theme.primary + font.weight: Font.Medium + } + } + + MouseArea { + id: importVpnArea + anchors.fill: parent + hoverEnabled: true + cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor + enabled: !VPNService.importing + onClicked: vpnFileBrowser.open() + } + } + + Rectangle { + height: 28 + radius: 14 + width: disconnectAllRow.width + Theme.spacingM * 2 + color: disconnectAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight + visible: DMSNetworkService.connected + opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 + + Row { + id: disconnectAllRow + anchors.centerIn: parent + spacing: Theme.spacingXS + + DankIcon { + name: "link_off" + size: Theme.fontSizeSmall + color: Theme.surfaceText + } + + StyledText { + text: I18n.tr("Disconnect") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + } + } + + MouseArea { + id: disconnectAllArea + anchors.fill: parent + hoverEnabled: true + cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor + enabled: !DMSNetworkService.isBusy + onClicked: DMSNetworkService.disconnectAllActive() + } + } + } + } + + Rectangle { + width: parent.width + height: 1 + color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) + } + + Item { + width: parent.width + height: 100 + visible: DMSNetworkService.profiles.length === 0 + + Column { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "vpn_key_off" + size: 36 + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + + StyledText { + text: I18n.tr("No VPN profiles") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + + StyledText { + text: I18n.tr("Click Import to add a .ovpn or .conf") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + } + } + + Column { + width: parent.width + spacing: 4 + visible: DMSNetworkService.profiles.length > 0 + + Repeater { + model: DMSNetworkService.profiles + + delegate: Rectangle { + id: vpnProfileRow + required property var modelData + required property int index + + readonly property bool isActive: DMSNetworkService.isActiveUuid(modelData.uuid) + readonly property bool isExpanded: networkTab.expandedVpnUuid === modelData.uuid + readonly property var configData: isExpanded ? VPNService.editConfig : null + + width: parent.width + height: isExpanded ? 56 + vpnExpandedContent.height : 56 + radius: Theme.cornerRadius + color: vpnRowArea.containsMouse ? Theme.primaryHoverLight : (isActive ? Theme.primaryPressed : Theme.surfaceLight) + border.width: isActive ? 2 : 0 + border.color: Theme.primary + opacity: DMSNetworkService.isBusy ? 0.6 : 1.0 + clip: true + + Behavior on height { + NumberAnimation { + duration: 150 + easing.type: Easing.OutQuad + } + } + + MouseArea { + id: vpnRowArea + anchors.fill: parent + hoverEnabled: true + cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor + enabled: !DMSNetworkService.isBusy + onClicked: DMSNetworkService.toggle(modelData.uuid) + } + + Column { + anchors.fill: parent + anchors.margins: Theme.spacingS + spacing: Theme.spacingS + + Row { + width: parent.width + height: 56 - Theme.spacingS * 2 + spacing: Theme.spacingS + + DankIcon { + name: isActive ? "vpn_lock" : "vpn_key_off" + size: 20 + color: isActive ? Theme.primary : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Column { + spacing: 2 + anchors.verticalCenter: parent.verticalCenter + width: parent.width - 20 - 28 - 28 - Theme.spacingS * 4 + + StyledText { + text: modelData.name + font.pixelSize: Theme.fontSizeMedium + color: isActive ? Theme.primary : Theme.surfaceText + elide: Text.ElideRight + width: parent.width + } + + StyledText { + text: VPNService.getVpnTypeFromProfile(modelData) + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + + Item { + width: Theme.spacingXS + height: 1 + } + + Rectangle { + width: 28 + height: 28 + radius: 14 + color: vpnExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" + anchors.verticalCenter: parent.verticalCenter + + DankIcon { + anchors.centerIn: parent + name: isExpanded ? "expand_less" : "expand_more" + size: 18 + color: Theme.surfaceText + } + + MouseArea { + id: vpnExpandBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + if (isExpanded) { + networkTab.expandedVpnUuid = ""; + } else { + networkTab.expandedVpnUuid = modelData.uuid; + VPNService.getConfig(modelData.uuid); + } + } + } + } + + Rectangle { + width: 28 + height: 28 + radius: 14 + color: vpnDeleteBtn.containsMouse ? Theme.errorHover : "transparent" + anchors.verticalCenter: parent.verticalCenter + + DankIcon { + anchors.centerIn: parent + name: "delete" + size: 18 + color: vpnDeleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText + } + + MouseArea { + id: vpnDeleteBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + deleteVpnConfirm.showWithOptions({ + title: I18n.tr("Delete VPN"), + message: I18n.tr("Delete \"") + modelData.name + "\"?", + confirmText: I18n.tr("Delete"), + confirmColor: Theme.error, + onConfirm: () => VPNService.deleteVpn(modelData.uuid) + }); + } + } + } + } + + Column { + id: vpnExpandedContent + width: parent.width + spacing: Theme.spacingXS + visible: isExpanded + + Rectangle { + width: parent.width + height: 1 + color: Theme.outlineLight + } + + Item { + width: parent.width + height: VPNService.configLoading ? 40 : 0 + visible: VPNService.configLoading + + Row { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "sync" + size: 16 + color: Theme.surfaceVariantText + } + + StyledText { + text: I18n.tr("Loading...") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + + Flow { + width: parent.width + spacing: Theme.spacingXS + visible: !VPNService.configLoading && configData + + Repeater { + model: { + if (!configData) + return []; + const fields = []; + const data = configData.data || {}; + + if (data.remote) + fields.push({ + label: I18n.tr("Server"), + value: data.remote + }); + if (configData.username || data.username) + fields.push({ + label: I18n.tr("Username"), + value: configData.username || data.username + }); + if (data.cipher) + fields.push({ + label: I18n.tr("Cipher"), + value: data.cipher + }); + if (data.auth) + fields.push({ + label: I18n.tr("Auth"), + value: data.auth + }); + if (data["proto-tcp"] === "yes" || data["proto-tcp"] === "no") + fields.push({ + label: I18n.tr("Protocol"), + value: data["proto-tcp"] === "yes" ? "TCP" : "UDP" + }); + if (data["tunnel-mtu"]) + fields.push({ + label: I18n.tr("MTU"), + value: data["tunnel-mtu"] + }); + if (data["connection-type"]) + fields.push({ + label: I18n.tr("Auth Type"), + value: data["connection-type"] + }); + fields.push({ + label: I18n.tr("Autoconnect"), + value: configData.autoconnect ? I18n.tr("Yes") : I18n.tr("No") + }); + + return fields; + } + + delegate: Rectangle { + required property var modelData + required property int index + + width: vpnFieldContent.width + Theme.spacingM * 2 + height: 32 + radius: Theme.cornerRadius - 2 + color: Theme.surfaceContainerHigh + border.width: 1 + border.color: Theme.outlineLight + + Row { + id: vpnFieldContent + anchors.centerIn: parent + spacing: Theme.spacingXS + + StyledText { + text: modelData.label + ":" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: modelData.value + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + } + + Item { + width: 1 + height: Theme.spacingXS + } + } + } + } + } + } + } + } + } + } +} diff --git a/quickshell/Services/DMSNetworkService.qml b/quickshell/Services/DMSNetworkService.qml index 79480db1..8f1b7b4b 100644 --- a/quickshell/Services/DMSNetworkService.qml +++ b/quickshell/Services/DMSNetworkService.qml @@ -18,6 +18,7 @@ Singleton { property string ethernetInterface: "" property bool ethernetConnected: false property string ethernetConnectionUuid: "" + property var ethernetDevices: [] property var wiredConnections: [] @@ -116,7 +117,7 @@ Singleton { signal networksUpdated signal connectionChanged - signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService) + signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService, var fieldsInfo) readonly property string socketPath: Quickshell.env("DMS_SOCKET") @@ -197,8 +198,9 @@ Singleton { const connType = data.connType || ""; const connName = data.name || data.connectionId || ""; const vpnService = data.vpnService || ""; + const fInfo = data.fieldsInfo || []; - credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason, connType, connName, vpnService); + credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason, connType, connName, vpnService, fInfo); } function addRef() { @@ -244,6 +246,7 @@ Singleton { ethernetInterface = state.ethernetDevice || ""; ethernetConnected = state.ethernetConnected || false; ethernetConnectionUuid = state.ethernetConnectionUuid || ""; + ethernetDevices = state.ethernetDevices || []; wiredConnections = state.wiredConnections || []; @@ -618,7 +621,7 @@ Singleton { if (!networkAvailable) return; if (type === "ethernet") { - if (networkStatus === "ethernet") { + if (ethernetConnected) { DMSService.sendRequest("network.ethernet.disconnect", null, null); } else { DMSService.sendRequest("network.ethernet.connect", null, null); @@ -626,6 +629,14 @@ Singleton { } } + function disconnectEthernetDevice(deviceName) { + if (!networkAvailable) + return; + DMSService.sendRequest("network.ethernet.disconnect", { + device: deviceName + }, null); + } + function startAutoScan() { autoScan = true; autoRefreshEnabled = true; diff --git a/quickshell/Services/IdleService.qml b/quickshell/Services/IdleService.qml index 8927086a..a7e9af5f 100644 --- a/quickshell/Services/IdleService.qml +++ b/quickshell/Services/IdleService.qml @@ -176,15 +176,6 @@ Singleton { } } - Connections { - target: SessionService - function onPrepareForSleep() { - if (SettingsData.lockBeforeSuspend) { - root.lockRequested(); - } - } - } - Connections { target: SettingsData function onPreventIdleForMediaChanged() { diff --git a/quickshell/Services/NetworkService.qml b/quickshell/Services/NetworkService.qml index 139c962f..38383d28 100644 --- a/quickshell/Services/NetworkService.qml +++ b/quickshell/Services/NetworkService.qml @@ -16,6 +16,7 @@ Singleton { property string ethernetInterface: activeService?.ethernetInterface ?? "" property bool ethernetConnected: activeService?.ethernetConnected ?? false property string ethernetConnectionUuid: activeService?.ethernetConnectionUuid ?? "" + property var ethernetDevices: activeService?.ethernetDevices ?? [] property var wiredConnections: activeService?.wiredConnections ?? [] @@ -88,7 +89,7 @@ Singleton { signal networksUpdated signal connectionChanged - signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService) + signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService, var fieldsInfo) property bool usingLegacy: false property var activeService: null @@ -230,6 +231,12 @@ Singleton { } } + function disconnectEthernetDevice(deviceName) { + if (activeService && activeService.disconnectEthernetDevice) { + activeService.disconnectEthernetDevice(deviceName); + } + } + function startAutoScan() { if (activeService && activeService.startAutoScan) { activeService.startAutoScan(); diff --git a/quickshell/Services/PopoutService.qml b/quickshell/Services/PopoutService.qml index 589b6c61..c3ddd252 100644 --- a/quickshell/Services/PopoutService.qml +++ b/quickshell/Services/PopoutService.qml @@ -1,7 +1,7 @@ -import QtQuick -import Quickshell pragma Singleton pragma ComponentBehavior: Bound +import QtQuick +import Quickshell Singleton { id: root @@ -23,6 +23,7 @@ Singleton { property var colorPickerModal: null property var notificationModal: null property var wifiPasswordModal: null + property var polkitAuthModal: null property var bluetoothPairingModal: null property var networkInfoModal: null @@ -30,267 +31,267 @@ Singleton { function setPosition(popout, x, y, width, section, screen) { if (popout && popout.setTriggerPosition && arguments.length >= 6) { - popout.setTriggerPosition(x, y, width, section, screen) + popout.setTriggerPosition(x, y, width, section, screen); } } function openControlCenter(x, y, width, section, screen) { if (controlCenterPopout) { - setPosition(controlCenterPopout, x, y, width, section, screen) - controlCenterPopout.open() + setPosition(controlCenterPopout, x, y, width, section, screen); + controlCenterPopout.open(); } } function closeControlCenter() { - controlCenterPopout?.close() + controlCenterPopout?.close(); } function toggleControlCenter(x, y, width, section, screen) { if (controlCenterPopout) { - setPosition(controlCenterPopout, x, y, width, section, screen) - controlCenterPopout.toggle() + setPosition(controlCenterPopout, x, y, width, section, screen); + controlCenterPopout.toggle(); } } function openNotificationCenter(x, y, width, section, screen) { if (notificationCenterPopout) { - setPosition(notificationCenterPopout, x, y, width, section, screen) - notificationCenterPopout.open() + setPosition(notificationCenterPopout, x, y, width, section, screen); + notificationCenterPopout.open(); } } function closeNotificationCenter() { - notificationCenterPopout?.close() + notificationCenterPopout?.close(); } function toggleNotificationCenter(x, y, width, section, screen) { if (notificationCenterPopout) { - setPosition(notificationCenterPopout, x, y, width, section, screen) - notificationCenterPopout.toggle() + setPosition(notificationCenterPopout, x, y, width, section, screen); + notificationCenterPopout.toggle(); } } function openAppDrawer(x, y, width, section, screen) { if (appDrawerPopout) { - setPosition(appDrawerPopout, x, y, width, section, screen) - appDrawerPopout.open() + setPosition(appDrawerPopout, x, y, width, section, screen); + appDrawerPopout.open(); } } function closeAppDrawer() { - appDrawerPopout?.close() + appDrawerPopout?.close(); } function toggleAppDrawer(x, y, width, section, screen) { if (appDrawerPopout) { - setPosition(appDrawerPopout, x, y, width, section, screen) - appDrawerPopout.toggle() + setPosition(appDrawerPopout, x, y, width, section, screen); + appDrawerPopout.toggle(); } } function openProcessList(x, y, width, section, screen) { if (processListPopout) { - setPosition(processListPopout, x, y, width, section, screen) - processListPopout.open() + setPosition(processListPopout, x, y, width, section, screen); + processListPopout.open(); } } function closeProcessList() { - processListPopout?.close() + processListPopout?.close(); } function toggleProcessList(x, y, width, section, screen) { if (processListPopout) { - setPosition(processListPopout, x, y, width, section, screen) - processListPopout.toggle() + setPosition(processListPopout, x, y, width, section, screen); + processListPopout.toggle(); } } function openDankDash(tabIndex, x, y, width, section, screen) { if (dankDashPopout) { if (arguments.length >= 6) { - setPosition(dankDashPopout, x, y, width, section, screen) + setPosition(dankDashPopout, x, y, width, section, screen); } - dankDashPopout.currentTabIndex = tabIndex || 0 - dankDashPopout.dashVisible = true + dankDashPopout.currentTabIndex = tabIndex || 0; + dankDashPopout.dashVisible = true; } } function closeDankDash() { if (dankDashPopout) { - dankDashPopout.dashVisible = false + dankDashPopout.dashVisible = false; } } function toggleDankDash(tabIndex, x, y, width, section, screen) { if (dankDashPopout) { if (arguments.length >= 6) { - setPosition(dankDashPopout, x, y, width, section, screen) + setPosition(dankDashPopout, x, y, width, section, screen); } if (dankDashPopout.dashVisible) { - dankDashPopout.dashVisible = false + dankDashPopout.dashVisible = false; } else { - dankDashPopout.currentTabIndex = tabIndex || 0 - dankDashPopout.dashVisible = true + dankDashPopout.currentTabIndex = tabIndex || 0; + dankDashPopout.dashVisible = true; } } } function openBattery(x, y, width, section, screen) { if (batteryPopout) { - setPosition(batteryPopout, x, y, width, section, screen) - batteryPopout.open() + setPosition(batteryPopout, x, y, width, section, screen); + batteryPopout.open(); } } function closeBattery() { - batteryPopout?.close() + batteryPopout?.close(); } function toggleBattery(x, y, width, section, screen) { if (batteryPopout) { - setPosition(batteryPopout, x, y, width, section, screen) - batteryPopout.toggle() + setPosition(batteryPopout, x, y, width, section, screen); + batteryPopout.toggle(); } } function openVpn(x, y, width, section, screen) { if (vpnPopout) { - setPosition(vpnPopout, x, y, width, section, screen) - vpnPopout.open() + setPosition(vpnPopout, x, y, width, section, screen); + vpnPopout.open(); } } function closeVpn() { - vpnPopout?.close() + vpnPopout?.close(); } function toggleVpn(x, y, width, section, screen) { if (vpnPopout) { - setPosition(vpnPopout, x, y, width, section, screen) - vpnPopout.toggle() + setPosition(vpnPopout, x, y, width, section, screen); + vpnPopout.toggle(); } } function openSystemUpdate(x, y, width, section, screen) { if (systemUpdatePopout) { - setPosition(systemUpdatePopout, x, y, width, section, screen) - systemUpdatePopout.open() + setPosition(systemUpdatePopout, x, y, width, section, screen); + systemUpdatePopout.open(); } } function closeSystemUpdate() { - systemUpdatePopout?.close() + systemUpdatePopout?.close(); } function toggleSystemUpdate(x, y, width, section, screen) { if (systemUpdatePopout) { - setPosition(systemUpdatePopout, x, y, width, section, screen) - systemUpdatePopout.toggle() + setPosition(systemUpdatePopout, x, y, width, section, screen); + systemUpdatePopout.toggle(); } } function openSettings() { - settingsModal?.show() + settingsModal?.show(); } function closeSettings() { - settingsModal?.close() + settingsModal?.close(); } function openClipboardHistory() { - clipboardHistoryModal?.show() + clipboardHistoryModal?.show(); } function closeClipboardHistory() { - clipboardHistoryModal?.close() + clipboardHistoryModal?.close(); } function openSpotlight() { - spotlightModal?.show() + spotlightModal?.show(); } function closeSpotlight() { - spotlightModal?.close() + spotlightModal?.close(); } function openPowerMenu() { - powerMenuModal?.openCentered() + powerMenuModal?.openCentered(); } function closePowerMenu() { - powerMenuModal?.close() + powerMenuModal?.close(); } function togglePowerMenu() { if (powerMenuModal) { if (powerMenuModal.shouldBeVisible) { - powerMenuModal.close() + powerMenuModal.close(); } else { - powerMenuModal.openCentered() + powerMenuModal.openCentered(); } } } function showProcessListModal() { - processListModal?.show() + processListModal?.show(); } function hideProcessListModal() { - processListModal?.hide() + processListModal?.hide(); } function toggleProcessListModal() { - processListModal?.toggle() + processListModal?.toggle(); } function showColorPicker() { - colorPickerModal?.show() + colorPickerModal?.show(); } function hideColorPicker() { - colorPickerModal?.close() + colorPickerModal?.close(); } function showNotificationModal() { - notificationModal?.show() + notificationModal?.show(); } function hideNotificationModal() { - notificationModal?.close() + notificationModal?.close(); } function showWifiPasswordModal() { - wifiPasswordModal?.show() + wifiPasswordModal?.show(); } function hideWifiPasswordModal() { - wifiPasswordModal?.close() + wifiPasswordModal?.hide(); } function showNetworkInfoModal() { - networkInfoModal?.show() + networkInfoModal?.show(); } function hideNetworkInfoModal() { - networkInfoModal?.close() + networkInfoModal?.close(); } function openNotepad() { if (notepadSlideouts.length > 0) { - notepadSlideouts[0]?.show() + notepadSlideouts[0]?.show(); } } function closeNotepad() { if (notepadSlideouts.length > 0) { - notepadSlideouts[0]?.hide() + notepadSlideouts[0]?.hide(); } } function toggleNotepad() { if (notepadSlideouts.length > 0) { - notepadSlideouts[0]?.toggle() + notepadSlideouts[0]?.toggle(); } } } diff --git a/quickshell/Services/VPNService.qml b/quickshell/Services/VPNService.qml new file mode 100644 index 00000000..a8a4c9cd --- /dev/null +++ b/quickshell/Services/VPNService.qml @@ -0,0 +1,220 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import qs.Common + +Singleton { + id: root + + readonly property bool available: DMSNetworkService.vpnAvailable + + property var plugins: [] + property var allExtensions: [] + property bool importing: false + property string importError: "" + + property var editConfig: null + property bool configLoading: false + + property bool pluginsLoading: false + + signal importComplete(string uuid, string name) + signal configLoaded(var config) + signal configUpdated + signal vpnDeleted(string uuid) + + Component.onCompleted: { + if (available) { + fetchPlugins(); + } + } + + Connections { + target: DMSNetworkService + function onVpnAvailableChanged() { + if (DMSNetworkService.vpnAvailable && plugins.length === 0) { + fetchPlugins(); + } + } + } + + function fetchPlugins() { + if (!available || pluginsLoading) + return; + pluginsLoading = true; + + DMSService.sendRequest("network.vpn.plugins", null, response => { + pluginsLoading = false; + if (response.error) { + console.warn("VPNService: Failed to fetch plugins:", response.error); + return; + } + if (!response.result) + return; + plugins = response.result; + const extSet = new Set(); + for (const plugin of response.result) { + for (const ext of plugin.fileExtensions || []) { + extSet.add(ext); + } + } + allExtensions = Array.from(extSet); + }); + } + + function importVpn(filePath, name = "") { + if (!available || importing) + return; + importing = true; + importError = ""; + + const params = { + file: filePath + }; + if (name) + params.name = name; + + DMSService.sendRequest("network.vpn.import", params, response => { + importing = false; + + if (response.error) { + importError = response.error; + ToastService.showError(I18n.tr("Failed to import VPN")); + return; + } + + if (!response.result) + return; + if (response.result.success) { + ToastService.showInfo(I18n.tr("VPN imported: ") + (response.result.name || "")); + DMSNetworkService.refreshVpnProfiles(); + importComplete(response.result.uuid || "", response.result.name || ""); + return; + } + + importError = response.result.error || "Import failed"; + ToastService.showError(importError); + }); + } + + function getConfig(uuidOrName) { + if (!available) + return; + configLoading = true; + editConfig = null; + + DMSService.sendRequest("network.vpn.getConfig", { + uuid: uuidOrName + }, response => { + configLoading = false; + + if (response.error) { + ToastService.showError(I18n.tr("Failed to load VPN config")); + return; + } + + if (response.result) { + editConfig = response.result; + configLoaded(response.result); + } + }); + } + + function updateConfig(uuid, updates) { + if (!available) + return; + const params = { + uuid: uuid + }; + if (updates.name !== undefined) + params.name = updates.name; + if (updates.autoconnect !== undefined) + params.autoconnect = updates.autoconnect; + if (updates.data !== undefined) + params.data = updates.data; + + DMSService.sendRequest("network.vpn.updateConfig", params, response => { + if (response.error) { + ToastService.showError(I18n.tr("Failed to update VPN")); + return; + } + ToastService.showInfo(I18n.tr("VPN configuration updated")); + DMSNetworkService.refreshVpnProfiles(); + configUpdated(); + }); + } + + function deleteVpn(uuidOrName) { + if (!available) + return; + DMSService.sendRequest("network.vpn.delete", { + uuid: uuidOrName + }, response => { + if (response.error) { + ToastService.showError(I18n.tr("Failed to delete VPN")); + return; + } + ToastService.showInfo(I18n.tr("VPN deleted")); + DMSNetworkService.refreshVpnProfiles(); + vpnDeleted(uuidOrName); + }); + } + + function getFileFilter() { + if (allExtensions.length === 0) { + return ["*.ovpn", "*.conf"]; + } + return allExtensions.map(e => "*" + e); + } + + function getExtensionsForPlugin(serviceType) { + const plugin = plugins.find(p => p.serviceType === serviceType); + if (!plugin) + return ["*.conf"]; + return (plugin.fileExtensions || [".conf"]).map(e => "*" + e); + } + + function getPluginName(serviceType) { + if (!serviceType) + return "VPN"; + + const plugin = plugins.find(p => p.serviceType === serviceType); + if (plugin) + return plugin.name; + + const svc = serviceType.toLowerCase(); + if (svc.includes("openvpn")) + return "OpenVPN"; + if (svc.includes("wireguard")) + return "WireGuard"; + if (svc.includes("openconnect")) + return "OpenConnect"; + if (svc.includes("fortissl") || svc.includes("forti")) + return "Fortinet"; + if (svc.includes("strongswan")) + return "IPsec (strongSwan)"; + if (svc.includes("libreswan")) + return "IPsec (Libreswan)"; + if (svc.includes("l2tp")) + return "L2TP/IPsec"; + if (svc.includes("pptp")) + return "PPTP"; + if (svc.includes("vpnc")) + return "Cisco (vpnc)"; + if (svc.includes("sstp")) + return "SSTP"; + + const parts = serviceType.split('.'); + return parts[parts.length - 1] || "VPN"; + } + + function getVpnTypeFromProfile(profile) { + if (!profile) + return "VPN"; + if (profile.type === "wireguard") + return "WireGuard"; + return getPluginName(profile.serviceType); + } +} diff --git a/quickshell/Widgets/DankPopout.qml b/quickshell/Widgets/DankPopout.qml index 06e881bb..576f0034 100644 --- a/quickshell/Widgets/DankPopout.qml +++ b/quickshell/Widgets/DankPopout.qml @@ -28,6 +28,7 @@ Item { property list animationExitCurve: Theme.expressiveCurves.emphasized property bool shouldBeVisible: false property var customKeyboardFocus: null + property bool backgroundInteractive: true property real storedBarThickness: Theme.barHeight - 4 property real storedBarSpacing: 4 @@ -227,8 +228,8 @@ Item { item: Rectangle { x: root.maskX y: root.maskY - width: shouldBeVisible ? root.maskWidth : 0 - height: shouldBeVisible ? root.maskHeight : 0 + width: (shouldBeVisible && backgroundInteractive) ? root.maskWidth : 0 + height: (shouldBeVisible && backgroundInteractive) ? root.maskHeight : 0 } } @@ -237,7 +238,7 @@ Item { y: root.maskY width: root.maskWidth height: root.maskHeight - enabled: shouldBeVisible + enabled: shouldBeVisible && backgroundInteractive acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton onClicked: mouse => { const clickX = mouse.x + root.maskX; diff --git a/quickshell/Widgets/VpnDetailContent.qml b/quickshell/Widgets/VpnDetailContent.qml new file mode 100644 index 00000000..0b1025d7 --- /dev/null +++ b/quickshell/Widgets/VpnDetailContent.qml @@ -0,0 +1,476 @@ +import QtQuick +import QtQuick.Layouts +import qs.Common +import qs.Modals.Common +import qs.Modals.FileBrowser +import qs.Services +import qs.Widgets + +Rectangle { + id: root + + property var parentPopout: null + property string expandedUuid: "" + property int listHeight: 180 + + implicitHeight: contentColumn.implicitHeight + Theme.spacingM * 2 + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + + FileBrowserSurfaceModal { + id: fileBrowser + browserTitle: I18n.tr("Import VPN") + browserIcon: "vpn_key" + browserType: "vpn" + fileExtensions: VPNService.getFileFilter() + parentPopout: root.parentPopout + + onFileSelected: path => { + VPNService.importVpn(path.replace("file://", "")); + } + } + + ConfirmModal { + id: deleteConfirm + } + + Column { + id: contentColumn + anchors.fill: parent + anchors.margins: Theme.spacingM + spacing: Theme.spacingS + + RowLayout { + spacing: Theme.spacingS + width: parent.width + + StyledText { + text: { + if (!DMSNetworkService.connected) + return I18n.tr("Active: None"); + const names = DMSNetworkService.activeNames || []; + if (names.length <= 1) + return I18n.tr("Active: ") + (names[0] || "VPN"); + return I18n.tr("Active: ") + names[0] + " +" + (names.length - 1); + } + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + font.weight: Font.Medium + elide: Text.ElideRight + wrapMode: Text.NoWrap + Layout.fillWidth: true + } + + Rectangle { + height: 28 + radius: 14 + color: importArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight + width: 90 + Layout.alignment: Qt.AlignVCenter + opacity: VPNService.importing ? 0.5 : 1.0 + + Row { + anchors.centerIn: parent + spacing: Theme.spacingXS + + DankIcon { + name: VPNService.importing ? "sync" : "add" + size: Theme.fontSizeSmall + color: Theme.primary + } + + StyledText { + text: I18n.tr("Import") + font.pixelSize: Theme.fontSizeSmall + color: Theme.primary + font.weight: Font.Medium + } + } + + MouseArea { + id: importArea + anchors.fill: parent + hoverEnabled: true + cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor + enabled: !VPNService.importing + onClicked: fileBrowser.open() + } + } + + Rectangle { + height: 28 + radius: 14 + color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight + visible: DMSNetworkService.connected + width: 100 + Layout.alignment: Qt.AlignVCenter + opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 + + Row { + anchors.centerIn: parent + spacing: Theme.spacingXS + + DankIcon { + name: "link_off" + size: Theme.fontSizeSmall + color: Theme.surfaceText + } + + StyledText { + text: I18n.tr("Disconnect") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + } + } + + MouseArea { + id: discAllArea + anchors.fill: parent + hoverEnabled: true + cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor + enabled: !DMSNetworkService.isBusy + onClicked: DMSNetworkService.disconnectAllActive() + } + } + } + + Rectangle { + height: 1 + width: parent.width + color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) + } + + DankFlickable { + width: parent.width + height: root.listHeight + contentHeight: listCol.height + clip: true + + Column { + id: listCol + width: parent.width + spacing: 4 + + Item { + width: parent.width + height: DMSNetworkService.profiles.length === 0 ? 100 : 0 + visible: height > 0 + + Column { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "vpn_key_off" + size: 36 + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + + StyledText { + text: I18n.tr("No VPN profiles") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + + StyledText { + text: I18n.tr("Click Import to add a .ovpn or .conf") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.horizontalCenter: parent.horizontalCenter + } + } + } + + Repeater { + model: DMSNetworkService.profiles + + delegate: Rectangle { + id: profileRow + required property var modelData + required property int index + + readonly property bool isActive: DMSNetworkService.isActiveUuid(modelData.uuid) + readonly property bool isExpanded: root.expandedUuid === modelData.uuid + readonly property bool isHovered: rowArea.containsMouse || expandBtn.containsMouse || deleteBtn.containsMouse + readonly property var configData: isExpanded ? VPNService.editConfig : null + + width: listCol.width + height: isExpanded ? 46 + expandedContent.height : 46 + radius: Theme.cornerRadius + color: isHovered ? Theme.primaryHoverLight : (isActive ? Theme.primaryPressed : Theme.surfaceLight) + border.width: isActive ? 2 : 1 + border.color: isActive ? Theme.primary : Theme.outlineLight + opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 + clip: true + + Behavior on height { + NumberAnimation { + duration: 150 + easing.type: Easing.OutQuad + } + } + + MouseArea { + id: rowArea + anchors.fill: parent + hoverEnabled: true + cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor + enabled: !DMSNetworkService.isBusy + onClicked: DMSNetworkService.toggle(modelData.uuid) + } + + Column { + anchors.fill: parent + anchors.margins: Theme.spacingS + spacing: Theme.spacingS + + Row { + width: parent.width + height: 46 - Theme.spacingS * 2 + spacing: Theme.spacingS + + DankIcon { + name: isActive ? "vpn_lock" : "vpn_key_off" + size: 20 + color: isActive ? Theme.primary : Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + Column { + spacing: 1 + anchors.verticalCenter: parent.verticalCenter + width: parent.width - 20 - 28 - 28 - Theme.spacingS * 4 + + StyledText { + text: modelData.name + font.pixelSize: Theme.fontSizeMedium + color: isActive ? Theme.primary : Theme.surfaceText + elide: Text.ElideRight + wrapMode: Text.NoWrap + width: parent.width + } + + StyledText { + text: VPNService.getVpnTypeFromProfile(modelData) + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceTextMedium + wrapMode: Text.NoWrap + width: parent.width + elide: Text.ElideRight + } + } + + Item { + width: Theme.spacingXS + height: 1 + } + + Rectangle { + id: expandBtnRect + width: 28 + height: 28 + radius: 14 + color: expandBtn.containsMouse ? Theme.surfacePressed : "transparent" + anchors.verticalCenter: parent.verticalCenter + + DankIcon { + anchors.centerIn: parent + name: isExpanded ? "expand_less" : "expand_more" + size: 18 + color: Theme.surfaceText + } + + MouseArea { + id: expandBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + if (isExpanded) { + root.expandedUuid = ""; + } else { + root.expandedUuid = modelData.uuid; + VPNService.getConfig(modelData.uuid); + } + } + } + } + + Rectangle { + id: deleteBtnRect + width: 28 + height: 28 + radius: 14 + color: deleteBtn.containsMouse ? Theme.errorHover : "transparent" + anchors.verticalCenter: parent.verticalCenter + + DankIcon { + anchors.centerIn: parent + name: "delete" + size: 18 + color: deleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText + } + + MouseArea { + id: deleteBtn + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + deleteConfirm.showWithOptions({ + title: I18n.tr("Delete VPN"), + message: I18n.tr("Delete \"") + modelData.name + "\"?", + confirmText: I18n.tr("Delete"), + confirmColor: Theme.error, + onConfirm: () => VPNService.deleteVpn(modelData.uuid) + }); + } + } + } + } + + Column { + id: expandedContent + width: parent.width + spacing: Theme.spacingXS + visible: isExpanded + + Rectangle { + width: parent.width + height: 1 + color: Theme.outlineLight + } + + Item { + width: parent.width + height: VPNService.configLoading ? 40 : 0 + visible: VPNService.configLoading + + Row { + anchors.centerIn: parent + spacing: Theme.spacingS + + DankIcon { + name: "sync" + size: 16 + color: Theme.surfaceVariantText + } + + StyledText { + text: I18n.tr("Loading...") + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + + Flow { + width: parent.width + spacing: Theme.spacingXS + visible: !VPNService.configLoading && configData + + Repeater { + model: { + if (!configData) + return []; + const fields = []; + const data = configData.data || {}; + + if (data.remote) + fields.push({ + label: I18n.tr("Server"), + value: data.remote + }); + if (configData.username || data.username) + fields.push({ + label: I18n.tr("Username"), + value: configData.username || data.username + }); + if (data.cipher) + fields.push({ + label: I18n.tr("Cipher"), + value: data.cipher + }); + if (data.auth) + fields.push({ + label: I18n.tr("Auth"), + value: data.auth + }); + if (data["proto-tcp"] === "yes" || data["proto-tcp"] === "no") + fields.push({ + label: I18n.tr("Protocol"), + value: data["proto-tcp"] === "yes" ? "TCP" : "UDP" + }); + if (data["tunnel-mtu"]) + fields.push({ + label: I18n.tr("MTU"), + value: data["tunnel-mtu"] + }); + if (data["connection-type"]) + fields.push({ + label: I18n.tr("Auth Type"), + value: data["connection-type"] + }); + fields.push({ + label: I18n.tr("Autoconnect"), + value: configData.autoconnect ? I18n.tr("Yes") : I18n.tr("No") + }); + + return fields; + } + + delegate: Rectangle { + required property var modelData + required property int index + + width: fieldContent.width + Theme.spacingM * 2 + height: 32 + radius: Theme.cornerRadius - 2 + color: Theme.surfaceContainerHigh + border.width: 1 + border.color: Theme.outlineLight + + Row { + id: fieldContent + anchors.centerIn: parent + spacing: Theme.spacingXS + + StyledText { + text: modelData.label + ":" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: modelData.value + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + } + + Item { + width: 1 + height: Theme.spacingXS + } + } + } + } + } + } + } + + Item { + width: 1 + height: Theme.spacingS + } + } +} diff --git a/quickshell/translations/en.json b/quickshell/translations/en.json index 5fc93c84..a81d1c6b 100644 --- a/quickshell/translations/en.json +++ b/quickshell/translations/en.json @@ -1,38 +1,50 @@ [ + { + "term": "%1 adapter(s), none connected", + "context": "%1 adapter(s), none connected", + "reference": "Modules/Settings/NetworkTab.qml:287", + "comment": "" + }, { "term": "%1 characters", "context": "%1 characters", "reference": "Modules/Notepad/NotepadTextEditor.qml:565", "comment": "" }, + { + "term": "%1 connected", + "context": "%1 connected", + "reference": "Modules/Settings/NetworkTab.qml:288", + "comment": "" + }, { "term": "%1 display(s)", "context": "%1 display(s)", - "reference": "Modules/Settings/DankBarTab.qml:994", + "reference": "Modules/Settings/DankBarTab.qml:1243", "comment": "" }, { "term": "%1 widgets", "context": "%1 widgets", - "reference": "Modules/Settings/DankBarTab.qml:1011", + "reference": "Modules/Settings/DankBarTab.qml:1260", "comment": "" }, { "term": "(Unnamed)", "context": "(Unnamed)", - "reference": "Modules/Dock/DockContextMenu.qml:229", + "reference": "Modules/Dock/DockContextMenu.qml:230", "comment": "" }, { "term": "- Stateless System Monitoring", "context": "- Stateless System Monitoring", - "reference": "Modules/Settings/AboutTab.qml:587", + "reference": "Modules/Settings/AboutTab.qml:588", "comment": "" }, { "term": "- Support Us With a Star ⭐", "context": "- Support Us With a Star ⭐", - "reference": "Modules/Settings/AboutTab.qml:552", + "reference": "Modules/Settings/AboutTab.qml:553", "comment": "" }, { @@ -44,19 +56,19 @@ { "term": "24-Hour Format", "context": "24-Hour Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:58", + "reference": "Modules/Settings/TimeWeatherTab.qml:56", "comment": "" }, { "term": "24-hour format", "context": "24-hour format", - "reference": "Modules/Settings/PersonalizationTab.qml:1358", + "reference": "Modules/Settings/PersonalizationTab.qml:1353", "comment": "" }, { "term": "3rd party", "context": "3rd party", - "reference": "Modules/Settings/PluginBrowser.qml:428", + "reference": "Modules/Settings/PluginBrowser.qml:400", "comment": "" }, { @@ -74,25 +86,25 @@ { "term": "About", "context": "About", - "reference": "Modals/Settings/SettingsSidebar.qml:55, Modules/Settings/AboutTab.qml:406", + "reference": "Modals/Settings/SettingsSidebar.qml:72, Modules/Settings/AboutTab.qml:408", "comment": "" }, { "term": "Access clipboard history", "context": "Access clipboard history", - "reference": "Modules/Settings/DankBarTab.qml:245", + "reference": "Modules/Settings/DankBarTab.qml:397", "comment": "" }, { "term": "Access to notifications and do not disturb", "context": "Access to notifications and do not disturb", - "reference": "Modules/Settings/DankBarTab.qml:313", + "reference": "Modules/Settings/DankBarTab.qml:465", "comment": "" }, { "term": "Access to system controls and settings", "context": "Access to system controls and settings", - "reference": "Modules/Settings/DankBarTab.qml:306", + "reference": "Modules/Settings/DankBarTab.qml:458", "comment": "" }, { @@ -101,6 +113,36 @@ "reference": "Widgets/DankIconPicker.qml:46", "comment": "" }, + { + "term": "Activate", + "context": "Activate", + "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:356", + "comment": "" + }, + { + "term": "Active", + "context": "Active", + "reference": "Modules/Settings/NetworkTab.qml:688", + "comment": "" + }, + { + "term": "Active: ", + "context": "Active: ", + "reference": "Widgets/VpnDetailContent.qml:53, Widgets/VpnDetailContent.qml:54", + "comment": "" + }, + { + "term": "Active: None", + "context": "Active: None", + "reference": "Widgets/VpnDetailContent.qml:50", + "comment": "" + }, + { + "term": "Adapters", + "context": "Adapters", + "reference": "Modules/Settings/NetworkTab.qml:308", + "comment": "" + }, { "term": "Add", "context": "Add", @@ -110,37 +152,31 @@ { "term": "Add Bar", "context": "Add Bar", - "reference": "Modules/Settings/DankBarTab.qml:894", + "reference": "Modules/Settings/DankBarTab.qml:1159", "comment": "" }, { "term": "Add Widget", "context": "Add Widget", - "reference": "Modules/Settings/WidgetsTabSection.qml:757, Modules/ControlCenter/Components/EditControls.qml:58, Modules/ControlCenter/Components/EditControls.qml:159", + "reference": "Modules/Settings/WidgetsTabSection.qml:698, Modules/Settings/WidgetSelectionPopup.qml:92, Modules/ControlCenter/Components/EditControls.qml:58, Modules/ControlCenter/Components/EditControls.qml:159", "comment": "" }, { - "term": "Add Widget to ", - "context": "Add Widget to ", - "reference": "Modules/Settings/WidgetSelectionPopup.qml:202", - "comment": "" - }, - { - "term": "Add a VPN in NetworkManager", - "context": "Add a VPN in NetworkManager", - "reference": "Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:147, Modules/DankBar/Popouts/VpnPopout.qml:278", + "term": "Add Widget to %1 Section", + "context": "Add Widget to %1 Section", + "reference": "Modules/Settings/WidgetSelectionPopup.qml:198", "comment": "" }, { "term": "Adjust the number of columns in grid view mode.", "context": "Adjust the number of columns in grid view mode.", - "reference": "Modules/Settings/LauncherTab.qml:564", + "reference": "Modules/Settings/LauncherTab.qml:565", "comment": "" }, { "term": "All", "context": "All", - "reference": "Services/AppSearchService.qml:310, Services/AppSearchService.qml:326, Modals/Spotlight/SpotlightModal.qml:65, Modules/AppDrawer/CategorySelector.qml:11, Modules/AppDrawer/AppLauncher.qml:16, Modules/AppDrawer/AppLauncher.qml:27, Modules/AppDrawer/AppLauncher.qml:28, Modules/AppDrawer/AppLauncher.qml:45, Modules/AppDrawer/AppLauncher.qml:46, Modules/AppDrawer/AppLauncher.qml:80, Modules/AppDrawer/AppDrawerPopout.qml:36", + "reference": "Services/AppSearchService.qml:310, Services/AppSearchService.qml:326, Modals/Spotlight/SpotlightModal.qml:65, Modules/AppDrawer/CategorySelector.qml:11, Modules/AppDrawer/AppLauncher.qml:16, Modules/AppDrawer/AppLauncher.qml:27, Modules/AppDrawer/AppLauncher.qml:28, Modules/AppDrawer/AppLauncher.qml:45, Modules/AppDrawer/AppLauncher.qml:46, Modules/AppDrawer/AppLauncher.qml:80, Modules/AppDrawer/AppDrawerPopout.qml:32", "comment": "" }, { @@ -152,7 +188,7 @@ { "term": "All displays", "context": "All displays", - "reference": "Modules/Settings/DisplaysTab.qml:787, Modules/Settings/DankBarTab.qml:992, Modules/Settings/DankBarTab.qml:1183", + "reference": "Modules/Settings/DisplaysTab.qml:796, Modules/Settings/DankBarTab.qml:1241, Modules/Settings/DankBarTab.qml:1432", "comment": "" }, { @@ -164,109 +200,91 @@ { "term": "Always Show OSD Percentage", "context": "Always Show OSD Percentage", - "reference": "Modules/Settings/WidgetTweaksTab.qml:676", + "reference": "Modules/Settings/WidgetTweaksTab.qml:665", "comment": "" }, { "term": "Always on icons", "context": "Always on icons", - "reference": "Modules/Settings/WidgetsTabSection.qml:1036", + "reference": "Modules/Settings/WidgetsTabSection.qml:915", "comment": "" }, { "term": "Always show a minimum of 3 workspaces, even if fewer are available", "context": "Always show a minimum of 3 workspaces, even if fewer are available", - "reference": "Modules/Settings/WidgetTweaksTab.qml:70", + "reference": "Modules/Settings/WidgetTweaksTab.qml:68", "comment": "" }, { "term": "Animation Speed", "context": "Animation Speed", - "reference": "Modules/Settings/PersonalizationTab.qml:1580", + "reference": "Modules/Settings/PersonalizationTab.qml:1575", + "comment": "" + }, + { + "term": "Anonymous Identity", + "context": "Anonymous Identity", + "reference": "Modals/WifiPasswordModal.qml:134", "comment": "" }, { "term": "Anonymous Identity (optional)", "context": "Anonymous Identity (optional)", - "reference": "Modals/WifiPasswordModal.qml:403", + "reference": "Modals/WifiPasswordModal.qml:459", "comment": "" }, { "term": "App Launcher", "context": "App Launcher", - "reference": "Modules/Settings/DankBarTab.qml:195", + "reference": "Modules/Settings/DankBarTab.qml:347", "comment": "" }, { "term": "Application Dock", "context": "Application Dock", - "reference": "Modules/Settings/DisplaysTab.qml:30", + "reference": "Modules/Settings/DisplaysTab.qml:28", "comment": "" }, { "term": "Applications", "context": "Applications", - "reference": "Modules/AppDrawer/AppDrawerPopout.qml:179, Modules/Settings/ThemeColorsTab.qml:1200", + "reference": "Modules/AppDrawer/AppDrawerPopout.qml:172, Modules/Settings/ThemeColorsTab.qml:1201", "comment": "" }, { "term": "Apply GTK Colors", "context": "Apply GTK Colors", - "reference": "Modules/Settings/ThemeColorsTab.qml:1376", + "reference": "Modules/Settings/ThemeColorsTab.qml:1371", "comment": "" }, { "term": "Apply Qt Colors", "context": "Apply Qt Colors", - "reference": "Modules/Settings/ThemeColorsTab.qml:1412", + "reference": "Modules/Settings/ThemeColorsTab.qml:1407", "comment": "" }, { "term": "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.", "context": "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.", - "reference": "Modules/Settings/DisplaysTab.qml:168", + "reference": "Modules/Settings/DisplaysTab.qml:177", "comment": "" }, { "term": "Apps Icon", "context": "Apps Icon", - "reference": "Modules/Settings/LauncherTab.qml:88", + "reference": "Modules/Settings/LauncherTab.qml:84", "comment": "" }, { "term": "Apps are ordered by usage frequency, then last used, then alphabetically.", "context": "Apps are ordered by usage frequency, then last used, then alphabetically.", - "reference": "Modules/Settings/LauncherTab.qml:743", + "reference": "Modules/Settings/LauncherTab.qml:736", "comment": "" }, { - "term": "Are you sure you want to hibernate the system?", - "context": "Are you sure you want to hibernate the system?", - "reference": "Modals/PowerMenuModal.qml:168", - "comment": "" - }, - { - "term": "Are you sure you want to log out?", - "context": "Are you sure you want to log out?", - "reference": "Modals/PowerMenuModal.qml:160", - "comment": "" - }, - { - "term": "Are you sure you want to power off the system?", - "context": "Are you sure you want to power off the system?", - "reference": "Modals/PowerMenuModal.qml:176", - "comment": "" - }, - { - "term": "Are you sure you want to reboot the system?", - "context": "Are you sure you want to reboot the system?", - "reference": "Modals/PowerMenuModal.qml:172", - "comment": "" - }, - { - "term": "Are you sure you want to suspend the system?", - "context": "Are you sure you want to suspend the system?", - "reference": "Modals/PowerMenuModal.qml:164", + "term": "Audio", + "context": "Audio", + "reference": "Modules/Settings/WidgetsTabSection.qml:775", "comment": "" }, { @@ -284,37 +302,49 @@ { "term": "Audio Devices", "context": "Audio Devices", - "reference": "Modules/ControlCenter/Details/AudioOutputDetail.qml:35", - "comment": "" - }, - { - "term": "Audio Icon", - "context": "Audio Icon", - "reference": "Modules/Settings/WidgetsTabSection.qml:948", + "reference": "Modules/ControlCenter/Details/AudioOutputDetail.qml:34", "comment": "" }, { "term": "Audio Output Devices (", "context": "Audio Output Devices (", - "reference": "Modules/DankDash/MediaPlayerTab.qml:405", + "reference": "Modules/DankDash/MediaDropdownOverlay.qml:231", + "comment": "" + }, + { + "term": "Auth", + "context": "Auth", + "reference": "Widgets/VpnDetailContent.qml:399, Modules/Settings/NetworkTab.qml:1765", + "comment": "" + }, + { + "term": "Auth Type", + "context": "Auth Type", + "reference": "Widgets/VpnDetailContent.qml:414, Modules/Settings/NetworkTab.qml:1780", "comment": "" }, { "term": "Authenticate", "context": "Authenticate", - "reference": "Modals/PolkitAuthModal.qml:330", + "reference": "Modals/PolkitAuthModal.qml:291", + "comment": "" + }, + { + "term": "Authentication", + "context": "Authentication", + "reference": "Modals/PolkitAuthModal.qml:45", "comment": "" }, { "term": "Authentication Required", "context": "Authentication Required", - "reference": "Modals/PolkitAuthModal.qml:142", + "reference": "Modals/PolkitAuthModal.qml:124", "comment": "" }, { "term": "Authentication failed, please try again", "context": "Authentication failed, please try again", - "reference": "Modals/PolkitAuthModal.qml:252", + "reference": "Modals/PolkitAuthModal.qml:220", "comment": "" }, { @@ -335,28 +365,34 @@ "reference": "Modals/BluetoothPairingModal.qml:142", "comment": "" }, + { + "term": "Auto", + "context": "Auto", + "reference": "Modules/Settings/NetworkTab.qml:206, Modules/Settings/NetworkTab.qml:815, Modules/Settings/NetworkTab.qml:819, Modules/Settings/NetworkTab.qml:820, Modules/Settings/NetworkTab.qml:823, Modules/ControlCenter/Details/NetworkDetail.qml:102, Modules/ControlCenter/Details/NetworkDetail.qml:103, Modules/ControlCenter/Details/NetworkDetail.qml:106, Modules/ControlCenter/Details/NetworkDetail.qml:109", + "comment": "" + }, { "term": "Auto Location", "context": "Auto Location", - "reference": "Modules/Settings/TimeWeatherTab.qml:609", + "reference": "Modules/Settings/TimeWeatherTab.qml:607", "comment": "" }, { "term": "Auto Popup Gaps", "context": "Auto Popup Gaps", - "reference": "Modules/Settings/DankBarTab.qml:1882", + "reference": "Modules/Settings/DankBarTab.qml:2134", "comment": "" }, { "term": "Auto-hide", "context": "Auto-hide", - "reference": "Modules/Settings/DankBarTab.qml:1389", + "reference": "Modules/Settings/DankBarTab.qml:1647", "comment": "" }, { "term": "Auto-hide Dock", "context": "Auto-hide Dock", - "reference": "Modules/Settings/DockTab.qml:181", + "reference": "Modules/Settings/DockTab.qml:189", "comment": "" }, { @@ -365,82 +401,88 @@ "reference": "Modules/Notepad/NotepadTextEditor.qml:581", "comment": "" }, + { + "term": "Autoconnect", + "context": "Autoconnect", + "reference": "Widgets/VpnDetailContent.qml:418, Modules/Settings/NetworkTab.qml:1368, Modules/Settings/NetworkTab.qml:1784", + "comment": "" + }, { "term": "Autoconnect disabled", "context": "Autoconnect disabled", - "reference": "Services/DMSNetworkService.qml:885", + "reference": "Services/DMSNetworkService.qml:938", "comment": "" }, { "term": "Autoconnect enabled", "context": "Autoconnect enabled", - "reference": "Services/DMSNetworkService.qml:885", + "reference": "Services/DMSNetworkService.qml:938", "comment": "" }, { "term": "Automatic Control", "context": "Automatic Control", - "reference": "Modules/Settings/DisplaysTab.qml:237", + "reference": "Modules/Settings/DisplaysTab.qml:246", "comment": "" }, { "term": "Automatic Cycling", "context": "Automatic Cycling", - "reference": "Modules/Settings/PersonalizationTab.qml:1111", + "reference": "Modules/Settings/PersonalizationTab.qml:1103", "comment": "" }, { "term": "Automatically calculate popup distance from bar edge.", "context": "Automatically calculate popup distance from bar edge.", - "reference": "Modules/Settings/DankBarTab.qml:1883", + "reference": "Modules/Settings/DankBarTab.qml:2135", "comment": "" }, { "term": "Automatically cycle through wallpapers in the same folder", "context": "Automatically cycle through wallpapers in the same folder", - "reference": "Modules/Settings/PersonalizationTab.qml:1118", + "reference": "Modules/Settings/PersonalizationTab.qml:1110", "comment": "" }, { "term": "Automatically detect location based on IP address", "context": "Automatically detect location based on IP address", - "reference": "Modules/Settings/DisplaysTab.qml:441", + "reference": "Modules/Settings/DisplaysTab.qml:453", "comment": "" }, { "term": "Automatically determine your location using your IP address", "context": "Automatically determine your location using your IP address", - "reference": "Modules/Settings/TimeWeatherTab.qml:616", + "reference": "Modules/Settings/TimeWeatherTab.qml:614", "comment": "" }, { "term": "Automatically extract colors from wallpaper", "context": "Automatically extract colors from wallpaper", - "reference": "Modules/Settings/PersonalizationTab.qml:1784", + "reference": "Modules/Settings/PersonalizationTab.qml:1779", "comment": "" }, { "term": "Automatically hide the top bar to expand screen real estate", "context": "Automatically hide the top bar to expand screen real estate", - "reference": "Modules/Settings/DankBarTab.qml:1396", + "reference": "Modules/Settings/DankBarTab.qml:1654", "comment": "" }, { "term": "Automatically lock after", "context": "Automatically lock after", - "reference": "Modals/Settings/PowerSettings.qml:169", + "reference": "Modals/Settings/PowerSettings.qml:204", "comment": "" }, { "term": "Automatically lock the screen when the system prepares to suspend", "context": "Automatically lock the screen when the system prepares to suspend", - "reference": "Modals/Settings/PowerSettings.qml:88", + "reference": "Modals/Settings/PowerSettings.qml:89", "comment": "" }, { "term": "Available", "context": "Available", - "reference": "Modules/ProcessList/SystemTab.qml:478", + "reference": "Modules/ProcessList/SystemTab.qml:464", "comment": "" }, { @@ -449,64 +491,82 @@ "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:222", "comment": "" }, + { + "term": "Available Networks", + "context": "Available Networks", + "reference": "Modules/Settings/NetworkTab.qml:941", + "comment": "" + }, { "term": "Available Plugins", "context": "Available Plugins", - "reference": "Modules/Settings/PluginsTab.qml:211", + "reference": "Modules/Settings/PluginsTab.qml:214", "comment": "" }, { "term": "Available Screens (", "context": "Available Screens (", - "reference": "Modules/Settings/DisplaysTab.qml:593", + "reference": "Modules/Settings/DisplaysTab.qml:603", + "comment": "" + }, + { + "term": "BSSID", + "context": "BSSID", + "reference": "Modules/Settings/NetworkTab.qml:1316", "comment": "" }, { "term": "Back", "context": "Back", - "reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:1238", + "reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:1281", + "comment": "" + }, + { + "term": "Backend", + "context": "Backend", + "reference": "Modules/Settings/NetworkTab.qml:116", "comment": "" }, { "term": "Balanced palette with focused accents (default).", "context": "Balanced palette with focused accents (default).", - "reference": "Common/Theme.qml:208", + "reference": "Common/Theme.qml:209", "comment": "" }, { "term": "Bar Configurations", "context": "Bar Configurations", - "reference": "Modules/Settings/DankBarTab.qml:861", + "reference": "Modules/Settings/DankBarTab.qml:1146", "comment": "" }, { "term": "Bar Transparency", "context": "Bar Transparency", - "reference": "Modules/Settings/DankBarTab.qml:2373, Modules/Settings/DankBarTab.qml:2387", + "reference": "Modules/Settings/DankBarTab.qml:2861, Modules/Settings/DankBarTab.qml:2875", "comment": "" }, { "term": "Battery", "context": "Battery", - "reference": "Modules/Settings/DankBarTab.qml:319", + "reference": "Modules/Settings/WidgetsTabSection.qml:793, Modules/Settings/DankBarTab.qml:471", "comment": "" }, { "term": "Battery level and power management", "context": "Battery level and power management", - "reference": "Modules/Settings/DankBarTab.qml:320", + "reference": "Modules/Settings/DankBarTab.qml:472", "comment": "" }, { "term": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen", "context": "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen", - "reference": "Modals/Settings/PowerSettings.qml:75", + "reference": "Modals/Settings/PowerSettings.qml:76", "comment": "" }, { - "term": "Bluetooth Icon", - "context": "Bluetooth Icon", - "reference": "Modules/Settings/WidgetsTabSection.qml:895", + "term": "Bluetooth", + "context": "Bluetooth", + "reference": "Modules/Settings/WidgetsTabSection.qml:769", "comment": "" }, { @@ -518,79 +578,79 @@ { "term": "Blur on Overview", "context": "Blur on Overview", - "reference": "Modules/Settings/PersonalizationTab.qml:911", + "reference": "Modules/Settings/PersonalizationTab.qml:903", "comment": "" }, { "term": "Blur wallpaper when niri overview is open", "context": "Blur wallpaper when niri overview is open", - "reference": "Modules/Settings/PersonalizationTab.qml:918", + "reference": "Modules/Settings/PersonalizationTab.qml:910", "comment": "" }, { "term": "Border", "context": "Border", - "reference": "Modules/Settings/DankBarTab.qml:2120", + "reference": "Modules/Settings/DankBarTab.qml:2369", "comment": "" }, { "term": "Border Color", "context": "Border Color", - "reference": "Modules/Settings/DankBarTab.qml:2152", + "reference": "Modules/Settings/DankBarTab.qml:2401", "comment": "" }, { "term": "Border Opacity", "context": "Border Opacity", - "reference": "Modules/Settings/DankBarTab.qml:2214, Modules/Settings/DankBarTab.qml:2228", + "reference": "Modules/Settings/DankBarTab.qml:2463, Modules/Settings/DankBarTab.qml:2477", "comment": "" }, { "term": "Border Thickness", "context": "Border Thickness", - "reference": "Modules/Settings/DankBarTab.qml:2289, Modules/Settings/DankBarTab.qml:2303", + "reference": "Modules/Settings/DankBarTab.qml:2537, Modules/Settings/DankBarTab.qml:2551", "comment": "" }, { "term": "Bottom", "context": "Bottom", - "reference": "Modules/Settings/DankBarTab.qml:969, Modules/Settings/DankBarTab.qml:1300", + "reference": "Modules/Settings/DankBarTab.qml:1218, Modules/Settings/DankBarTab.qml:1558", "comment": "" }, { "term": "Bottom Section", "context": "Bottom Section", - "reference": "Modules/Settings/DankBarTab.qml:2858", + "reference": "Modules/Settings/DankBarTab.qml:3346", "comment": "" }, { "term": "Bottom dock for pinned and running applications", "context": "Bottom dock for pinned and running applications", - "reference": "Modules/Settings/DisplaysTab.qml:31", + "reference": "Modules/Settings/DisplaysTab.qml:29", "comment": "" }, { "term": "Brightness", "context": "Brightness", - "reference": "Modules/Settings/LauncherTab.qml:325", + "reference": "Modules/Settings/WidgetsTabSection.qml:787, Modules/Settings/LauncherTab.qml:331", "comment": "" }, { "term": "Brightness OSD", "context": "Brightness OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:826", + "reference": "Modules/Settings/WidgetTweaksTab.qml:813", "comment": "" }, { "term": "Browse", "context": "Browse", - "reference": "Modules/Settings/PluginsTab.qml:125", + "reference": "Modules/Settings/PluginsTab.qml:128", "comment": "" }, { "term": "Browse Plugins", "context": "Browse Plugins", - "reference": "Modules/Settings/PluginBrowser.qml:197", + "reference": "Modules/Settings/PluginBrowser.qml:105, Modules/Settings/PluginBrowser.qml:174", "comment": "" }, { @@ -602,25 +662,25 @@ { "term": "CPU Temperature", "context": "CPU Temperature", - "reference": "Modules/Settings/DankBarTab.qml:275", + "reference": "Modules/Settings/DankBarTab.qml:427", "comment": "" }, { "term": "CPU Usage", "context": "CPU Usage", - "reference": "Modules/Settings/DankBarTab.qml:251", + "reference": "Modules/Settings/DankBarTab.qml:403", "comment": "" }, { "term": "CPU temperature display", "context": "CPU temperature display", - "reference": "Modules/Settings/DankBarTab.qml:276", + "reference": "Modules/Settings/DankBarTab.qml:428", "comment": "" }, { "term": "CPU usage indicator", "context": "CPU usage indicator", - "reference": "Modules/Settings/DankBarTab.qml:252", + "reference": "Modules/Settings/DankBarTab.qml:404", "comment": "" }, { @@ -638,13 +698,13 @@ { "term": "Camera", "context": "Camera", - "reference": "Modules/Settings/WidgetsTabSection.qml:1117", + "reference": "Modules/Settings/WidgetsTabSection.qml:996", "comment": "" }, { "term": "Cancel", "context": "Cancel", - "reference": "Modals/BluetoothPairingModal.qml:272, Modals/PolkitAuthModal.qml:297, Modals/WifiPasswordModal.qml:553, Modals/FileBrowser/FileBrowserOverwriteDialog.qml:83, Modules/Settings/PluginBrowser.qml:650", + "reference": "Modals/BluetoothPairingModal.qml:272, Modals/PolkitAuthModal.qml:264, Modals/WifiPasswordModal.qml:605, Modals/FileBrowser/FileBrowserOverwriteDialog.qml:83, Modules/Settings/PluginBrowser.qml:634", "comment": "" }, { @@ -656,19 +716,19 @@ { "term": "Caps Lock Indicator", "context": "Caps Lock Indicator", - "reference": "Modules/Settings/DankBarTab.qml:340", + "reference": "Modules/Settings/DankBarTab.qml:492", "comment": "" }, { "term": "Caps Lock OSD", "context": "Caps Lock OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:856", + "reference": "Modules/Settings/WidgetTweaksTab.qml:843", "comment": "" }, { "term": "Center Section", "context": "Center Section", - "reference": "Modules/Settings/DankBarTab.qml:2802", + "reference": "Modules/Settings/DankBarTab.qml:3288", "comment": "" }, { @@ -677,6 +737,12 @@ "reference": "Modules/DankBar/Popouts/DWLLayoutPopout.qml:50", "comment": "" }, + { + "term": "Certificate Password", + "context": "Certificate Password", + "reference": "Modals/WifiPasswordModal.qml:126", + "comment": "" + }, { "term": "Change bar appearance", "context": "Change bar appearance", @@ -689,10 +755,16 @@ "reference": "Modals/DisplayConfirmationModal.qml:122", "comment": "" }, + { + "term": "Channel", + "context": "Channel", + "reference": "Modules/Settings/NetworkTab.qml:1301", + "comment": "" + }, { "term": "Check for system updates", "context": "Check for system updates", - "reference": "Modules/Settings/DankBarTab.qml:390", + "reference": "Modules/Settings/DankBarTab.qml:542", "comment": "" }, { @@ -704,7 +776,7 @@ { "term": "Choose Launcher Logo Color", "context": "Choose Launcher Logo Color", - "reference": "Modules/Settings/LauncherTab.qml:252", + "reference": "Modules/Settings/LauncherTab.qml:258", "comment": "" }, { @@ -716,37 +788,49 @@ { "term": "Choose the background color for widgets", "context": "Choose the background color for widgets", - "reference": "Modules/Settings/ThemeColorsTab.qml:781", + "reference": "Modules/Settings/ThemeColorsTab.qml:785", "comment": "" }, { "term": "Choose the border accent color", "context": "Choose the border accent color", - "reference": "Modules/Settings/DankBarTab.qml:2159", + "reference": "Modules/Settings/DankBarTab.qml:2408", "comment": "" }, { "term": "Choose the logo displayed on the launcher button in DankBar", "context": "Choose the logo displayed on the launcher button in DankBar", - "reference": "Modules/Settings/LauncherTab.qml:74", + "reference": "Modules/Settings/LauncherTab.qml:70", + "comment": "" + }, + { + "term": "Choose the widget outline accent color", + "context": "Choose the widget outline accent color", + "reference": "Modules/Settings/DankBarTab.qml:2649", "comment": "" }, { "term": "Choose where notification popups appear on screen", "context": "Choose where notification popups appear on screen", - "reference": "Modules/Settings/WidgetTweaksTab.qml:603", + "reference": "Modules/Settings/WidgetTweaksTab.qml:593", "comment": "" }, { "term": "Choose where on-screen displays appear on screen", "context": "Choose where on-screen displays appear on screen", - "reference": "Modules/Settings/WidgetTweaksTab.qml:748", + "reference": "Modules/Settings/WidgetTweaksTab.qml:736", + "comment": "" + }, + { + "term": "Cipher", + "context": "Cipher", + "reference": "Widgets/VpnDetailContent.qml:394, Modules/Settings/NetworkTab.qml:1760", "comment": "" }, { "term": "Clear", "context": "Clear", - "reference": "Modules/Notifications/Center/NotificationHeader.qml:102", + "reference": "Modules/Notifications/Center/NotificationHeader.qml:98", "comment": "" }, { @@ -761,6 +845,12 @@ "reference": "Modals/Clipboard/ClipboardContent.qml:33", "comment": "" }, + { + "term": "Click Import to add a .ovpn or .conf", + "context": "Click Import to add a .ovpn or .conf", + "reference": "Widgets/VpnDetailContent.qml:179, Modules/Settings/NetworkTab.qml:1547", + "comment": "" + }, { "term": "Clipboard History", "context": "Clipboard History", @@ -770,25 +860,25 @@ { "term": "Clipboard Manager", "context": "Clipboard Manager", - "reference": "Modules/Settings/DankBarTab.qml:244", + "reference": "Modules/Settings/DankBarTab.qml:396", "comment": "" }, { "term": "Clock", "context": "Clock", - "reference": "Modules/Settings/DankBarTab.qml:223", + "reference": "Modules/Settings/DankBarTab.qml:375", "comment": "" }, { "term": "Clock show seconds", "context": "Clock show seconds", - "reference": "Modules/Settings/TimeWeatherTab.qml:128", + "reference": "Modules/Settings/TimeWeatherTab.qml:123", "comment": "" }, { "term": "Close", "context": "Close", - "reference": "Modules/SystemUpdatePopout.qml:335, Modals/NetworkWiredInfoModal.qml:129, Modals/NetworkInfoModal.qml:129, Modules/DankBar/Widgets/RunningApps.qml:860", + "reference": "Modules/SystemUpdatePopout.qml:335, Modals/NetworkWiredInfoModal.qml:129, Modals/NetworkInfoModal.qml:129, Modules/DankBar/Widgets/RunningApps.qml:920", "comment": "" }, { @@ -800,67 +890,67 @@ { "term": "Color Override", "context": "Color Override", - "reference": "Modules/Settings/LauncherTab.qml:188", + "reference": "Modules/Settings/LauncherTab.qml:190", "comment": "" }, { "term": "Color Picker", "context": "Color Picker", - "reference": "Modules/Settings/DankBarTab.qml:382", + "reference": "Modules/Settings/DankBarTab.qml:534", "comment": "" }, { "term": "Color temperature for day time", "context": "Color temperature for day time", - "reference": "Modules/Settings/DisplaysTab.qml:215", + "reference": "Modules/Settings/DisplaysTab.qml:224", "comment": "" }, { "term": "Color temperature for night mode", "context": "Color temperature for night mode", - "reference": "Modules/Settings/DisplaysTab.qml:194", + "reference": "Modules/Settings/DisplaysTab.qml:203", "comment": "" }, { "term": "Colorful mix of bright contrasting accents.", "context": "Colorful mix of bright contrasting accents.", - "reference": "Common/Theme.qml:238", + "reference": "Common/Theme.qml:233", "comment": "" }, { "term": "Command or script to run instead of the standard hibernate procedure", "context": "Command or script to run instead of the standard hibernate procedure", - "reference": "Modals/Settings/PowerSettings.qml:695", + "reference": "Modals/Settings/PowerSettings.qml:773", "comment": "" }, { "term": "Command or script to run instead of the standard lock procedure", "context": "Command or script to run instead of the standard lock procedure", - "reference": "Modals/Settings/PowerSettings.qml:599", + "reference": "Modals/Settings/PowerSettings.qml:677", "comment": "" }, { "term": "Command or script to run instead of the standard logout procedure", "context": "Command or script to run instead of the standard logout procedure", - "reference": "Modals/Settings/PowerSettings.qml:631", + "reference": "Modals/Settings/PowerSettings.qml:709", "comment": "" }, { "term": "Command or script to run instead of the standard power off procedure", "context": "Command or script to run instead of the standard power off procedure", - "reference": "Modals/Settings/PowerSettings.qml:759", + "reference": "Modals/Settings/PowerSettings.qml:837", "comment": "" }, { "term": "Command or script to run instead of the standard reboot procedure", "context": "Command or script to run instead of the standard reboot procedure", - "reference": "Modals/Settings/PowerSettings.qml:727", + "reference": "Modals/Settings/PowerSettings.qml:805", "comment": "" }, { "term": "Command or script to run instead of the standard suspend procedure", "context": "Command or script to run instead of the standard suspend procedure", - "reference": "Modals/Settings/PowerSettings.qml:663", + "reference": "Modals/Settings/PowerSettings.qml:741", "comment": "" }, { @@ -872,31 +962,31 @@ { "term": "Compact Mode", "context": "Compact Mode", - "reference": "Modules/Settings/WidgetsTabSection.qml:551", + "reference": "Modules/Settings/WidgetsTabSection.qml:485", "comment": "" }, { "term": "Compositor", "context": "Compositor", - "reference": "Modules/Settings/LauncherTab.qml:98", + "reference": "Modules/Settings/LauncherTab.qml:94", "comment": "" }, { "term": "Configuration activated", "context": "Configuration activated", - "reference": "Services/DMSNetworkService.qml:374", + "reference": "Services/DMSNetworkService.qml:389", "comment": "" }, { "term": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.", "context": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.", - "reference": "Modules/Settings/WidgetTweaksTab.qml:439", + "reference": "Modules/Settings/WidgetTweaksTab.qml:442", "comment": "" }, { "term": "Configure which displays show shell components", "context": "Configure which displays show shell components", - "reference": "Modules/Settings/DisplaysTab.qml:569", + "reference": "Modules/Settings/DisplaysTab.qml:581", "comment": "" }, { @@ -920,25 +1010,31 @@ { "term": "Connect", "context": "Connect", - "reference": "Modals/WifiPasswordModal.qml:595", + "reference": "Modals/WifiPasswordModal.qml:645", "comment": "" }, { "term": "Connect to VPN", "context": "Connect to VPN", - "reference": "Modals/WifiPasswordModal.qml:197", + "reference": "Modals/WifiPasswordModal.qml:256", "comment": "" }, { "term": "Connect to Wi-Fi", "context": "Connect to Wi-Fi", - "reference": "Modals/WifiPasswordModal.qml:199", + "reference": "Modals/WifiPasswordModal.qml:256", + "comment": "" + }, + { + "term": "Connected", + "context": "Connected", + "reference": "Modules/Settings/NetworkTab.qml:384, Modules/Settings/NetworkTab.qml:1105, Modules/Settings/NetworkTab.qml:1429, Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:21", "comment": "" }, { "term": "Connected Displays", "context": "Connected Displays", - "reference": "Modules/Settings/DisplaysTab.qml:562", + "reference": "Modules/Settings/DisplaysTab.qml:574", "comment": "" }, { @@ -950,25 +1046,25 @@ { "term": "Contrast", "context": "Contrast", - "reference": "Modules/Settings/LauncherTab.qml:354", + "reference": "Modules/Settings/LauncherTab.qml:360", "comment": "" }, { "term": "Control Center", "context": "Control Center", - "reference": "Modules/Settings/DankBarTab.qml:305", + "reference": "Modules/Settings/DankBarTab.qml:457", "comment": "" }, { "term": "Control currently playing media", "context": "Control currently playing media", - "reference": "Modules/Settings/DankBarTab.qml:238", + "reference": "Modules/Settings/DankBarTab.qml:390", "comment": "" }, { "term": "Controls opacity of all popouts, modals, and their content layers (DankDash, Settings, App Drawer, Control Center, etc.)", "context": "Controls opacity of all popouts, modals, and their content layers (DankDash, Settings, App Drawer, Control Center, etc.)", - "reference": "Modules/Settings/ThemeColorsTab.qml:835", + "reference": "Modules/Settings/ThemeColorsTab.qml:845", "comment": "" }, { @@ -998,13 +1094,13 @@ { "term": "Corner Radius (0 = square corners)", "context": "Corner Radius (0 = square corners)", - "reference": "Modules/Settings/ThemeColorsTab.qml:872", + "reference": "Modules/Settings/ThemeColorsTab.qml:880", "comment": "" }, { "term": "Corner Radius Override", "context": "Corner Radius Override", - "reference": "Modules/Settings/DankBarTab.qml:2026", + "reference": "Modules/Settings/DankBarTab.qml:2276", "comment": "" }, { @@ -1016,7 +1112,7 @@ { "term": "Create Dir", "context": "Create Dir", - "reference": "Modules/Settings/PluginsTab.qml:147", + "reference": "Modules/Settings/PluginsTab.qml:150", "comment": "" }, { @@ -1034,37 +1130,37 @@ { "term": "Current Weather", "context": "Current Weather", - "reference": "Modules/Settings/TimeWeatherTab.qml:832", + "reference": "Modules/Settings/TimeWeatherTab.qml:828", "comment": "" }, { "term": "Current time and date display", "context": "Current time and date display", - "reference": "Modules/Settings/DankBarTab.qml:224", + "reference": "Modules/Settings/DankBarTab.qml:376", "comment": "" }, { "term": "Current weather conditions and temperature", "context": "Current weather conditions and temperature", - "reference": "Modules/Settings/DankBarTab.qml:231", + "reference": "Modules/Settings/DankBarTab.qml:383", "comment": "" }, { "term": "Custom", "context": "Custom", - "reference": "Modules/Settings/LauncherTab.qml:100, Modules/Settings/LauncherTab.qml:201", + "reference": "Modules/Settings/LauncherTab.qml:96, Modules/Settings/LauncherTab.qml:203", "comment": "" }, { "term": "Custom Location", "context": "Custom Location", - "reference": "Modules/Settings/TimeWeatherTab.qml:649", + "reference": "Modules/Settings/TimeWeatherTab.qml:646", "comment": "" }, { "term": "Custom Power Actions", "context": "Custom Power Actions", - "reference": "Modals/Settings/PowerSettings.qml:585", + "reference": "Modals/Settings/PowerSettings.qml:663", "comment": "" }, { @@ -1076,31 +1172,31 @@ { "term": "Custom: ", "context": "Custom: ", - "reference": "Modules/Settings/TimeWeatherTab.qml:223, Modules/Settings/TimeWeatherTab.qml:285", + "reference": "Modules/Settings/TimeWeatherTab.qml:224, Modules/Settings/TimeWeatherTab.qml:293", "comment": "" }, { "term": "Customizable empty space", "context": "Customizable empty space", - "reference": "Modules/Settings/DankBarTab.qml:348", + "reference": "Modules/Settings/DankBarTab.qml:500", "comment": "" }, { "term": "Customize which actions appear in the power menu", "context": "Customize which actions appear in the power menu", - "reference": "Modals/Settings/PowerSettings.qml:363", + "reference": "Modals/Settings/PowerSettings.qml:398", "comment": "" }, { "term": "DEMO MODE - Click anywhere to exit", "context": "DEMO MODE - Click anywhere to exit", - "reference": "Modules/Lock/LockScreenContent.qml:777", + "reference": "Modules/Lock/LockScreenContent.qml:788", "comment": "" }, { "term": "DMS Plugin Manager Unavailable", "context": "DMS Plugin Manager Unavailable", - "reference": "Modules/Settings/PluginsTab.qml:102", + "reference": "Modules/Settings/PluginsTab.qml:105", "comment": "" }, { @@ -1112,37 +1208,37 @@ { "term": "DMS_SOCKET not available", "context": "DMS_SOCKET not available", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:201", + "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:203", "comment": "" }, { "term": "DWL service not available", "context": "DWL service not available", - "reference": "Modules/Settings/DankBarTab.qml:191", + "reference": "Modules/Settings/DankBarTab.qml:343", "comment": "" }, { "term": "Daily at:", "context": "Daily at:", - "reference": "Modules/Settings/PersonalizationTab.qml:1283", + "reference": "Modules/Settings/PersonalizationTab.qml:1278", "comment": "" }, { "term": "Dank", "context": "Dank", - "reference": "Modules/Settings/LauncherTab.qml:88", + "reference": "Modules/Settings/LauncherTab.qml:84", "comment": "" }, { "term": "Dank Bar", "context": "Dank Bar", - "reference": "Modals/Settings/SettingsSidebar.qml:23", + "reference": "Modals/Settings/SettingsSidebar.qml:26", "comment": "" }, { "term": "DankBar Font Scale", "context": "DankBar Font Scale", - "reference": "Modules/Settings/DankBarTab.qml:2539", + "reference": "Modules/Settings/DankBarTab.qml:3023", "comment": "" }, { @@ -1154,25 +1250,25 @@ { "term": "Dark Mode", "context": "Dark Mode", - "reference": "Modules/Settings/PersonalizationTab.qml:698, Modules/ControlCenter/Components/DragDropGrid.qml:599", + "reference": "Modules/Settings/PersonalizationTab.qml:690, Modules/ControlCenter/Components/DragDropGrid.qml:601", "comment": "" }, { "term": "Darken Modal Background", "context": "Darken Modal Background", - "reference": "Modules/Settings/ThemeColorsTab.qml:913", + "reference": "Modules/Settings/ThemeColorsTab.qml:920", "comment": "" }, { "term": "Date Format", "context": "Date Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:178", + "reference": "Modules/Settings/TimeWeatherTab.qml:171", "comment": "" }, { "term": "Day Temperature", "context": "Day Temperature", - "reference": "Modules/Settings/DisplaysTab.qml:214", + "reference": "Modules/Settings/DisplaysTab.qml:223", "comment": "" }, { @@ -1184,13 +1280,13 @@ { "term": "Default", "context": "Default", - "reference": "Modules/Settings/LauncherTab.qml:201", + "reference": "Modules/Settings/LauncherTab.qml:203", "comment": "" }, { "term": "Default selected action", "context": "Default selected action", - "reference": "Modals/Settings/PowerSettings.qml:382", + "reference": "Modals/Settings/PowerSettings.qml:417", "comment": "" }, { @@ -1205,10 +1301,22 @@ "reference": "Modules/Notifications/Center/NotificationKeyboardHints.qml:35", "comment": "" }, + { + "term": "Delete", + "context": "Delete", + "reference": "Widgets/VpnDetailContent.qml:326, Modules/Settings/NetworkTab.qml:1692", + "comment": "" + }, + { + "term": "Delete VPN", + "context": "Delete VPN", + "reference": "Widgets/VpnDetailContent.qml:324, Modules/Settings/NetworkTab.qml:1690", + "comment": "" + }, { "term": "Derives colors that closely match the underlying image.", "context": "Derives colors that closely match the underlying image.", - "reference": "Common/Theme.qml:223", + "reference": "Common/Theme.qml:221", "comment": "" }, { @@ -1226,7 +1334,7 @@ { "term": "Device", "context": "Device", - "reference": "Modules/ProcessList/SystemTab.qml:434", + "reference": "Modules/ProcessList/SystemTab.qml:420", "comment": "" }, { @@ -1238,37 +1346,43 @@ { "term": "Disable Autoconnect", "context": "Disable Autoconnect", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:699", + "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:757", "comment": "" }, { "term": "Disabled", "context": "Disabled", - "reference": "Modals/DisplayConfirmationModal.qml:144, Modules/Settings/DankBarTab.qml:1025", + "reference": "Modals/DisplayConfirmationModal.qml:144, Modules/Settings/NetworkTab.qml:755, Modules/Settings/DankBarTab.qml:1274", "comment": "" }, { "term": "Disconnect", "context": "Disconnect", - "reference": "Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:88, Modules/DankBar/Popouts/VpnPopout.qml:214", + "reference": "Widgets/VpnDetailContent.qml:120, Modules/Settings/NetworkTab.qml:1498, Modules/ControlCenter/Details/NetworkDetail.qml:381", + "comment": "" + }, + { + "term": "Disconnected", + "context": "Disconnected", + "reference": "Modules/Settings/NetworkTab.qml:161, Modules/Settings/NetworkTab.qml:386, Modules/Settings/NetworkTab.qml:1426, Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:18", "comment": "" }, { "term": "Disconnected from WiFi", "context": "Disconnected from WiFi", - "reference": "Services/DMSNetworkService.qml:449", + "reference": "Services/DMSNetworkService.qml:479", "comment": "" }, { "term": "Disk", "context": "Disk", - "reference": "Modules/ProcessList/PerformanceTab.qml:428", + "reference": "Modules/ProcessList/PerformanceTab.qml:403", "comment": "" }, { "term": "Disk Usage", "context": "Disk Usage", - "reference": "Modules/Settings/DankBarTab.qml:267", + "reference": "Modules/Settings/DankBarTab.qml:419", "comment": "" }, { @@ -1280,19 +1394,19 @@ { "term": "Display Assignment", "context": "Display Assignment", - "reference": "Modules/Settings/DankBarTab.qml:1155", + "reference": "Modules/Settings/DankBarTab.qml:1404", "comment": "" }, { "term": "Display Name Format", "context": "Display Name Format", - "reference": "Modules/Settings/DisplaysTab.qml:610", + "reference": "Modules/Settings/DisplaysTab.qml:620", "comment": "" }, { "term": "Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen", "context": "Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen", - "reference": "Modules/Settings/DockTab.qml:134", + "reference": "Modules/Settings/DockTab.qml:143", "comment": "" }, { @@ -1304,25 +1418,31 @@ { "term": "Display and switch DWL layouts", "context": "Display and switch DWL layouts", - "reference": "Modules/Settings/DankBarTab.qml:188", + "reference": "Modules/Settings/DankBarTab.qml:340", "comment": "" }, { "term": "Display application icons in workspace indicators", "context": "Display application icons in workspace indicators", - "reference": "Modules/Settings/WidgetTweaksTab.qml:81", + "reference": "Modules/Settings/WidgetTweaksTab.qml:78", "comment": "" }, { "term": "Display currently focused application title", "context": "Display currently focused application title", - "reference": "Modules/Settings/DankBarTab.qml:210", + "reference": "Modules/Settings/DankBarTab.qml:362", + "comment": "" + }, + { + "term": "Display only workspaces that contain windows", + "context": "Display only workspaces that contain windows", + "reference": "Modules/Settings/WidgetTweaksTab.qml:141", "comment": "" }, { "term": "Display power menu actions in a grid instead of a list", "context": "Display power menu actions in a grid instead of a list", - "reference": "Modals/Settings/PowerSettings.qml:373", + "reference": "Modals/Settings/PowerSettings.qml:408", "comment": "" }, { @@ -1334,55 +1454,55 @@ { "term": "Display volume and brightness percentage values by default in OSD popups", "context": "Display volume and brightness percentage values by default in OSD popups", - "reference": "Modules/Settings/WidgetTweaksTab.qml:683", + "reference": "Modules/Settings/WidgetTweaksTab.qml:672", "comment": "" }, { "term": "Displays", "context": "Displays", - "reference": "Modals/Settings/SettingsSidebar.qml:35", + "reference": "Modals/Settings/SettingsSidebar.qml:41", "comment": "" }, { "term": "Displays the active keyboard layout and allows switching", "context": "Displays the active keyboard layout and allows switching", - "reference": "Modules/Settings/DankBarTab.qml:370", + "reference": "Modules/Settings/DankBarTab.qml:522", "comment": "" }, { "term": "Diverse palette spanning the full spectrum.", "context": "Diverse palette spanning the full spectrum.", - "reference": "Common/Theme.qml:253", + "reference": "Common/Theme.qml:245", "comment": "" }, { "term": "Do Not Disturb", "context": "Do Not Disturb", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:601, Modules/Notifications/Center/NotificationHeader.qml:41, Modules/Notifications/Center/NotificationSettings.qml:131", + "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:603, Modules/Notifications/Center/NotificationHeader.qml:41, Modules/Notifications/Center/NotificationSettings.qml:131", "comment": "" }, { "term": "Dock", "context": "Dock", - "reference": "Modals/Settings/SettingsSidebar.qml:31", + "reference": "Modals/Settings/SettingsSidebar.qml:36", "comment": "" }, { "term": "Dock Position", "context": "Dock Position", - "reference": "Modules/Settings/DockTab.qml:52", + "reference": "Modules/Settings/DockTab.qml:50", "comment": "" }, { "term": "Dock Transparency", "context": "Dock Transparency", - "reference": "Modules/Settings/DockTab.qml:722", + "reference": "Modules/Settings/DockTab.qml:721", "comment": "" }, { "term": "Domain (optional)", "context": "Domain (optional)", - "reference": "Modals/WifiPasswordModal.qml:435", + "reference": "Modals/WifiPasswordModal.qml:490", "comment": "" }, { @@ -1400,31 +1520,37 @@ { "term": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.", "context": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.", - "reference": "Modules/Settings/DankBarTab.qml:2721", + "reference": "Modules/Settings/DankBarTab.qml:3205", + "comment": "" + }, + { + "term": "Driver", + "context": "Driver", + "reference": "Modules/Settings/NetworkTab.qml:547", "comment": "" }, { "term": "Duplicate Wallpaper with Blur", "context": "Duplicate Wallpaper with Blur", - "reference": "Modules/Settings/PersonalizationTab.qml:1467", + "reference": "Modules/Settings/PersonalizationTab.qml:1462", "comment": "" }, { "term": "Duration", "context": "Duration", - "reference": "Modules/Settings/PersonalizationTab.qml:1633", + "reference": "Modules/Settings/PersonalizationTab.qml:1628", "comment": "" }, { "term": "Dynamic Theming", "context": "Dynamic Theming", - "reference": "Modules/Settings/PersonalizationTab.qml:1777", + "reference": "Modules/Settings/PersonalizationTab.qml:1772", "comment": "" }, { "term": "Edge Spacing (0 = edge-to-edge)", "context": "Edge Spacing (0 = edge-to-edge)", - "reference": "Modules/Settings/DankBarTab.qml:1657, Modules/Settings/DankBarTab.qml:1671", + "reference": "Modules/Settings/DankBarTab.qml:1915, Modules/Settings/DankBarTab.qml:1929", "comment": "" }, { @@ -1442,13 +1568,13 @@ { "term": "Enable Autoconnect", "context": "Enable Autoconnect", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:699", + "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:757", "comment": "" }, { "term": "Enable Bar", "context": "Enable Bar", - "reference": "Modules/Settings/DankBarTab.qml:1100", + "reference": "Modules/Settings/DankBarTab.qml:1349", "comment": "" }, { @@ -1460,37 +1586,37 @@ { "term": "Enable System Sounds", "context": "Enable System Sounds", - "reference": "Modules/Settings/PersonalizationTab.qml:1933", + "reference": "Modules/Settings/PersonalizationTab.qml:1928", "comment": "" }, { "term": "Enable Weather", "context": "Enable Weather", - "reference": "Modules/Settings/TimeWeatherTab.qml:472", + "reference": "Modules/Settings/TimeWeatherTab.qml:476", "comment": "" }, { "term": "Enable WiFi", "context": "Enable WiFi", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:184", + "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:212", "comment": "" }, { "term": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", "context": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", - "reference": "Modules/Settings/PersonalizationTab.qml:1474", + "reference": "Modules/Settings/PersonalizationTab.qml:1469", "comment": "" }, { "term": "Enable fingerprint authentication", "context": "Enable fingerprint authentication", - "reference": "Modals/Settings/PowerSettings.qml:96", + "reference": "Modals/Settings/PowerSettings.qml:97", "comment": "" }, { "term": "Enable loginctl lock integration", "context": "Enable loginctl lock integration", - "reference": "Modals/Settings/PowerSettings.qml:74", + "reference": "Modals/Settings/PowerSettings.qml:75", "comment": "" }, { @@ -1502,7 +1628,7 @@ { "term": "End", "context": "End", - "reference": "Modules/Settings/DisplaysTab.qml:390", + "reference": "Modules/Settings/DisplaysTab.qml:402", "comment": "" }, { @@ -1532,19 +1658,19 @@ { "term": "Enter credentials for ", "context": "Enter credentials for ", - "reference": "Modals/WifiPasswordModal.qml:215", + "reference": "Modals/WifiPasswordModal.qml:269, Modals/WifiPasswordModal.qml:272", "comment": "" }, { "term": "Enter custom lock screen format (e.g., dddd, MMMM d)", "context": "Enter custom lock screen format (e.g., dddd, MMMM d)", - "reference": "Modules/Settings/TimeWeatherTab.qml:328", + "reference": "Modules/Settings/TimeWeatherTab.qml:335", "comment": "" }, { "term": "Enter custom top bar format (e.g., ddd MMM d)", "context": "Enter custom top bar format (e.g., ddd MMM d)", - "reference": "Modules/Settings/TimeWeatherTab.qml:315", + "reference": "Modules/Settings/TimeWeatherTab.qml:322", "comment": "" }, { @@ -1562,7 +1688,7 @@ { "term": "Enter password for ", "context": "Enter password for ", - "reference": "Modals/WifiPasswordModal.qml:213, Modals/WifiPasswordModal.qml:215", + "reference": "Modals/WifiPasswordModal.qml:271, Modals/WifiPasswordModal.qml:272", "comment": "" }, { @@ -1571,22 +1697,34 @@ "reference": "Modals/BluetoothPairingModal.qml:133", "comment": "" }, + { + "term": "Enterprise", + "context": "Enterprise", + "reference": "Modules/Settings/NetworkTab.qml:1321", + "comment": "" + }, { "term": "Error", "context": "Error", "reference": "Services/CupsService.qml:345", "comment": "" }, + { + "term": "Ethernet", + "context": "Ethernet", + "reference": "Modules/Settings/NetworkTab.qml:157, Modules/Settings/NetworkTab.qml:206, Modules/Settings/NetworkTab.qml:274", + "comment": "" + }, { "term": "Exclusive Zone Offset", "context": "Exclusive Zone Offset", - "reference": "Modules/Settings/DockTab.qml:572, Modules/Settings/DockTab.qml:586, Modules/Settings/DankBarTab.qml:1733, Modules/Settings/DankBarTab.qml:1747", + "reference": "Modules/Settings/DockTab.qml:573, Modules/Settings/DockTab.qml:587, Modules/Settings/DankBarTab.qml:1989, Modules/Settings/DankBarTab.qml:2003", "comment": "" }, { "term": "Execute templates from ~/.config/matugen/config.toml", "context": "Execute templates from ~/.config/matugen/config.toml", - "reference": "Modules/Settings/PersonalizationTab.qml:1870", + "reference": "Modules/Settings/PersonalizationTab.qml:1865", "comment": "" }, { @@ -1595,10 +1733,22 @@ "reference": "Modals/FileBrowser/FileInfo.qml:200", "comment": "" }, + { + "term": "Fade grace period", + "context": "Fade grace period", + "reference": "Modals/Settings/PowerSettings.qml:179", + "comment": "" + }, + { + "term": "Fade to lock screen", + "context": "Fade to lock screen", + "reference": "Modals/Settings/PowerSettings.qml:166", + "comment": "" + }, { "term": "Failed to activate configuration", "context": "Failed to activate configuration", - "reference": "Services/DMSNetworkService.qml:370", + "reference": "Services/DMSNetworkService.qml:385", "comment": "" }, { @@ -1616,37 +1766,55 @@ { "term": "Failed to connect VPN", "context": "Failed to connect VPN", - "reference": "Services/DMSNetworkService.qml:783", + "reference": "Services/DMSNetworkService.qml:829", "comment": "" }, { "term": "Failed to connect to ", "context": "Failed to connect to ", - "reference": "Services/DMSNetworkService.qml:343", + "reference": "Services/DMSNetworkService.qml:356", + "comment": "" + }, + { + "term": "Failed to delete VPN", + "context": "Failed to delete VPN", + "reference": "Services/VPNService.qml:156", "comment": "" }, { "term": "Failed to disconnect VPN", "context": "Failed to disconnect VPN", - "reference": "Services/DMSNetworkService.qml:807", + "reference": "Services/DMSNetworkService.qml:853", "comment": "" }, { "term": "Failed to disconnect VPNs", "context": "Failed to disconnect VPNs", - "reference": "Services/DMSNetworkService.qml:825", + "reference": "Services/DMSNetworkService.qml:871", "comment": "" }, { "term": "Failed to disconnect WiFi", "context": "Failed to disconnect WiFi", - "reference": "Services/DMSNetworkService.qml:447", + "reference": "Services/DMSNetworkService.qml:477", "comment": "" }, { "term": "Failed to enable WiFi", "context": "Failed to enable WiFi", - "reference": "Services/DMSNetworkService.qml:548", + "reference": "Services/DMSNetworkService.qml:580", + "comment": "" + }, + { + "term": "Failed to import VPN", + "context": "Failed to import VPN", + "reference": "Services/VPNService.qml:84", + "comment": "" + }, + { + "term": "Failed to load VPN config", + "context": "Failed to load VPN config", + "reference": "Services/VPNService.qml:114", "comment": "" }, { @@ -1682,19 +1850,25 @@ { "term": "Failed to start connection to ", "context": "Failed to start connection to ", - "reference": "Services/DMSNetworkService.qml:437", + "reference": "Services/DMSNetworkService.qml:464", + "comment": "" + }, + { + "term": "Failed to update VPN", + "context": "Failed to update VPN", + "reference": "Services/VPNService.qml:140", "comment": "" }, { "term": "Failed to update autoconnect", "context": "Failed to update autoconnect", - "reference": "Services/DMSNetworkService.qml:883", + "reference": "Services/DMSNetworkService.qml:936", "comment": "" }, { "term": "Feels Like", "context": "Feels Like", - "reference": "Modules/DankDash/WeatherTab.qml:260, Modules/Settings/TimeWeatherTab.qml:1086", + "reference": "Modules/DankDash/WeatherTab.qml:260, Modules/Settings/TimeWeatherTab.qml:1082", "comment": "" }, { @@ -1724,25 +1898,25 @@ { "term": "Focused Window", "context": "Focused Window", - "reference": "Modules/Settings/DankBarTab.qml:209", + "reference": "Modules/Settings/DankBarTab.qml:361", "comment": "" }, { "term": "Font Family", "context": "Font Family", - "reference": "Modules/Notepad/NotepadSettings.qml:211, Modules/Settings/ThemeColorsTab.qml:977", + "reference": "Modules/Notepad/NotepadSettings.qml:211, Modules/Settings/ThemeColorsTab.qml:983", "comment": "" }, { "term": "Font Scale", "context": "Font Scale", - "reference": "Modules/Settings/ThemeColorsTab.qml:1097", + "reference": "Modules/Settings/ThemeColorsTab.qml:1103", "comment": "" }, { "term": "Font Settings", "context": "Font Settings", - "reference": "Modules/Settings/ThemeColorsTab.qml:968", + "reference": "Modules/Settings/ThemeColorsTab.qml:974", "comment": "" }, { @@ -1754,7 +1928,7 @@ { "term": "Font Weight", "context": "Font Weight", - "reference": "Modules/Settings/ThemeColorsTab.qml:998", + "reference": "Modules/Settings/ThemeColorsTab.qml:1004", "comment": "" }, { @@ -1766,7 +1940,13 @@ { "term": "Force terminal applications to always use dark color schemes", "context": "Force terminal applications to always use dark color schemes", - "reference": "Modules/Settings/ThemeColorsTab.qml:1221", + "reference": "Modules/Settings/ThemeColorsTab.qml:1222", + "comment": "" + }, + { + "term": "Forget", + "context": "Forget", + "reference": "Modules/Settings/NetworkTab.qml:1200", "comment": "" }, { @@ -1778,19 +1958,25 @@ { "term": "Forget Network", "context": "Forget Network", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:722", + "reference": "Modules/Settings/NetworkTab.qml:1198, Modules/ControlCenter/Details/NetworkDetail.qml:780", "comment": "" }, { "term": "Forgot network ", "context": "Forgot network ", - "reference": "Services/DMSNetworkService.qml:505", + "reference": "Services/DMSNetworkService.qml:537", "comment": "" }, { "term": "Format Legend", "context": "Format Legend", - "reference": "Modules/Settings/TimeWeatherTab.qml:353", + "reference": "Modules/Settings/TimeWeatherTab.qml:359", + "comment": "" + }, + { + "term": "Frequency", + "context": "Frequency", + "reference": "Modules/Settings/NetworkTab.qml:1296", "comment": "" }, { @@ -1808,13 +1994,13 @@ { "term": "GPU Temperature", "context": "GPU Temperature", - "reference": "Modules/Settings/DankBarTab.qml:283", + "reference": "Modules/Settings/DankBarTab.qml:435", "comment": "" }, { "term": "GPU temperature display", "context": "GPU temperature display", - "reference": "Modules/Settings/DankBarTab.qml:284", + "reference": "Modules/Settings/DankBarTab.qml:436", "comment": "" }, { @@ -1826,37 +2012,43 @@ { "term": "Gamma Control", "context": "Gamma Control", - "reference": "Modules/Settings/DisplaysTab.qml:155", + "reference": "Modules/Settings/DisplaysTab.qml:164", "comment": "" }, { "term": "Gamma control not available. Requires DMS API v6+.", "context": "Gamma control not available. Requires DMS API v6+.", - "reference": "Modules/Settings/DisplaysTab.qml:168", + "reference": "Modules/Settings/DisplaysTab.qml:177", "comment": "" }, { "term": "Github:", "context": "Github:", - "reference": "Modules/Settings/AboutTab.qml:525", + "reference": "Modules/Settings/AboutTab.qml:526", "comment": "" }, { "term": "Good", "context": "Good", - "reference": "Modules/DankDash/WeatherTab.qml:519, Modules/Settings/TimeWeatherTab.qml:1345", + "reference": "Modules/DankDash/WeatherTab.qml:519, Modules/Settings/TimeWeatherTab.qml:1344", "comment": "" }, { "term": "Goth Corner Radius", "context": "Goth Corner Radius", - "reference": "Modules/Settings/DankBarTab.qml:2047, Modules/Settings/DankBarTab.qml:2061", + "reference": "Modules/Settings/DankBarTab.qml:2297, Modules/Settings/DankBarTab.qml:2311", "comment": "" }, { "term": "Goth Corners", "context": "Goth Corners", - "reference": "Modules/Settings/DankBarTab.qml:2014", + "reference": "Modules/Settings/DankBarTab.qml:2264", + "comment": "" + }, + { + "term": "Gradually fade the screen before locking with a configurable grace period", + "context": "Gradually fade the screen before locking with a configurable grace period", + "reference": "Modals/Settings/PowerSettings.qml:167", "comment": "" }, { @@ -1874,25 +2066,25 @@ { "term": "Grid Columns", "context": "Grid Columns", - "reference": "Modules/Settings/LauncherTab.qml:554", + "reference": "Modules/Settings/LauncherTab.qml:555", "comment": "" }, { "term": "Group by App", "context": "Group by App", - "reference": "Modules/Settings/DockTab.qml:304", + "reference": "Modules/Settings/DockTab.qml:309", "comment": "" }, { "term": "Group multiple windows of the same app together with a window count indicator", "context": "Group multiple windows of the same app together with a window count indicator", - "reference": "Modules/Settings/DockTab.qml:311", + "reference": "Modules/Settings/DockTab.qml:316", "comment": "" }, { "term": "HSV", "context": "HSV", - "reference": "Modals/DankColorPickerModal.qml:617", + "reference": "Modals/DankColorPickerModal.qml:647", "comment": "" }, { @@ -1904,73 +2096,109 @@ { "term": "Hex", "context": "Hex", - "reference": "Modals/DankColorPickerModal.qml:494", + "reference": "Modals/DankColorPickerModal.qml:524", "comment": "" }, { "term": "Hibernate", "context": "Hibernate", - "reference": "Modals/PowerMenuModal.qml:127, Modals/PowerMenuModal.qml:167, Modules/Lock/LockPowerMenu.qml:90", + "reference": "Modals/PowerMenuModal.qml:212, Modules/Lock/LockPowerMenu.qml:90", "comment": "" }, { "term": "Hide Delay (ms)", "context": "Hide Delay (ms)", - "reference": "Modules/Settings/DankBarTab.qml:1436, Modules/Settings/DankBarTab.qml:1450", + "reference": "Modules/Settings/DankBarTab.qml:1694, Modules/Settings/DankBarTab.qml:1708", "comment": "" }, { "term": "Hide the dock when not in use and reveal it when hovering near the dock area", "context": "Hide the dock when not in use and reveal it when hovering near the dock area", - "reference": "Modules/Settings/DockTab.qml:188", + "reference": "Modules/Settings/DockTab.qml:196", "comment": "" }, { "term": "High-contrast palette for strong visual distinction.", "context": "High-contrast palette for strong visual distinction.", - "reference": "Common/Theme.qml:218", + "reference": "Common/Theme.qml:217", "comment": "" }, { "term": "High-fidelity palette that preserves source hues.", "context": "High-fidelity palette that preserves source hues.", - "reference": "Common/Theme.qml:233", + "reference": "Common/Theme.qml:229", + "comment": "" + }, + { + "term": "Hold Duration", + "context": "Hold Duration", + "reference": "Modals/Settings/PowerSettings.qml:604", + "comment": "" + }, + { + "term": "Hold longer to confirm", + "context": "Hold longer to confirm", + "reference": "Modals/PowerMenuModal.qml:793", + "comment": "" + }, + { + "term": "Hold to Confirm Power Actions", + "context": "Hold to Confirm Power Actions", + "reference": "Modals/Settings/PowerSettings.qml:586", + "comment": "" + }, + { + "term": "Hold to confirm (%1s)", + "context": "Hold to confirm (%1s)", + "reference": "Modals/PowerMenuModal.qml:795, Modals/PowerMenuModal.qml:796", "comment": "" }, { "term": "Hour", "context": "Hour", - "reference": "Modules/Settings/DisplaysTab.qml:327", + "reference": "Modules/Settings/DisplaysTab.qml:339", "comment": "" }, { "term": "How often to change wallpaper", "context": "How often to change wallpaper", - "reference": "Modules/Settings/PersonalizationTab.qml:1229", + "reference": "Modules/Settings/PersonalizationTab.qml:1224", "comment": "" }, { "term": "Humidity", "context": "Humidity", - "reference": "Modules/DankDash/WeatherTab.qml:307, Modules/Settings/TimeWeatherTab.qml:1133", + "reference": "Modules/DankDash/WeatherTab.qml:307, Modules/Settings/TimeWeatherTab.qml:1129", "comment": "" }, { "term": "I Understand", "context": "I Understand", - "reference": "Modules/Settings/PluginBrowser.qml:656", + "reference": "Modules/Settings/PluginBrowser.qml:640", + "comment": "" + }, + { + "term": "IP", + "context": "IP", + "reference": "Modules/Settings/NetworkTab.qml:532", + "comment": "" + }, + { + "term": "IP Address:", + "context": "IP Address:", + "reference": "Modules/Settings/NetworkTab.qml:877", "comment": "" }, { "term": "Icon Size", "context": "Icon Size", - "reference": "Modules/Settings/DockTab.qml:419", + "reference": "Modules/Settings/DockTab.qml:422", "comment": "" }, { "term": "Icon Theme", "context": "Icon Theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:1294", + "reference": "Modules/Settings/ThemeColorsTab.qml:1292", "comment": "" }, { @@ -1982,25 +2210,25 @@ { "term": "Idle Inhibitor", "context": "Idle Inhibitor", - "reference": "Modules/Settings/DankBarTab.qml:333", + "reference": "Modules/Settings/DankBarTab.qml:485", "comment": "" }, { "term": "Idle Inhibitor OSD", "context": "Idle Inhibitor OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:836", + "reference": "Modules/Settings/WidgetTweaksTab.qml:823", "comment": "" }, { "term": "Idle Settings", "context": "Idle Settings", - "reference": "Modals/Settings/PowerSettings.qml:131", + "reference": "Modals/Settings/PowerSettings.qml:132", "comment": "" }, { "term": "Idle monitoring not supported - requires newer Quickshell version", "context": "Idle monitoring not supported - requires newer Quickshell version", - "reference": "Modals/Settings/PowerSettings.qml:319", + "reference": "Modals/Settings/PowerSettings.qml:354", "comment": "" }, { @@ -2009,22 +2237,34 @@ "reference": "Modals/Clipboard/ClipboardEntry.qml:83", "comment": "" }, + { + "term": "Import", + "context": "Import", + "reference": "Widgets/VpnDetailContent.qml:83, Modules/Settings/NetworkTab.qml:1461", + "comment": "" + }, + { + "term": "Import VPN", + "context": "Import VPN", + "reference": "Widgets/VpnDetailContent.qml:22, Modules/Settings/NetworkTab.qml:28", + "comment": "" + }, { "term": "Include Transitions", "context": "Include Transitions", - "reference": "Modules/Settings/PersonalizationTab.qml:1395", + "reference": "Modules/Settings/PersonalizationTab.qml:1390", "comment": "" }, { "term": "Incorrect password", "context": "Incorrect password", - "reference": "Modals/WifiPasswordModal.qml:226", + "reference": "Modals/WifiPasswordModal.qml:283", "comment": "" }, { "term": "Indicator Style", "context": "Indicator Style", - "reference": "Modules/Settings/DockTab.qml:362", + "reference": "Modules/Settings/DockTab.qml:366", "comment": "" }, { @@ -2036,25 +2276,31 @@ { "term": "Individual bar configuration", "context": "Individual bar configuration", - "reference": "Modules/Settings/DisplaysTab.qml:17", + "reference": "Modules/Settings/DisplaysTab.qml:16", "comment": "" }, { "term": "Inhibit idle timeout when audio or video is playing", "context": "Inhibit idle timeout when audio or video is playing", - "reference": "Modals/Settings/PowerSettings.qml:157", + "reference": "Modals/Settings/PowerSettings.qml:158", "comment": "" }, { "term": "Input Devices", "context": "Input Devices", - "reference": "Modules/ControlCenter/Details/AudioInputDetail.qml:35", + "reference": "Modules/ControlCenter/Details/AudioInputDetail.qml:34", "comment": "" }, { "term": "Install plugins from the DMS plugin registry", "context": "Install plugins from the DMS plugin registry", - "reference": "Modules/Settings/PluginBrowser.qml:251", + "reference": "Modules/Settings/PluginBrowser.qml:228", + "comment": "" + }, + { + "term": "Interface:", + "context": "Interface:", + "reference": "Modules/Settings/NetworkTab.qml:857", "comment": "" }, { @@ -2072,13 +2318,13 @@ { "term": "Interval", "context": "Interval", - "reference": "Modules/Settings/PersonalizationTab.qml:1228", + "reference": "Modules/Settings/PersonalizationTab.qml:1223", "comment": "" }, { "term": "Invert on mode change", "context": "Invert on mode change", - "reference": "Modules/Settings/LauncherTab.qml:383", + "reference": "Modules/Settings/LauncherTab.qml:389", "comment": "" }, { @@ -2096,7 +2342,7 @@ { "term": "Keep Awake", "context": "Keep Awake", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:603", + "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:605", "comment": "" }, { @@ -2108,13 +2354,13 @@ { "term": "Keeping Awake", "context": "Keeping Awake", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:603", + "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:605", "comment": "" }, { "term": "Keyboard Layout Name", "context": "Keyboard Layout Name", - "reference": "Modules/Settings/DankBarTab.qml:369", + "reference": "Modules/Settings/DankBarTab.qml:521", "comment": "" }, { @@ -2126,91 +2372,91 @@ { "term": "Last launched %1", "context": "Last launched %1", - "reference": "Modules/Settings/LauncherTab.qml:843", + "reference": "Modules/Settings/LauncherTab.qml:822", "comment": "" }, { "term": "Last launched %1 day%2 ago", "context": "Last launched %1 day%2 ago", - "reference": "Modules/Settings/LauncherTab.qml:839", + "reference": "Modules/Settings/LauncherTab.qml:820", "comment": "" }, { "term": "Last launched %1 hour%2 ago", "context": "Last launched %1 hour%2 ago", - "reference": "Modules/Settings/LauncherTab.qml:834", + "reference": "Modules/Settings/LauncherTab.qml:817", "comment": "" }, { "term": "Last launched %1 minute%2 ago", "context": "Last launched %1 minute%2 ago", - "reference": "Modules/Settings/LauncherTab.qml:829", + "reference": "Modules/Settings/LauncherTab.qml:814", "comment": "" }, { "term": "Last launched just now", "context": "Last launched just now", - "reference": "Modules/Settings/LauncherTab.qml:826", + "reference": "Modules/Settings/LauncherTab.qml:811", "comment": "" }, { "term": "Latitude", "context": "Latitude", - "reference": "Modules/Settings/DisplaysTab.qml:474, Modules/Settings/TimeWeatherTab.qml:664", + "reference": "Modules/Settings/DisplaysTab.qml:486, Modules/Settings/TimeWeatherTab.qml:661", "comment": "" }, { "term": "Launch", "context": "Launch", - "reference": "Modals/Spotlight/SpotlightContextMenu.qml:251, Modules/AppDrawer/AppDrawerPopout.qml:735", + "reference": "Modals/Spotlight/SpotlightContextMenuContent.qml:51, Modules/AppDrawer/AppDrawerPopout.qml:728", "comment": "" }, { "term": "Launch Prefix", "context": "Launch Prefix", - "reference": "Modules/Settings/LauncherTab.qml:434", + "reference": "Modules/Settings/LauncherTab.qml:439", "comment": "" }, { "term": "Launch on dGPU", "context": "Launch on dGPU", - "reference": "Modals/Spotlight/SpotlightContextMenu.qml:312, Modules/AppDrawer/AppDrawerPopout.qml:795, Modules/Dock/DockContextMenu.qml:420", + "reference": "Modals/Spotlight/SpotlightContextMenuContent.qml:62, Modules/AppDrawer/AppDrawerPopout.qml:788, Modules/Dock/DockContextMenu.qml:432", "comment": "" }, { "term": "Launcher", "context": "Launcher", - "reference": "Modals/Settings/SettingsSidebar.qml:39", + "reference": "Modals/Settings/SettingsSidebar.qml:52", "comment": "" }, { "term": "Launcher Button Logo", "context": "Launcher Button Logo", - "reference": "Modules/Settings/LauncherTab.qml:64", + "reference": "Modules/Settings/LauncherTab.qml:60", "comment": "" }, { "term": "Layout", "context": "Layout", - "reference": "Modules/Settings/DankBarTab.qml:187, Modules/DankBar/Popouts/DWLLayoutPopout.qml:182", + "reference": "Modules/Settings/DankBarTab.qml:339, Modules/DankBar/Popouts/DWLLayoutPopout.qml:182", "comment": "" }, { "term": "Left", "context": "Left", - "reference": "Modules/Settings/DankBarTab.qml:971, Modules/Settings/DankBarTab.qml:1300, Modules/DankBar/Popouts/BatteryPopout.qml:532", + "reference": "Modules/Settings/DankBarTab.qml:1220, Modules/Settings/DankBarTab.qml:1558, Modules/DankBar/Popouts/BatteryPopout.qml:532", "comment": "" }, { "term": "Left Section", "context": "Left Section", - "reference": "Modules/Settings/DankBarTab.qml:2746", + "reference": "Modules/Settings/DankBarTab.qml:3230", "comment": "" }, { "term": "Light Mode", "context": "Light Mode", - "reference": "Modules/Settings/PersonalizationTab.qml:509, Modules/Settings/PersonalizationTab.qml:1524", + "reference": "Modules/Settings/PersonalizationTab.qml:501, Modules/Settings/PersonalizationTab.qml:1519", "comment": "" }, { @@ -2228,25 +2474,31 @@ { "term": "Loading plugins...", "context": "Loading plugins...", - "reference": "Modules/Settings/PluginBrowser.qml:319", + "reference": "Modules/Settings/PluginBrowser.qml:296", + "comment": "" + }, + { + "term": "Loading...", + "context": "Loading...", + "reference": "Widgets/VpnDetailContent.qml:363, Modules/Settings/NetworkTab.qml:617, Modules/Settings/NetworkTab.qml:1271, Modules/Settings/NetworkTab.qml:1729", "comment": "" }, { "term": "Location Search", "context": "Location Search", - "reference": "Modules/Settings/TimeWeatherTab.qml:768", + "reference": "Modules/Settings/TimeWeatherTab.qml:765", "comment": "" }, { "term": "Lock", "context": "Lock", - "reference": "Modals/PowerMenuModal.qml:115", + "reference": "Modals/PowerMenuModal.qml:200", "comment": "" }, { "term": "Lock Screen", "context": "Lock Screen", - "reference": "Modals/Settings/PowerSettings.qml:47", + "reference": "Modals/Settings/PowerSettings.qml:48", "comment": "" }, { @@ -2258,13 +2510,13 @@ { "term": "Lock before suspend", "context": "Lock before suspend", - "reference": "Modals/Settings/PowerSettings.qml:87", + "reference": "Modals/Settings/PowerSettings.qml:88", "comment": "" }, { "term": "Log Out", "context": "Log Out", - "reference": "Modals/PowerMenuModal.qml:103, Modals/PowerMenuModal.qml:159, Modules/Lock/LockPowerMenu.qml:84", + "reference": "Modals/PowerMenuModal.qml:188, Modules/Lock/LockPowerMenu.qml:84", "comment": "" }, { @@ -2276,7 +2528,7 @@ { "term": "Longitude", "context": "Longitude", - "reference": "Modules/Settings/DisplaysTab.qml:497, Modules/Settings/TimeWeatherTab.qml:715", + "reference": "Modules/Settings/DisplaysTab.qml:509, Modules/Settings/TimeWeatherTab.qml:712", "comment": "" }, { @@ -2285,34 +2537,46 @@ "reference": "Modules/Notifications/Center/NotificationSettings.qml:160", "comment": "" }, + { + "term": "MAC", + "context": "MAC", + "reference": "Modules/Settings/NetworkTab.qml:542", + "comment": "" + }, + { + "term": "MTU", + "context": "MTU", + "reference": "Widgets/VpnDetailContent.qml:409, Modules/Settings/NetworkTab.qml:1775", + "comment": "" + }, { "term": "Manage and configure plugins for extending DMS functionality", "context": "Manage and configure plugins for extending DMS functionality", - "reference": "Modules/Settings/PluginsTab.qml:69", + "reference": "Modules/Settings/PluginsTab.qml:72", "comment": "" }, { "term": "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.", "context": "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.", - "reference": "Modules/Settings/DankBarTab.qml:922", + "reference": "Modules/Settings/DankBarTab.qml:1171", "comment": "" }, { "term": "Manual Coordinates", "context": "Manual Coordinates", - "reference": "Modules/Settings/DisplaysTab.qml:462", + "reference": "Modules/Settings/DisplaysTab.qml:474", "comment": "" }, { "term": "Manual Gap Size", "context": "Manual Gap Size", - "reference": "Modules/Settings/DankBarTab.qml:1915, Modules/Settings/DankBarTab.qml:1929", + "reference": "Modules/Settings/DankBarTab.qml:2167, Modules/Settings/DankBarTab.qml:2181", "comment": "" }, { "term": "Manual Show/Hide", "context": "Manual Show/Hide", - "reference": "Modules/Settings/DankBarTab.qml:1527", + "reference": "Modules/Settings/DankBarTab.qml:1785", "comment": "" }, { @@ -2348,43 +2612,43 @@ { "term": "Material Colors", "context": "Material Colors", - "reference": "Modals/DankColorPickerModal.qml:347", + "reference": "Modals/DankColorPickerModal.qml:377", "comment": "" }, { "term": "Matugen Palette", "context": "Matugen Palette", - "reference": "Modules/Settings/ThemeColorsTab.qml:594, Modules/Settings/PersonalizationTab.qml:1809", + "reference": "Modules/Settings/ThemeColorsTab.qml:595, Modules/Settings/PersonalizationTab.qml:1804", "comment": "" }, { "term": "Matugen Settings", "context": "Matugen Settings", - "reference": "Modules/Settings/PersonalizationTab.qml:1752", + "reference": "Modules/Settings/PersonalizationTab.qml:1747", "comment": "" }, { "term": "Matugen Target Monitor", "context": "Matugen Target Monitor", - "reference": "Modules/Settings/PersonalizationTab.qml:1041", + "reference": "Modules/Settings/PersonalizationTab.qml:1033", "comment": "" }, { "term": "Max apps to show", "context": "Max apps to show", - "reference": "Modules/Settings/WidgetTweaksTab.qml:103", + "reference": "Modules/Settings/WidgetTweaksTab.qml:99", "comment": "" }, { "term": "Media", "context": "Media", - "reference": "Services/AppSearchService.qml:251, Services/AppSearchService.qml:252, Services/AppSearchService.qml:253, Widgets/DankIconPicker.qml:37, Modules/DankDash/DankDashPopout.qml:188", + "reference": "Services/AppSearchService.qml:251, Services/AppSearchService.qml:252, Services/AppSearchService.qml:253, Widgets/DankIconPicker.qml:37, Modules/DankDash/DankDashPopout.qml:273", "comment": "" }, { "term": "Media Controls", "context": "Media Controls", - "reference": "Modules/Settings/DankBarTab.qml:237", + "reference": "Modules/Settings/DankBarTab.qml:389", "comment": "" }, { @@ -2414,73 +2678,79 @@ { "term": "Media Player Settings", "context": "Media Player Settings", - "reference": "Modules/Settings/WidgetTweaksTab.qml:183", + "reference": "Modules/Settings/WidgetTweaksTab.qml:189", "comment": "" }, { "term": "Media Players (", "context": "Media Players (", - "reference": "Modules/DankDash/MediaPlayerTab.qml:562", + "reference": "Modules/DankDash/MediaDropdownOverlay.qml:381", "comment": "" }, { "term": "Media Volume OSD", "context": "Media Volume OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:816", + "reference": "Modules/Settings/WidgetTweaksTab.qml:803", "comment": "" }, { "term": "Memory", "context": "Memory", - "reference": "Modules/ProcessList/SystemOverview.qml:166, Modules/ProcessList/PerformanceTab.qml:197", + "reference": "Modules/ProcessList/SystemOverview.qml:166, Modules/ProcessList/PerformanceTab.qml:189", "comment": "" }, { "term": "Memory Usage", "context": "Memory Usage", - "reference": "Modules/Settings/DankBarTab.qml:259", + "reference": "Modules/Settings/DankBarTab.qml:411", "comment": "" }, { "term": "Memory usage indicator", "context": "Memory usage indicator", - "reference": "Modules/Settings/DankBarTab.qml:260", + "reference": "Modules/Settings/DankBarTab.qml:412", "comment": "" }, { "term": "Microphone", "context": "Microphone", - "reference": "Modules/Settings/WidgetsTabSection.qml:1065", + "reference": "Modules/Settings/WidgetsTabSection.qml:781, Modules/Settings/WidgetsTabSection.qml:944", "comment": "" }, { "term": "Microphone Mute OSD", "context": "Microphone Mute OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:846", + "reference": "Modules/Settings/WidgetTweaksTab.qml:833", "comment": "" }, { "term": "Middle Section", "context": "Middle Section", - "reference": "Modules/Settings/DankBarTab.qml:2802", + "reference": "Modules/Settings/DankBarTab.qml:3288", "comment": "" }, { "term": "Minimal palette built around a single hue.", "context": "Minimal palette built around a single hue.", - "reference": "Common/Theme.qml:243", + "reference": "Common/Theme.qml:237", "comment": "" }, { "term": "Minute", "context": "Minute", - "reference": "Modules/Settings/DisplaysTab.qml:335", + "reference": "Modules/Settings/DisplaysTab.qml:347", + "comment": "" + }, + { + "term": "Mode", + "context": "Mode", + "reference": "Modules/Settings/NetworkTab.qml:1311", "comment": "" }, { "term": "Mode:", "context": "Mode:", - "reference": "Modules/Settings/PersonalizationTab.qml:1160", + "reference": "Modules/Settings/PersonalizationTab.qml:1152", "comment": "" }, { @@ -2492,19 +2762,19 @@ { "term": "Model", "context": "Model", - "reference": "Modules/Settings/DisplaysTab.qml:618", + "reference": "Modules/Settings/DisplaysTab.qml:628", "comment": "" }, { "term": "Monitor Selection:", "context": "Monitor Selection:", - "reference": "Modules/Settings/PersonalizationTab.qml:999", + "reference": "Modules/Settings/PersonalizationTab.qml:991", "comment": "" }, { "term": "Monitor whose wallpaper drives dynamic theming colors", "context": "Monitor whose wallpaper drives dynamic theming colors", - "reference": "Modules/Settings/PersonalizationTab.qml:1042", + "reference": "Modules/Settings/PersonalizationTab.qml:1034", "comment": "" }, { @@ -2516,13 +2786,13 @@ { "term": "Monospace Font", "context": "Monospace Font", - "reference": "Modules/Settings/ThemeColorsTab.qml:1064", + "reference": "Modules/Settings/ThemeColorsTab.qml:1070", "comment": "" }, { "term": "Mount", "context": "Mount", - "reference": "Modules/ProcessList/SystemTab.qml:445", + "reference": "Modules/ProcessList/SystemTab.qml:431", "comment": "" }, { @@ -2534,25 +2804,25 @@ { "term": "Muted palette with subdued, calming tones.", "context": "Muted palette with subdued, calming tones.", - "reference": "Common/Theme.qml:248", + "reference": "Common/Theme.qml:241", "comment": "" }, { "term": "NM not supported", "context": "NM not supported", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:203", + "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:205", "comment": "" }, { "term": "Name", "context": "Name", - "reference": "Modules/Settings/DisplaysTab.qml:618", + "reference": "Modules/Settings/DisplaysTab.qml:628", "comment": "" }, { "term": "Named Workspace Icons", "context": "Named Workspace Icons", - "reference": "Modules/Settings/WidgetTweaksTab.qml:429", + "reference": "Modules/Settings/WidgetTweaksTab.qml:432", "comment": "" }, { @@ -2564,19 +2834,13 @@ { "term": "Network", "context": "Network", - "reference": "Modules/ProcessList/PerformanceTab.qml:362", - "comment": "" - }, - { - "term": "Network Icon", - "context": "Network Icon", - "reference": "Modules/Settings/WidgetsTabSection.qml:842", + "reference": "Modals/Settings/SettingsSidebar.qml:46, Modules/ProcessList/PerformanceTab.qml:342, Modules/Settings/WidgetsTabSection.qml:757", "comment": "" }, { "term": "Network Info", "context": "Network Info", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:352, Modules/ControlCenter/Details/NetworkDetail.qml:676", + "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:404, Modules/ControlCenter/Details/NetworkDetail.qml:734", "comment": "" }, { @@ -2594,13 +2858,19 @@ { "term": "Network Speed Monitor", "context": "Network Speed Monitor", - "reference": "Modules/Settings/DankBarTab.qml:361", + "reference": "Modules/Settings/DankBarTab.qml:513", + "comment": "" + }, + { + "term": "Network Status", + "context": "Network Status", + "reference": "Modules/Settings/NetworkTab.qml:89", "comment": "" }, { "term": "Network download and upload speed display", "context": "Network download and upload speed display", - "reference": "Modules/Settings/DankBarTab.qml:362", + "reference": "Modules/Settings/DankBarTab.qml:514", "comment": "" }, { @@ -2612,37 +2882,43 @@ { "term": "New Notification", "context": "New Notification", - "reference": "Modules/Settings/PersonalizationTab.qml:2047", + "reference": "Modules/Settings/PersonalizationTab.qml:2042", "comment": "" }, { "term": "New York, NY", "context": "New York, NY", - "reference": "Modules/Settings/TimeWeatherTab.qml:778", + "reference": "Modules/Settings/TimeWeatherTab.qml:775", "comment": "" }, { "term": "Night Mode", "context": "Night Mode", - "reference": "Modules/Settings/DisplaysTab.qml:167, Modules/ControlCenter/Components/DragDropGrid.qml:597", + "reference": "Modules/Settings/DisplaysTab.qml:176, Modules/ControlCenter/Components/DragDropGrid.qml:599", "comment": "" }, { "term": "Night Temperature", "context": "Night Temperature", - "reference": "Modules/Settings/DisplaysTab.qml:193", + "reference": "Modules/Settings/DisplaysTab.qml:202", + "comment": "" + }, + { + "term": "No", + "context": "No", + "reference": "Widgets/VpnDetailContent.qml:419, Modules/Settings/NetworkTab.qml:1785", "comment": "" }, { "term": "No Active Players", "context": "No Active Players", - "reference": "Modules/DankDash/MediaPlayerTab.qml:304", + "reference": "Modules/DankDash/MediaPlayerTab.qml:358", "comment": "" }, { "term": "No Background", "context": "No Background", - "reference": "Modules/Settings/DankBarTab.qml:1998", + "reference": "Modules/Settings/DankBarTab.qml:2248", "comment": "" }, { @@ -2658,15 +2934,21 @@ "comment": "" }, { - "term": "No VPN profiles found", - "context": "No VPN profiles found", - "reference": "Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml:140, Modules/DankBar/Popouts/VpnPopout.qml:271", + "term": "No VPN profiles", + "context": "No VPN profiles", + "reference": "Widgets/VpnDetailContent.qml:172, Modules/Settings/NetworkTab.qml:1540", "comment": "" }, { "term": "No Weather Data Available", "context": "No Weather Data Available", - "reference": "Modules/DankDash/WeatherTab.qml:27, Modules/Settings/TimeWeatherTab.qml:853", + "reference": "Modules/DankDash/WeatherTab.qml:27, Modules/Settings/TimeWeatherTab.qml:849", + "comment": "" + }, + { + "term": "No adapters", + "context": "No adapters", + "reference": "Modules/Settings/NetworkTab.qml:285", "comment": "" }, { @@ -2696,13 +2978,13 @@ { "term": "No plugins found", "context": "No plugins found", - "reference": "Modules/Settings/PluginBrowser.qml:553", + "reference": "Modules/Settings/PluginBrowser.qml:524", "comment": "" }, { "term": "No plugins found.", "context": "No plugins found.", - "reference": "Modules/Settings/PluginsTab.qml:244", + "reference": "Modules/Settings/PluginsTab.qml:249", "comment": "" }, { @@ -2723,10 +3005,16 @@ "reference": "Modules/Notifications/Center/NotificationSettings.qml:175", "comment": "" }, + { + "term": "Not connected", + "context": "Not connected", + "reference": "Modules/Settings/NetworkTab.qml:758", + "comment": "" + }, { "term": "Notepad", "context": "Notepad", - "reference": "DMSShell.qml:414, Modules/Settings/DankBarTab.qml:375", + "reference": "DMSShell.qml:452, Modules/Settings/DankBarTab.qml:527", "comment": "" }, { @@ -2738,7 +3026,7 @@ { "term": "Notepad Slideout", "context": "Notepad Slideout", - "reference": "Modules/Settings/DisplaysTab.qml:55", + "reference": "Modules/Settings/DisplaysTab.qml:58", "comment": "" }, { @@ -2750,7 +3038,7 @@ { "term": "Notification Center", "context": "Notification Center", - "reference": "Modules/Settings/DankBarTab.qml:312", + "reference": "Modules/Settings/DankBarTab.qml:464", "comment": "" }, { @@ -2762,7 +3050,7 @@ { "term": "Notification Popups", "context": "Notification Popups", - "reference": "Modules/Settings/DisplaysTab.qml:35, Modules/Settings/WidgetTweaksTab.qml:586", + "reference": "Modules/Settings/DisplaysTab.qml:34, Modules/Settings/WidgetTweaksTab.qml:576", "comment": "" }, { @@ -2780,13 +3068,13 @@ { "term": "Notification toast popups", "context": "Notification toast popups", - "reference": "Modules/Settings/DisplaysTab.qml:36", + "reference": "Modules/Settings/DisplaysTab.qml:35", "comment": "" }, { "term": "Notifications", "context": "Notifications", - "reference": "Modules/Notifications/Center/NotificationHeader.qml:22", + "reference": "Modules/Notifications/Center/NotificationHeader.qml:25", "comment": "" }, { @@ -2798,13 +3086,13 @@ { "term": "OS Logo", "context": "OS Logo", - "reference": "Modules/Settings/LauncherTab.qml:88", + "reference": "Modules/Settings/LauncherTab.qml:84", "comment": "" }, { "term": "OSD Position", "context": "OSD Position", - "reference": "Modules/Settings/WidgetTweaksTab.qml:747", + "reference": "Modules/Settings/WidgetTweaksTab.qml:735", "comment": "" }, { @@ -2822,37 +3110,37 @@ { "term": "On-Screen Displays", "context": "On-Screen Displays", - "reference": "Modules/Settings/DisplaysTab.qml:45", + "reference": "Modules/Settings/DisplaysTab.qml:46", "comment": "" }, { "term": "On-screen Displays", "context": "On-screen Displays", - "reference": "Modules/Settings/WidgetTweaksTab.qml:731", + "reference": "Modules/Settings/WidgetTweaksTab.qml:719", "comment": "" }, { "term": "Only adjust gamma based on time or location rules.", "context": "Only adjust gamma based on time or location rules.", - "reference": "Modules/Settings/DisplaysTab.qml:238", + "reference": "Modules/Settings/DisplaysTab.qml:247", "comment": "" }, { "term": "Only visible if hibernate is supported by your system", "context": "Only visible if hibernate is supported by your system", - "reference": "Modals/Settings/PowerSettings.qml:498", + "reference": "Modals/Settings/PowerSettings.qml:533", "comment": "" }, { "term": "Opacity", "context": "Opacity", - "reference": "Modals/DankColorPickerModal.qml:449", + "reference": "Modals/DankColorPickerModal.qml:479", "comment": "" }, { "term": "Open", "context": "Open", - "reference": "Modules/Notepad/NotepadTextEditor.qml:527", + "reference": "Modules/Notepad/NotepadTextEditor.qml:527, Modules/Settings/NetworkTab.qml:1105, Modules/Settings/NetworkTab.qml:1321", "comment": "" }, { @@ -2873,6 +3161,24 @@ "reference": "Services/CupsService.qml:296", "comment": "" }, + { + "term": "Outline Color", + "context": "Outline Color", + "reference": "Modules/Settings/DankBarTab.qml:2642", + "comment": "" + }, + { + "term": "Outline Opacity", + "context": "Outline Opacity", + "reference": "Modules/Settings/DankBarTab.qml:2704, Modules/Settings/DankBarTab.qml:2718", + "comment": "" + }, + { + "term": "Outline Thickness", + "context": "Outline Thickness", + "reference": "Modules/Settings/DankBarTab.qml:2778, Modules/Settings/DankBarTab.qml:2792", + "comment": "" + }, { "term": "Output Area Almost Full", "context": "Output Area Almost Full", @@ -2894,7 +3200,13 @@ { "term": "Overview", "context": "Overview", - "reference": "Modules/DankDash/DankDashPopout.qml:185", + "reference": "Modules/DankDash/DankDashPopout.qml:269", + "comment": "" + }, + { + "term": "Overview of your network connections", + "context": "Overview of your network connections", + "reference": "Modules/Settings/NetworkTab.qml:96", "comment": "" }, { @@ -2903,10 +3215,16 @@ "reference": "Modals/FileBrowser/FileBrowserOverwriteDialog.qml:108", "comment": "" }, + { + "term": "PIN", + "context": "PIN", + "reference": "Modals/WifiPasswordModal.qml:130", + "comment": "" + }, { "term": "Padding", "context": "Padding", - "reference": "Modules/Settings/DockTab.qml:508, Modules/Settings/DockTab.qml:522", + "reference": "Modules/Settings/DockTab.qml:510, Modules/Settings/DockTab.qml:524", "comment": "" }, { @@ -2936,7 +3254,7 @@ { "term": "Password", "context": "Password", - "reference": "Modals/WifiPasswordModal.qml:311", + "reference": "Modals/WifiPasswordModal.qml:123, Modals/WifiPasswordModal.qml:132, Modals/WifiPasswordModal.qml:422", "comment": "" }, { @@ -2954,25 +3272,25 @@ { "term": "Per-Mode Wallpapers", "context": "Per-Mode Wallpapers", - "reference": "Modules/Settings/PersonalizationTab.qml:469", + "reference": "Modules/Settings/PersonalizationTab.qml:461", "comment": "" }, { "term": "Per-Monitor Wallpapers", "context": "Per-Monitor Wallpapers", - "reference": "Modules/Settings/PersonalizationTab.qml:967", + "reference": "Modules/Settings/PersonalizationTab.qml:959", "comment": "" }, { "term": "Per-Monitor Workspaces", "context": "Per-Monitor Workspaces", - "reference": "Modules/Settings/WidgetTweaksTab.qml:134", + "reference": "Modules/Settings/WidgetTweaksTab.qml:130", "comment": "" }, { "term": "Percentage", "context": "Percentage", - "reference": "Modules/Settings/DankBarTab.qml:268", + "reference": "Modules/Settings/DankBarTab.qml:420", "comment": "" }, { @@ -2984,103 +3302,109 @@ { "term": "Personalization", "context": "Personalization", - "reference": "Modals/Settings/SettingsSidebar.qml:15", + "reference": "Modals/Settings/SettingsSidebar.qml:16", "comment": "" }, { "term": "Pin to Dock", "context": "Pin to Dock", - "reference": "Modals/Spotlight/SpotlightContextMenu.qml:110, Modals/Spotlight/SpotlightContextMenu.qml:113, Modules/AppDrawer/AppDrawerPopout.qml:598, Modules/Dock/DockContextMenu.qml:373", + "reference": "Modals/Spotlight/SpotlightContextMenuContent.qml:26, Modules/AppDrawer/AppDrawerPopout.qml:591, Modules/Dock/DockContextMenu.qml:379", "comment": "" }, { "term": "Place plugin directories here. Each plugin should have a plugin.json manifest file.", "context": "Place plugin directories here. Each plugin should have a plugin.json manifest file.", - "reference": "Modules/Settings/PluginsTab.qml:187", + "reference": "Modules/Settings/PluginsTab.qml:190", "comment": "" }, { "term": "Place plugins in", "context": "Place plugins in", - "reference": "Modules/Settings/PluginsTab.qml:244", + "reference": "Modules/Settings/PluginsTab.qml:249", "comment": "" }, { "term": "Play sound when new notification arrives", "context": "Play sound when new notification arrives", - "reference": "Modules/Settings/PersonalizationTab.qml:2053", + "reference": "Modules/Settings/PersonalizationTab.qml:2048", "comment": "" }, { "term": "Play sound when power cable is connected", "context": "Play sound when power cable is connected", - "reference": "Modules/Settings/PersonalizationTab.qml:2122", + "reference": "Modules/Settings/PersonalizationTab.qml:2117", "comment": "" }, { "term": "Play sound when volume is adjusted", "context": "Play sound when volume is adjusted", - "reference": "Modules/Settings/PersonalizationTab.qml:2087", + "reference": "Modules/Settings/PersonalizationTab.qml:2082", "comment": "" }, { "term": "Play sounds for system events", "context": "Play sounds for system events", - "reference": "Modules/Settings/PersonalizationTab.qml:1940", + "reference": "Modules/Settings/PersonalizationTab.qml:1935", + "comment": "" + }, + { + "term": "Playback", + "context": "Playback", + "reference": "Modules/ControlCenter/Details/AudioOutputDetail.qml:307", "comment": "" }, { "term": "Plugged In", "context": "Plugged In", - "reference": "Modules/Settings/PersonalizationTab.qml:2116", + "reference": "Modules/Settings/PersonalizationTab.qml:2111", "comment": "" }, { "term": "Plugin Directory", "context": "Plugin Directory", - "reference": "Modules/Settings/PluginsTab.qml:173", + "reference": "Modules/Settings/PluginsTab.qml:176", "comment": "" }, { "term": "Plugin Management", "context": "Plugin Management", - "reference": "Modules/Settings/PluginsTab.qml:62", + "reference": "Modules/Settings/PluginsTab.qml:65", "comment": "" }, { "term": "Plugin is disabled - enable in Plugins settings to use", "context": "Plugin is disabled - enable in Plugins settings to use", - "reference": "Modules/Settings/DankBarTab.qml:405", + "reference": "Modules/Settings/DankBarTab.qml:557", "comment": "" }, { "term": "Plugins", "context": "Plugins", - "reference": "Modals/Settings/SettingsSidebar.qml:51", + "reference": "Modals/Settings/SettingsSidebar.qml:67", "comment": "" }, { "term": "Plugins:", "context": "Plugins:", - "reference": "Modules/Settings/AboutTab.qml:502", + "reference": "Modules/Settings/AboutTab.qml:503", "comment": "" }, { "term": "Popup Position", "context": "Popup Position", - "reference": "Modules/Settings/WidgetTweaksTab.qml:602", + "reference": "Modules/Settings/WidgetTweaksTab.qml:592", "comment": "" }, { "term": "Popup Transparency", "context": "Popup Transparency", - "reference": "Modules/Settings/ThemeColorsTab.qml:828", + "reference": "Modules/Settings/ThemeColorsTab.qml:838", "comment": "" }, { "term": "Position", "context": "Position", - "reference": "Modules/Settings/DankBarTab.qml:1290", + "reference": "Modules/Settings/DankBarTab.qml:1548", "comment": "" }, { @@ -3092,25 +3416,25 @@ { "term": "Power & Security", "context": "Power & Security", - "reference": "Modals/Settings/SettingsSidebar.qml:47", + "reference": "Modals/Settings/SettingsSidebar.qml:62", "comment": "" }, { "term": "Power Action Confirmation", "context": "Power Action Confirmation", - "reference": "Modals/Settings/PowerSettings.qml:541", + "reference": "Modals/Settings/PowerSettings.qml:576", "comment": "" }, { "term": "Power Menu Customization", "context": "Power Menu Customization", - "reference": "Modals/Settings/PowerSettings.qml:354", + "reference": "Modals/Settings/PowerSettings.qml:389", "comment": "" }, { "term": "Power Off", "context": "Power Off", - "reference": "Modals/PowerMenuModal.qml:109, Modals/PowerMenuModal.qml:175, Modules/Lock/LockPowerMenu.qml:86", + "reference": "Modals/PowerMenuModal.qml:194, Modules/Lock/LockPowerMenu.qml:86", "comment": "" }, { @@ -3128,31 +3452,37 @@ { "term": "Power Profile OSD", "context": "Power Profile OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:866", + "reference": "Modules/Settings/WidgetTweaksTab.qml:853", + "comment": "" + }, + { + "term": "Preference", + "context": "Preference", + "reference": "Modules/Settings/NetworkTab.qml:193, Modules/Settings/NetworkTab.qml:238", "comment": "" }, { "term": "Pressure", "context": "Pressure", - "reference": "Modules/DankDash/WeatherTab.qml:410, Modules/Settings/TimeWeatherTab.qml:1236", + "reference": "Modules/DankDash/WeatherTab.qml:410, Modules/Settings/TimeWeatherTab.qml:1234", "comment": "" }, { "term": "Prevent idle for media", "context": "Prevent idle for media", - "reference": "Modals/Settings/PowerSettings.qml:156", + "reference": "Modals/Settings/PowerSettings.qml:157", "comment": "" }, { "term": "Prevent screen timeout", "context": "Prevent screen timeout", - "reference": "Modules/Settings/DankBarTab.qml:334", + "reference": "Modules/Settings/DankBarTab.qml:486", "comment": "" }, { "term": "Primary", "context": "Primary", - "reference": "Modules/Settings/LauncherTab.qml:201", + "reference": "Modules/Settings/LauncherTab.qml:203, Modules/Settings/NetworkTab.qml:173", "comment": "" }, { @@ -3161,6 +3491,12 @@ "reference": "Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:23, Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml:55", "comment": "" }, + { + "term": "Printer", + "context": "Printer", + "reference": "Modules/Settings/WidgetsTabSection.qml:799", + "comment": "" + }, { "term": "Printers", "context": "Printers", @@ -3176,7 +3512,13 @@ { "term": "Privacy Indicator", "context": "Privacy Indicator", - "reference": "Modules/Settings/DankBarTab.qml:298", + "reference": "Modules/Settings/DankBarTab.qml:450", + "comment": "" + }, + { + "term": "Private Key Password", + "context": "Private Key Password", + "reference": "Modals/WifiPasswordModal.qml:128", "comment": "" }, { @@ -3203,40 +3545,52 @@ "reference": "Services/PortalService.qml:153", "comment": "" }, + { + "term": "Protocol", + "context": "Protocol", + "reference": "Widgets/VpnDetailContent.qml:404, Modules/Settings/NetworkTab.qml:1770", + "comment": "" + }, { "term": "Quick access to application launcher", "context": "Quick access to application launcher", - "reference": "Modules/Settings/DankBarTab.qml:196", + "reference": "Modules/Settings/DankBarTab.qml:348", "comment": "" }, { "term": "Quick access to color picker", "context": "Quick access to color picker", - "reference": "Modules/Settings/DankBarTab.qml:383", + "reference": "Modules/Settings/DankBarTab.qml:535", "comment": "" }, { "term": "Quick access to notepad", "context": "Quick access to notepad", - "reference": "Modules/Settings/DankBarTab.qml:376", + "reference": "Modules/Settings/DankBarTab.qml:528", "comment": "" }, { "term": "Quick note-taking slideout panel", "context": "Quick note-taking slideout panel", - "reference": "Modules/Settings/DisplaysTab.qml:56", + "reference": "Modules/Settings/DisplaysTab.qml:59", "comment": "" }, { "term": "RGB", "context": "RGB", - "reference": "Modals/DankColorPickerModal.qml:553", + "reference": "Modals/DankColorPickerModal.qml:583", "comment": "" }, { "term": "Rain Chance", "context": "Rain Chance", - "reference": "Modules/DankDash/WeatherTab.qml:465, Modules/Settings/TimeWeatherTab.qml:1291", + "reference": "Modules/DankDash/WeatherTab.qml:465, Modules/Settings/TimeWeatherTab.qml:1290", + "comment": "" + }, + { + "term": "Rate", + "context": "Rate", + "reference": "Modules/Settings/NetworkTab.qml:1306", "comment": "" }, { @@ -3248,19 +3602,19 @@ { "term": "Reboot", "context": "Reboot", - "reference": "Modals/PowerMenuModal.qml:97, Modals/PowerMenuModal.qml:171, Modules/Lock/LockPowerMenu.qml:82", + "reference": "Modals/PowerMenuModal.qml:182, Modules/Lock/LockPowerMenu.qml:82", "comment": "" }, { "term": "Recent Colors", "context": "Recent Colors", - "reference": "Modals/DankColorPickerModal.qml:397", + "reference": "Modals/DankColorPickerModal.qml:427", "comment": "" }, { "term": "Recently Used Apps", "context": "Recently Used Apps", - "reference": "Modules/Settings/LauncherTab.qml:713", + "reference": "Modules/Settings/LauncherTab.qml:708", "comment": "" }, { @@ -3272,7 +3626,7 @@ { "term": "Reload Plugin", "context": "Reload Plugin", - "reference": "Modules/Settings/PluginListItem.qml:243", + "reference": "Modules/Settings/PluginListItem.qml:233", "comment": "" }, { @@ -3288,39 +3642,39 @@ "comment": "" }, { - "term": "Request confirmation on power off, restart, suspend, hibernate and logout actions", - "context": "Request confirmation on power off, restart, suspend, hibernate and logout actions", - "reference": "Modals/Settings/PowerSettings.qml:552", + "term": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout", + "context": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout", + "reference": "Modals/Settings/PowerSettings.qml:587", "comment": "" }, { "term": "Requires DWL compositor", "context": "Requires DWL compositor", - "reference": "Modules/Settings/DankBarTab.qml:191", + "reference": "Modules/Settings/DankBarTab.qml:343", "comment": "" }, { "term": "Reset", "context": "Reset", - "reference": "Modules/Settings/DankBarTab.qml:2682, Modules/ControlCenter/Components/EditControls.qml:227", + "reference": "Modules/Settings/DankBarTab.qml:3166, Modules/ControlCenter/Components/EditControls.qml:227", "comment": "" }, { "term": "Resources", "context": "Resources", - "reference": "Modules/Settings/AboutTab.qml:464", + "reference": "Modules/Settings/AboutTab.qml:465", "comment": "" }, { "term": "Restart DMS", "context": "Restart DMS", - "reference": "Modals/PowerMenuModal.qml:133", + "reference": "Modals/PowerMenuModal.qml:218", "comment": "" }, { "term": "Restart the DankMaterialShell", "context": "Restart the DankMaterialShell", - "reference": "Modals/Settings/PowerSettings.qml:482", + "reference": "Modals/Settings/PowerSettings.qml:517", "comment": "" }, { @@ -3344,13 +3698,13 @@ { "term": "Right", "context": "Right", - "reference": "Modules/Settings/DankBarTab.qml:973, Modules/Settings/DankBarTab.qml:1300", + "reference": "Modules/Settings/DankBarTab.qml:1222, Modules/Settings/DankBarTab.qml:1558", "comment": "" }, { "term": "Right Section", "context": "Right Section", - "reference": "Modules/Settings/DankBarTab.qml:2858", + "reference": "Modules/Settings/DankBarTab.qml:3346", "comment": "" }, { @@ -3368,31 +3722,31 @@ { "term": "Run User Templates", "context": "Run User Templates", - "reference": "Modules/Settings/PersonalizationTab.qml:1863", + "reference": "Modules/Settings/PersonalizationTab.qml:1858", "comment": "" }, { "term": "Running Apps", "context": "Running Apps", - "reference": "Modules/Settings/DankBarTab.qml:216", + "reference": "Modules/Settings/DankBarTab.qml:368", "comment": "" }, { "term": "Running Apps Only In Current Workspace", "context": "Running Apps Only In Current Workspace", - "reference": "Modules/Settings/WidgetTweaksTab.qml:389", + "reference": "Modules/Settings/WidgetTweaksTab.qml:394", "comment": "" }, { "term": "Running Apps Settings", "context": "Running Apps Settings", - "reference": "Modules/Settings/WidgetTweaksTab.qml:379", + "reference": "Modules/Settings/WidgetTweaksTab.qml:384", "comment": "" }, { "term": "Save", "context": "Save", - "reference": "Modals/DankColorPickerModal.qml:681, Modals/FileBrowser/FileBrowserSaveRow.qml:55, Modules/Notepad/NotepadTextEditor.qml:511, Modules/Notepad/Notepad.qml:461", + "reference": "Modals/DankColorPickerModal.qml:711, Modals/FileBrowser/FileBrowserSaveRow.qml:55, Modules/Notepad/NotepadTextEditor.qml:511, Modules/Notepad/Notepad.qml:461", "comment": "" }, { @@ -3404,31 +3758,43 @@ { "term": "Save password", "context": "Save password", - "reference": "Modals/WifiPasswordModal.qml:524", + "reference": "Modals/WifiPasswordModal.qml:577", "comment": "" }, { "term": "Saved", "context": "Saved", - "reference": "Modules/Notepad/NotepadTextEditor.qml:591", + "reference": "Modules/Notepad/NotepadTextEditor.qml:591, Modules/Settings/NetworkTab.qml:1118", + "comment": "" + }, + { + "term": "Saved Configurations", + "context": "Saved Configurations", + "reference": "Modules/Settings/NetworkTab.qml:643", "comment": "" }, { "term": "Scale DankBar font sizes independently", "context": "Scale DankBar font sizes independently", - "reference": "Modules/Settings/DankBarTab.qml:2546", + "reference": "Modules/Settings/DankBarTab.qml:3030", "comment": "" }, { "term": "Scale all font sizes", "context": "Scale all font sizes", - "reference": "Modules/Settings/ThemeColorsTab.qml:1104", + "reference": "Modules/Settings/ThemeColorsTab.qml:1110", "comment": "" }, { "term": "Scan", "context": "Scan", - "reference": "Modules/Settings/PluginsTab.qml:134", + "reference": "Modules/Settings/PluginsTab.qml:137", + "comment": "" + }, + { + "term": "Scanning...", + "context": "Scanning...", + "reference": "Modules/Settings/NetworkTab.qml:987", "comment": "" }, { @@ -3440,7 +3806,7 @@ { "term": "Screen sharing", "context": "Screen sharing", - "reference": "Modules/Settings/WidgetsTabSection.qml:1169", + "reference": "Modules/Settings/WidgetsTabSection.qml:1048", "comment": "" }, { @@ -3452,13 +3818,13 @@ { "term": "Search file contents", "context": "Search file contents", - "reference": "Modals/Spotlight/SpotlightContent.qml:381", + "reference": "Modals/Spotlight/SpotlightContent.qml:437", "comment": "" }, { "term": "Search filenames", "context": "Search filenames", - "reference": "Modals/Spotlight/SpotlightContent.qml:339", + "reference": "Modals/Spotlight/SpotlightContent.qml:395", "comment": "" }, { @@ -3470,7 +3836,13 @@ { "term": "Search plugins...", "context": "Search plugins...", - "reference": "Modules/Settings/PluginBrowser.qml:275", + "reference": "Modules/Settings/PluginBrowser.qml:252", + "comment": "" + }, + { + "term": "Search widgets...", + "context": "Search widgets...", + "reference": "Modules/Settings/WidgetSelectionPopup.qml:251", "comment": "" }, { @@ -3485,100 +3857,112 @@ "reference": "Modals/Spotlight/FileSearchResults.qml:228", "comment": "" }, + { + "term": "Secured", + "context": "Secured", + "reference": "Modules/Settings/NetworkTab.qml:1105", + "comment": "" + }, + { + "term": "Security", + "context": "Security", + "reference": "Modules/Settings/NetworkTab.qml:1320", + "comment": "" + }, { "term": "Select Custom Theme", "context": "custom theme file browser title", - "reference": "Modules/Settings/ThemeColorsTab.qml:1455", + "reference": "Modules/Settings/ThemeColorsTab.qml:1449", "comment": "" }, { "term": "Select Launcher Logo", "context": "Select Launcher Logo", - "reference": "Modules/Settings/LauncherTab.qml:16", + "reference": "Modules/Settings/LauncherTab.qml:12", "comment": "" }, { "term": "Select Profile Image", "context": "profile image file browser title", - "reference": "Modals/Settings/SettingsModal.qml:74", + "reference": "Modals/Settings/SettingsModal.qml:75", "comment": "" }, { "term": "Select Wallpaper", "context": "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title", - "reference": "Modals/Settings/SettingsModal.qml:93, Modules/Settings/PersonalizationTab.qml:2155, Modules/Settings/PersonalizationTab.qml:2184, Modules/Settings/PersonalizationTab.qml:2211", + "reference": "Modals/Settings/SettingsModal.qml:94, Modules/Settings/PersonalizationTab.qml:2144, Modules/Settings/PersonalizationTab.qml:2163, Modules/Settings/PersonalizationTab.qml:2180", "comment": "" }, { "term": "Select Wallpaper Directory", "context": "wallpaper directory file browser title", - "reference": "Modules/DankDash/WallpaperTab.qml:308", + "reference": "Modules/DankDash/WallpaperTab.qml:292", "comment": "" }, { "term": "Select a color from the palette or use custom sliders", "context": "Select a color from the palette or use custom sliders", - "reference": "Modals/DankColorPickerModal.qml:154", + "reference": "Modals/DankColorPickerModal.qml:184", "comment": "" }, { "term": "Select a preset or drag the slider to customize", "context": "Select a preset or drag the slider to customize", - "reference": "Modules/Settings/PersonalizationTab.qml:1714", + "reference": "Modules/Settings/PersonalizationTab.qml:1709", "comment": "" }, { - "term": "Select a widget to add to the ", - "context": "Select a widget to add to the ", - "reference": "Modules/Settings/WidgetSelectionPopup.qml:211", + "term": "Select a widget to add. You can add multiple instances of the same widget if needed.", + "context": "Select a widget to add. You can add multiple instances of the same widget if needed.", + "reference": "Modules/Settings/WidgetSelectionPopup.qml:229", "comment": "" }, { "term": "Select an image file...", "context": "Select an image file...", - "reference": "Modules/Settings/LauncherTab.qml:153", + "reference": "Modules/Settings/LauncherTab.qml:155", "comment": "" }, { "term": "Select font weight", "context": "Select font weight", - "reference": "Modules/Settings/ThemeColorsTab.qml:999", + "reference": "Modules/Settings/ThemeColorsTab.qml:1005", "comment": "" }, { "term": "Select monitor to configure wallpaper", "context": "Select monitor to configure wallpaper", - "reference": "Modules/Settings/PersonalizationTab.qml:1009", + "reference": "Modules/Settings/PersonalizationTab.qml:1001", "comment": "" }, { "term": "Select monospace font for process list and technical displays", "context": "Select monospace font for process list and technical displays", - "reference": "Modules/Settings/ThemeColorsTab.qml:1065", + "reference": "Modules/Settings/ThemeColorsTab.qml:1071", "comment": "" }, { "term": "Select system font family", "context": "Select system font family", - "reference": "Modules/Settings/ThemeColorsTab.qml:978", + "reference": "Modules/Settings/ThemeColorsTab.qml:984", "comment": "" }, { "term": "Select system sound theme", "context": "Select system sound theme", - "reference": "Modules/Settings/PersonalizationTab.qml:2011", + "reference": "Modules/Settings/PersonalizationTab.qml:2006", "comment": "" }, { "term": "Select the palette algorithm used for wallpaper-based colors", "context": "Select the palette algorithm used for wallpaper-based colors", - "reference": "Modules/Settings/ThemeColorsTab.qml:595, Modules/Settings/PersonalizationTab.qml:1810", + "reference": "Modules/Settings/ThemeColorsTab.qml:596, Modules/Settings/PersonalizationTab.qml:1805", "comment": "" }, { "term": "Select which transitions to include in randomization", "context": "Select which transitions to include in randomization", - "reference": "Modules/Settings/PersonalizationTab.qml:1402", + "reference": "Modules/Settings/PersonalizationTab.qml:1397", "comment": "" }, { @@ -3590,25 +3974,31 @@ { "term": "Separator", "context": "Separator", - "reference": "Modules/Settings/DankBarTab.qml:354", + "reference": "Modules/Settings/DankBarTab.qml:506", + "comment": "" + }, + { + "term": "Server", + "context": "Server", + "reference": "Widgets/VpnDetailContent.qml:384, Modules/Settings/NetworkTab.qml:1750", "comment": "" }, { "term": "Set different wallpapers for each connected monitor", "context": "Set different wallpapers for each connected monitor", - "reference": "Modules/Settings/PersonalizationTab.qml:974", + "reference": "Modules/Settings/PersonalizationTab.qml:966", "comment": "" }, { "term": "Set different wallpapers for light and dark mode", "context": "Set different wallpapers for light and dark mode", - "reference": "Modules/Settings/PersonalizationTab.qml:476", + "reference": "Modules/Settings/PersonalizationTab.qml:468", "comment": "" }, { "term": "Settings", "context": "settings window title", - "reference": "Services/AppSearchService.qml:269, Modals/Settings/SettingsModal.qml:41, Modals/Settings/SettingsModal.qml:183, Modules/DankDash/DankDashPopout.qml:203", + "reference": "Services/AppSearchService.qml:269, Modals/Settings/SettingsModal.qml:41, Modals/Settings/SettingsModal.qml:184, Modules/DankDash/DankDashPopout.qml:290", "comment": "" }, { @@ -3620,25 +4010,19 @@ { "term": "Show All Tags", "context": "Show All Tags", - "reference": "Modules/Settings/WidgetTweaksTab.qml:144", - "comment": "" - }, - { - "term": "Show Confirmation on Power Actions", - "context": "Show Confirmation on Power Actions", - "reference": "Modals/Settings/PowerSettings.qml:551", + "reference": "Modules/Settings/WidgetTweaksTab.qml:151", "comment": "" }, { "term": "Show Dock", "context": "Show Dock", - "reference": "Modules/Settings/DockTab.qml:127", + "reference": "Modules/Settings/DockTab.qml:136", "comment": "" }, { "term": "Show Hibernate", "context": "Show Hibernate", - "reference": "Modals/Settings/PowerSettings.qml:497", + "reference": "Modals/Settings/PowerSettings.qml:532", "comment": "" }, { @@ -3650,193 +4034,199 @@ { "term": "Show Lock", "context": "Show Lock", - "reference": "Modals/Settings/PowerSettings.qml:451", + "reference": "Modals/Settings/PowerSettings.qml:486", "comment": "" }, { "term": "Show Log Out", "context": "Show Log Out", - "reference": "Modals/Settings/PowerSettings.qml:421", + "reference": "Modals/Settings/PowerSettings.qml:456", + "comment": "" + }, + { + "term": "Show Occupied Workspaces Only", + "context": "Show Occupied Workspaces Only", + "reference": "Modules/Settings/WidgetTweaksTab.qml:140", "comment": "" }, { "term": "Show Power Actions", "context": "Show Power Actions", - "reference": "Modals/Settings/PowerSettings.qml:57", + "reference": "Modals/Settings/PowerSettings.qml:58", "comment": "" }, { "term": "Show Power Off", "context": "Show Power Off", - "reference": "Modals/Settings/PowerSettings.qml:436", + "reference": "Modals/Settings/PowerSettings.qml:471", "comment": "" }, { "term": "Show Reboot", "context": "Show Reboot", - "reference": "Modals/Settings/PowerSettings.qml:406", + "reference": "Modals/Settings/PowerSettings.qml:441", "comment": "" }, { "term": "Show Restart DMS", "context": "Show Restart DMS", - "reference": "Modals/Settings/PowerSettings.qml:481", + "reference": "Modals/Settings/PowerSettings.qml:516", "comment": "" }, { "term": "Show Suspend", "context": "Show Suspend", - "reference": "Modals/Settings/PowerSettings.qml:466", + "reference": "Modals/Settings/PowerSettings.qml:501", "comment": "" }, { "term": "Show Workspace Apps", "context": "Show Workspace Apps", - "reference": "Modules/Settings/WidgetTweaksTab.qml:80", + "reference": "Modules/Settings/WidgetTweaksTab.qml:77", "comment": "" }, { "term": "Show all 9 tags instead of only occupied tags (DWL only)", "context": "Show all 9 tags instead of only occupied tags (DWL only)", - "reference": "Modules/Settings/WidgetTweaksTab.qml:145", + "reference": "Modules/Settings/WidgetTweaksTab.qml:152", "comment": "" }, { "term": "Show darkened overlay behind modal dialogs", "context": "Show darkened overlay behind modal dialogs", - "reference": "Modules/Settings/ThemeColorsTab.qml:920", + "reference": "Modules/Settings/ThemeColorsTab.qml:927", "comment": "" }, { "term": "Show on Last Display", "context": "Show on Last Display", - "reference": "Modules/Settings/DisplaysTab.qml:808, Modules/Settings/DankBarTab.qml:1197", + "reference": "Modules/Settings/DisplaysTab.qml:817, Modules/Settings/DankBarTab.qml:1446", "comment": "" }, { "term": "Show on Overview", "context": "Show on Overview", - "reference": "Modules/Settings/DockTab.qml:241, Modules/Settings/DankBarTab.qml:1582", + "reference": "Modules/Settings/DockTab.qml:248, Modules/Settings/DankBarTab.qml:1840", "comment": "" }, { "term": "Show on all connected displays", "context": "Show on all connected displays", - "reference": "Modules/Settings/DisplaysTab.qml:788, Modules/Settings/DankBarTab.qml:1184", + "reference": "Modules/Settings/DisplaysTab.qml:797, Modules/Settings/DankBarTab.qml:1433", "comment": "" }, { "term": "Show on screens:", "context": "Show on screens:", - "reference": "Modules/Settings/DisplaysTab.qml:773", + "reference": "Modules/Settings/DisplaysTab.qml:782", "comment": "" }, { "term": "Show on-screen display when brightness changes", "context": "Show on-screen display when brightness changes", - "reference": "Modules/Settings/WidgetTweaksTab.qml:827", + "reference": "Modules/Settings/WidgetTweaksTab.qml:814", "comment": "" }, { "term": "Show on-screen display when caps lock state changes", "context": "Show on-screen display when caps lock state changes", - "reference": "Modules/Settings/WidgetTweaksTab.qml:857", + "reference": "Modules/Settings/WidgetTweaksTab.qml:844", "comment": "" }, { "term": "Show on-screen display when idle inhibitor state changes", "context": "Show on-screen display when idle inhibitor state changes", - "reference": "Modules/Settings/WidgetTweaksTab.qml:837", + "reference": "Modules/Settings/WidgetTweaksTab.qml:824", "comment": "" }, { "term": "Show on-screen display when media player volume changes", "context": "Show on-screen display when media player volume changes", - "reference": "Modules/Settings/WidgetTweaksTab.qml:817", + "reference": "Modules/Settings/WidgetTweaksTab.qml:804", "comment": "" }, { "term": "Show on-screen display when microphone is muted/unmuted", "context": "Show on-screen display when microphone is muted/unmuted", - "reference": "Modules/Settings/WidgetTweaksTab.qml:847", + "reference": "Modules/Settings/WidgetTweaksTab.qml:834", "comment": "" }, { "term": "Show on-screen display when power profile changes", "context": "Show on-screen display when power profile changes", - "reference": "Modules/Settings/WidgetTweaksTab.qml:867", + "reference": "Modules/Settings/WidgetTweaksTab.qml:854", "comment": "" }, { "term": "Show on-screen display when volume changes", "context": "Show on-screen display when volume changes", - "reference": "Modules/Settings/WidgetTweaksTab.qml:806", + "reference": "Modules/Settings/WidgetTweaksTab.qml:794", "comment": "" }, { "term": "Show only apps running in current workspace", "context": "Show only apps running in current workspace", - "reference": "Modules/Settings/WidgetTweaksTab.qml:390", + "reference": "Modules/Settings/WidgetTweaksTab.qml:395", "comment": "" }, { "term": "Show only workspaces belonging to each specific monitor.", "context": "Show only workspaces belonging to each specific monitor.", - "reference": "Modules/Settings/WidgetTweaksTab.qml:135", + "reference": "Modules/Settings/WidgetTweaksTab.qml:131", "comment": "" }, { "term": "Show password", "context": "Show password", - "reference": "Modals/WifiPasswordModal.qml:482", + "reference": "Modals/WifiPasswordModal.qml:537", "comment": "" }, { "term": "Show power, restart, and logout buttons on the lock screen", "context": "Show power, restart, and logout buttons on the lock screen", - "reference": "Modals/Settings/PowerSettings.qml:58", + "reference": "Modals/Settings/PowerSettings.qml:59", "comment": "" }, { "term": "Show seconds", "context": "Show seconds", - "reference": "Modules/Settings/TimeWeatherTab.qml:121", + "reference": "Modules/Settings/TimeWeatherTab.qml:116", "comment": "" }, { "term": "Show weather information in top bar and control center", "context": "Show weather information in top bar and control center", - "reference": "Modules/Settings/TimeWeatherTab.qml:479", + "reference": "Modules/Settings/TimeWeatherTab.qml:483", "comment": "" }, { "term": "Show workspace index numbers in the top bar workspace switcher", "context": "Show workspace index numbers in the top bar workspace switcher", - "reference": "Modules/Settings/WidgetTweaksTab.qml:60", + "reference": "Modules/Settings/WidgetTweaksTab.qml:59", "comment": "" }, { "term": "Shows all running applications with focus indication", "context": "Shows all running applications with focus indication", - "reference": "Modules/Settings/DankBarTab.qml:217", + "reference": "Modules/Settings/DankBarTab.qml:369", "comment": "" }, { "term": "Shows current workspace and allows switching", "context": "Shows current workspace and allows switching", - "reference": "Modules/Settings/DankBarTab.qml:203", + "reference": "Modules/Settings/DankBarTab.qml:355", "comment": "" }, { "term": "Shows when caps lock is active", "context": "Shows when caps lock is active", - "reference": "Modules/Settings/DankBarTab.qml:341", + "reference": "Modules/Settings/DankBarTab.qml:493", "comment": "" }, { "term": "Shows when microphone, camera, or screen sharing is active", "context": "Shows when microphone, camera, or screen sharing is active", - "reference": "Modules/Settings/DankBarTab.qml:299", + "reference": "Modules/Settings/DankBarTab.qml:451", "comment": "" }, { @@ -3845,40 +4235,58 @@ "reference": "Services/CupsService.qml:326", "comment": "" }, + { + "term": "Signal", + "context": "Signal", + "reference": "Modules/Settings/NetworkTab.qml:1291", + "comment": "" + }, + { + "term": "Signal:", + "context": "Signal:", + "reference": "Modules/Settings/NetworkTab.qml:897", + "comment": "" + }, { "term": "Size", "context": "Size", - "reference": "Modules/ProcessList/SystemTab.qml:456, Modules/Settings/DankBarTab.qml:1809, Modules/Settings/DankBarTab.qml:1823", + "reference": "Modules/ProcessList/SystemTab.qml:442, Modules/Settings/DankBarTab.qml:2063, Modules/Settings/DankBarTab.qml:2077", "comment": "" }, { "term": "Size Offset", "context": "Size Offset", - "reference": "Modules/Settings/LauncherTab.qml:274", + "reference": "Modules/Settings/LauncherTab.qml:280", "comment": "" }, { "term": "Sort Alphabetically", "context": "Sort Alphabetically", - "reference": "Modules/Settings/LauncherTab.qml:489", + "reference": "Modules/Settings/LauncherTab.qml:493", "comment": "" }, { "term": "Sound Theme", "context": "Sound Theme", - "reference": "Modules/Settings/PersonalizationTab.qml:2010", + "reference": "Modules/Settings/PersonalizationTab.qml:2005", "comment": "" }, { "term": "Spacer", "context": "Spacer", - "reference": "Modules/Settings/DankBarTab.qml:347", + "reference": "Modules/Settings/DankBarTab.qml:499", "comment": "" }, { "term": "Spacing", "context": "Spacing", - "reference": "Modules/Settings/DockTab.qml:491, Modules/Settings/DankBarTab.qml:1640", + "reference": "Modules/Settings/DockTab.qml:493, Modules/Settings/DankBarTab.qml:1898", + "comment": "" + }, + { + "term": "Speed", + "context": "Speed", + "reference": "Modules/Settings/NetworkTab.qml:537", "comment": "" }, { @@ -3890,13 +4298,13 @@ { "term": "Square Corners", "context": "Square Corners", - "reference": "Modules/Settings/DankBarTab.qml:1986", + "reference": "Modules/Settings/DankBarTab.qml:2236", "comment": "" }, { "term": "Start", "context": "Start", - "reference": "Modules/Settings/DisplaysTab.qml:347", + "reference": "Modules/Settings/DisplaysTab.qml:359", "comment": "" }, { @@ -3905,10 +4313,16 @@ "reference": "Modules/Notepad/NotepadTextEditor.qml:386", "comment": "" }, + { + "term": "State", + "context": "State", + "reference": "Modules/Settings/NetworkTab.qml:551", + "comment": "" + }, { "term": "Status", "context": "Status", - "reference": "Widgets/DankIconPicker.qml:49", + "reference": "Widgets/DankIconPicker.qml:49, Modules/Settings/NetworkTab.qml:128", "comment": "" }, { @@ -3932,7 +4346,7 @@ { "term": "Storage & Disks", "context": "Storage & Disks", - "reference": "Modules/ProcessList/SystemTab.qml:414", + "reference": "Modules/ProcessList/SystemTab.qml:401", "comment": "" }, { @@ -3944,31 +4358,31 @@ { "term": "Surface", "context": "Surface", - "reference": "Modules/Settings/LauncherTab.qml:201", + "reference": "Modules/Settings/LauncherTab.qml:203", "comment": "" }, { "term": "Suspend", "context": "Suspend", - "reference": "Modals/PowerMenuModal.qml:121, Modals/PowerMenuModal.qml:163, Modules/Lock/LockPowerMenu.qml:88", + "reference": "Modals/PowerMenuModal.qml:206, Modules/Lock/LockPowerMenu.qml:88", "comment": "" }, { "term": "Suspend behavior", "context": "Suspend behavior", - "reference": "Modals/Settings/PowerSettings.qml:280", + "reference": "Modals/Settings/PowerSettings.qml:315", "comment": "" }, { "term": "Suspend system after", "context": "Suspend system after", - "reference": "Modals/Settings/PowerSettings.qml:243", + "reference": "Modals/Settings/PowerSettings.qml:278", "comment": "" }, { "term": "Swap", "context": "Swap", - "reference": "Modules/ProcessList/PerformanceTab.qml:272", + "reference": "Modules/ProcessList/PerformanceTab.qml:263", "comment": "" }, { @@ -3980,31 +4394,31 @@ { "term": "Sync Mode with Portal", "context": "Sync Mode with Portal", - "reference": "Modules/Settings/ThemeColorsTab.qml:1210", + "reference": "Modules/Settings/ThemeColorsTab.qml:1211", "comment": "" }, { "term": "Sync dark mode with settings portals for system-wide theme hints", "context": "Sync dark mode with settings portals for system-wide theme hints", - "reference": "Modules/Settings/ThemeColorsTab.qml:1211", + "reference": "Modules/Settings/ThemeColorsTab.qml:1212", "comment": "" }, { "term": "System", "context": "System", - "reference": "Services/AppSearchService.qml:270, Widgets/DankIconPicker.qml:40, Modules/ProcessList/SystemTab.qml:130", + "reference": "Services/AppSearchService.qml:270, Widgets/DankIconPicker.qml:40, Modules/ProcessList/SystemTab.qml:127", "comment": "" }, { "term": "System App Theming", "context": "System App Theming", - "reference": "Modules/Settings/ThemeColorsTab.qml:1344", + "reference": "Modules/Settings/ThemeColorsTab.qml:1339", "comment": "" }, { "term": "System Monitor", "context": "sysmon window title", - "reference": "Modals/ProcessListModal.qml:44, Modals/ProcessListModal.qml:166", + "reference": "Modals/ProcessListModal.qml:43, Modals/ProcessListModal.qml:166", "comment": "" }, { @@ -4016,25 +4430,25 @@ { "term": "System Monitoring:", "context": "System Monitoring:", - "reference": "Modules/Settings/AboutTab.qml:560", + "reference": "Modules/Settings/AboutTab.qml:561", "comment": "" }, { "term": "System Tray", "context": "System Tray", - "reference": "Modules/Settings/DisplaysTab.qml:60, Modules/Settings/DankBarTab.qml:291", + "reference": "Modules/Settings/DisplaysTab.qml:64, Modules/Settings/DankBarTab.qml:443", "comment": "" }, { "term": "System Update", "context": "System Update", - "reference": "Modules/Settings/DankBarTab.qml:389", + "reference": "Modules/Settings/DankBarTab.qml:541", "comment": "" }, { "term": "System Updater", "context": "System Updater", - "reference": "Modules/Settings/WidgetTweaksTab.qml:230", + "reference": "Modules/Settings/WidgetTweaksTab.qml:236", "comment": "" }, { @@ -4046,25 +4460,25 @@ { "term": "System notification area icons", "context": "System notification area icons", - "reference": "Modules/Settings/DankBarTab.qml:292", + "reference": "Modules/Settings/DankBarTab.qml:444", "comment": "" }, { "term": "System toast notifications", "context": "System toast notifications", - "reference": "Modules/Settings/DisplaysTab.qml:51", + "reference": "Modules/Settings/DisplaysTab.qml:53", "comment": "" }, { "term": "System tray icons", "context": "System tray icons", - "reference": "Modules/Settings/DisplaysTab.qml:61", + "reference": "Modules/Settings/DisplaysTab.qml:65", "comment": "" }, { "term": "System update custom command", "context": "System update custom command", - "reference": "Modules/Settings/WidgetTweaksTab.qml:266", + "reference": "Modules/Settings/WidgetTweaksTab.qml:272", "comment": "" }, { @@ -4076,13 +4490,13 @@ { "term": "Terminal custom additional parameters", "context": "Terminal custom additional parameters", - "reference": "Modules/Settings/WidgetTweaksTab.qml:313", + "reference": "Modules/Settings/WidgetTweaksTab.qml:319", "comment": "" }, { "term": "Terminals - Always use Dark Theme", "context": "Terminals - Always use Dark Theme", - "reference": "Modules/Settings/ThemeColorsTab.qml:1220", + "reference": "Modules/Settings/ThemeColorsTab.qml:1221", "comment": "" }, { @@ -4094,13 +4508,13 @@ { "term": "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.", "context": "The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.", - "reference": "Modules/Settings/PluginsTab.qml:111", + "reference": "Modules/Settings/PluginsTab.qml:114", "comment": "" }, { "term": "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).", "context": "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).", - "reference": "Modules/Settings/ThemeColorsTab.qml:1255", + "reference": "Modules/Settings/ThemeColorsTab.qml:1254", "comment": "" }, { @@ -4112,31 +4526,31 @@ { "term": "Theme & Colors", "context": "Theme & Colors", - "reference": "Modals/Settings/SettingsSidebar.qml:43", + "reference": "Modals/Settings/SettingsSidebar.qml:57", "comment": "" }, { "term": "Theme Color", "context": "Theme Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:107", + "reference": "Modules/Settings/ThemeColorsTab.qml:100", "comment": "" }, { "term": "Third-Party Plugin Warning", "context": "Third-Party Plugin Warning", - "reference": "Modules/Settings/PluginBrowser.qml:601", + "reference": "Modules/Settings/PluginBrowser.qml:537, Modules/Settings/PluginBrowser.qml:571", "comment": "" }, { "term": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\\n\\nThese plugins may pose security and privacy risks - install at your own risk.", "context": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\\n\\nThese plugins may pose security and privacy risks - install at your own risk.", - "reference": "Modules/Settings/PluginBrowser.qml:611", + "reference": "Modules/Settings/PluginBrowser.qml:595", "comment": "" }, { "term": "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.", "context": "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.", - "reference": "Modules/Settings/DankBarTab.qml:286", + "reference": "Modules/Settings/DankBarTab.qml:438", "comment": "" }, { @@ -4154,7 +4568,7 @@ { "term": "Time & Weather", "context": "Time & Weather", - "reference": "Modals/Settings/SettingsSidebar.qml:19", + "reference": "Modals/Settings/SettingsSidebar.qml:21", "comment": "" }, { @@ -4178,7 +4592,7 @@ { "term": "Toast Messages", "context": "Toast Messages", - "reference": "Modules/Settings/DisplaysTab.qml:50", + "reference": "Modules/Settings/DisplaysTab.qml:52", "comment": "" }, { @@ -4190,13 +4604,19 @@ { "term": "Toggle top bar visibility manually (can be controlled via IPC)", "context": "Toggle top bar visibility manually (can be controlled via IPC)", - "reference": "Modules/Settings/DankBarTab.qml:1534", + "reference": "Modules/Settings/DankBarTab.qml:1792", "comment": "" }, { "term": "Toggle visibility of this bar configuration", "context": "Toggle visibility of this bar configuration", - "reference": "Modules/Settings/DankBarTab.qml:1107", + "reference": "Modules/Settings/DankBarTab.qml:1356", + "comment": "" + }, + { + "term": "Toggling...", + "context": "Toggling...", + "reference": "Modules/Settings/NetworkTab.qml:753", "comment": "" }, { @@ -4220,43 +4640,55 @@ { "term": "Top", "context": "Top", - "reference": "Modules/Settings/DankBarTab.qml:967, Modules/Settings/DankBarTab.qml:975, Modules/Settings/DankBarTab.qml:1300", + "reference": "Modules/Settings/DankBarTab.qml:1216, Modules/Settings/DankBarTab.qml:1224, Modules/Settings/DankBarTab.qml:1558", "comment": "" }, { "term": "Top Bar Format", "context": "Top Bar Format", - "reference": "Modules/Settings/TimeWeatherTab.qml:188", + "reference": "Modules/Settings/TimeWeatherTab.qml:181", "comment": "" }, { "term": "Top Section", "context": "Top Section", - "reference": "Modules/Settings/DankBarTab.qml:2746", + "reference": "Modules/Settings/DankBarTab.qml:3230", "comment": "" }, { "term": "Transition Effect", "context": "Transition Effect", - "reference": "Modules/Settings/PersonalizationTab.qml:1375", + "reference": "Modules/Settings/PersonalizationTab.qml:1370", "comment": "" }, { "term": "Turn off monitors after", "context": "Turn off monitors after", - "reference": "Modals/Settings/PowerSettings.qml:206", + "reference": "Modals/Settings/PowerSettings.qml:241", + "comment": "" + }, + { + "term": "Unavailable", + "context": "Unavailable", + "reference": "Modules/Settings/NetworkTab.qml:388", "comment": "" }, { "term": "Uninstall Plugin", "context": "Uninstall Plugin", - "reference": "Modules/Settings/PluginListItem.qml:197", + "reference": "Modules/Settings/PluginListItem.qml:192", + "comment": "" + }, + { + "term": "Unknown", + "context": "Unknown", + "reference": "Modules/Settings/NetworkTab.qml:121, Modules/Settings/NetworkTab.qml:163, Modules/Settings/NetworkTab.qml:369, Modules/Settings/NetworkTab.qml:390, Modules/Settings/NetworkTab.qml:552, Modules/Settings/NetworkTab.qml:681, Modules/Settings/NetworkTab.qml:1085", "comment": "" }, { "term": "Unpin from Dock", "context": "Unpin from Dock", - "reference": "Modals/Spotlight/SpotlightContextMenu.qml:113, Modules/AppDrawer/AppDrawerPopout.qml:598, Modules/Dock/DockContextMenu.qml:373", + "reference": "Modals/Spotlight/SpotlightContextMenuContent.qml:26, Modules/AppDrawer/AppDrawerPopout.qml:591, Modules/Dock/DockContextMenu.qml:379", "comment": "" }, { @@ -4292,43 +4724,43 @@ { "term": "Update Plugin", "context": "Update Plugin", - "reference": "Modules/Settings/PluginListItem.qml:148", + "reference": "Modules/Settings/PluginListItem.qml:149", "comment": "" }, { "term": "Use 24-hour time format instead of 12-hour AM/PM", "context": "Use 24-hour time format instead of 12-hour AM/PM", - "reference": "Modules/Settings/TimeWeatherTab.qml:65", + "reference": "Modules/Settings/TimeWeatherTab.qml:63", "comment": "" }, { "term": "Use Custom Command", "context": "Use Custom Command", - "reference": "Modules/Settings/WidgetTweaksTab.qml:240", + "reference": "Modules/Settings/WidgetTweaksTab.qml:246", "comment": "" }, { "term": "Use Grid Layout", "context": "Use Grid Layout", - "reference": "Modals/Settings/PowerSettings.qml:372", + "reference": "Modals/Settings/PowerSettings.qml:407", "comment": "" }, { "term": "Use IP Location", "context": "Use IP Location", - "reference": "Modules/Settings/DisplaysTab.qml:440", + "reference": "Modules/Settings/DisplaysTab.qml:452", "comment": "" }, { "term": "Use Imperial Units", "context": "Use Imperial Units", - "reference": "Modules/Settings/TimeWeatherTab.qml:537", + "reference": "Modules/Settings/TimeWeatherTab.qml:538", "comment": "" }, { "term": "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)", "context": "Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)", - "reference": "Modules/Settings/TimeWeatherTab.qml:544", + "reference": "Modules/Settings/TimeWeatherTab.qml:545", "comment": "" }, { @@ -4340,61 +4772,61 @@ { "term": "Use System Theme", "context": "Use System Theme", - "reference": "Modules/Settings/PersonalizationTab.qml:1982", + "reference": "Modules/Settings/PersonalizationTab.qml:1977", "comment": "" }, { "term": "Use animated wave progress bars for media playback", "context": "Use animated wave progress bars for media playback", - "reference": "Modules/Settings/WidgetTweaksTab.qml:194", + "reference": "Modules/Settings/WidgetTweaksTab.qml:200", "comment": "" }, { "term": "Use custom command for update your system", "context": "Use custom command for update your system", - "reference": "Modules/Settings/WidgetTweaksTab.qml:241", + "reference": "Modules/Settings/WidgetTweaksTab.qml:247", "comment": "" }, { "term": "Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)", "context": "Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)", - "reference": "Modals/Settings/PowerSettings.qml:97", + "reference": "Modals/Settings/PowerSettings.qml:98", "comment": "" }, { "term": "Use light theme instead of dark theme", "context": "Use light theme instead of dark theme", - "reference": "Modules/Settings/PersonalizationTab.qml:1531", + "reference": "Modules/Settings/PersonalizationTab.qml:1526", "comment": "" }, { "term": "Use sound theme from system settings", "context": "Use sound theme from system settings", - "reference": "Modules/Settings/PersonalizationTab.qml:1988", + "reference": "Modules/Settings/PersonalizationTab.qml:1983", "comment": "" }, { "term": "Use%", "context": "Use%", - "reference": "Modules/ProcessList/SystemTab.qml:489", + "reference": "Modules/ProcessList/SystemTab.qml:475", "comment": "" }, { "term": "Used", "context": "Used", - "reference": "Modules/ProcessList/SystemTab.qml:467", + "reference": "Modules/ProcessList/SystemTab.qml:453", "comment": "" }, { "term": "Username", "context": "Username", - "reference": "Modals/WifiPasswordModal.qml:274", + "reference": "Modals/WifiPasswordModal.qml:121, Modals/WifiPasswordModal.qml:390, Widgets/VpnDetailContent.qml:389, Modules/Settings/NetworkTab.qml:1755", "comment": "" }, { "term": "Uses sunrise/sunset times to automatically adjust night mode based on your location.", "context": "Uses sunrise/sunset times to automatically adjust night mode based on your location.", - "reference": "Modules/Settings/DisplaysTab.qml:518", + "reference": "Modules/Settings/DisplaysTab.qml:530", "comment": "" }, { @@ -4406,19 +4838,43 @@ { "term": "VPN", "context": "VPN", - "reference": "Modules/Settings/DankBarTab.qml:326", + "reference": "Modules/Settings/WidgetsTabSection.qml:763, Modules/Settings/NetworkTab.qml:1417, Modules/Settings/DankBarTab.qml:478", "comment": "" }, { "term": "VPN Connections", "context": "VPN Connections", - "reference": "Modules/DankBar/Popouts/VpnPopout.qml:104", + "reference": "Modules/DankBar/Popouts/VpnPopout.qml:67", + "comment": "" + }, + { + "term": "VPN Password", + "context": "VPN Password", + "reference": "Modals/WifiPasswordModal.qml:191", + "comment": "" + }, + { + "term": "VPN configuration updated", + "context": "VPN configuration updated", + "reference": "Services/VPNService.qml:143", + "comment": "" + }, + { + "term": "VPN deleted", + "context": "VPN deleted", + "reference": "Services/VPNService.qml:159", + "comment": "" + }, + { + "term": "VPN imported: ", + "context": "VPN imported: ", + "reference": "Services/VPNService.qml:91", "comment": "" }, { "term": "VPN status and quick connect", "context": "VPN status and quick connect", - "reference": "Modules/Settings/DankBarTab.qml:327", + "reference": "Modules/Settings/DankBarTab.qml:479", "comment": "" }, { @@ -4454,61 +4910,67 @@ { "term": "Vibrant palette with playful saturation.", "context": "Vibrant palette with playful saturation.", - "reference": "Common/Theme.qml:228", + "reference": "Common/Theme.qml:225", "comment": "" }, { "term": "Visibility", "context": "Visibility", - "reference": "Modules/DankDash/WeatherTab.qml:512, Modules/Settings/TimeWeatherTab.qml:1338", + "reference": "Modules/DankDash/WeatherTab.qml:512, Modules/Settings/TimeWeatherTab.qml:1337", "comment": "" }, { "term": "Visual divider between widgets", "context": "Visual divider between widgets", - "reference": "Modules/Settings/DankBarTab.qml:355", + "reference": "Modules/Settings/DankBarTab.qml:507", "comment": "" }, { "term": "Visual effect used when wallpaper changes", "context": "Visual effect used when wallpaper changes", - "reference": "Modules/Settings/PersonalizationTab.qml:1376", + "reference": "Modules/Settings/PersonalizationTab.qml:1371", "comment": "" }, { "term": "Volume Changed", "context": "Volume Changed", - "reference": "Modules/Settings/PersonalizationTab.qml:2081", + "reference": "Modules/Settings/PersonalizationTab.qml:2076", "comment": "" }, { "term": "Volume OSD", "context": "Volume OSD", - "reference": "Modules/Settings/WidgetTweaksTab.qml:805", + "reference": "Modules/Settings/WidgetTweaksTab.qml:793", "comment": "" }, { "term": "Volume, brightness, and other system OSDs", "context": "Volume, brightness, and other system OSDs", - "reference": "Modules/Settings/DisplaysTab.qml:46", + "reference": "Modules/Settings/DisplaysTab.qml:47", + "comment": "" + }, + { + "term": "WPA/WPA2", + "context": "WPA/WPA2", + "reference": "Modules/Settings/NetworkTab.qml:1321", "comment": "" }, { "term": "Wallpaper", "context": "Wallpaper", - "reference": "Modules/Settings/DisplaysTab.qml:40, Modules/Settings/PersonalizationTab.qml:109", + "reference": "Modules/Settings/DisplaysTab.qml:40, Modules/Settings/PersonalizationTab.qml:103", "comment": "" }, { "term": "Wallpaper Monitor", "context": "Wallpaper Monitor", - "reference": "Modules/Settings/PersonalizationTab.qml:1008", + "reference": "Modules/Settings/PersonalizationTab.qml:1000", "comment": "" }, { "term": "Wallpapers", "context": "Wallpapers", - "reference": "Modules/DankDash/DankDashPopout.qml:191", + "reference": "Modules/DankDash/DankDashPopout.qml:277", "comment": "" }, { @@ -4520,61 +4982,85 @@ { "term": "Wave Progress Bars", "context": "Wave Progress Bars", - "reference": "Modules/Settings/WidgetTweaksTab.qml:193", + "reference": "Modules/Settings/WidgetTweaksTab.qml:199", "comment": "" }, { "term": "Weather", "context": "Weather", - "reference": "Modules/DankDash/DankDashPopout.qml:197", + "reference": "Modules/DankDash/DankDashPopout.qml:284", "comment": "" }, { "term": "Weather Widget", "context": "Weather Widget", - "reference": "Modules/Settings/DankBarTab.qml:230", + "reference": "Modules/Settings/DankBarTab.qml:382", "comment": "" }, { "term": "Website:", "context": "Website:", - "reference": "Modules/Settings/AboutTab.qml:479", + "reference": "Modules/Settings/AboutTab.qml:480", "comment": "" }, { "term": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.", "context": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.", - "reference": "Modules/Settings/LauncherTab.qml:518", + "reference": "Modules/Settings/LauncherTab.qml:520", + "comment": "" + }, + { + "term": "Wi-Fi Password", + "context": "Wi-Fi Password", + "reference": "Modals/WifiPasswordModal.qml:191", + "comment": "" + }, + { + "term": "WiFi", + "context": "WiFi", + "reference": "Modules/Settings/NetworkTab.qml:159, Modules/Settings/NetworkTab.qml:206, Modules/Settings/NetworkTab.qml:744", + "comment": "" + }, + { + "term": "WiFi Device", + "context": "WiFi Device", + "reference": "Modules/Settings/NetworkTab.qml:800, Modules/Settings/NetworkTab.qml:832", "comment": "" }, { "term": "WiFi disabled", "context": "WiFi disabled", - "reference": "Services/DMSNetworkService.qml:538", + "reference": "Services/DMSNetworkService.qml:570", "comment": "" }, { "term": "WiFi enabled", "context": "WiFi enabled", - "reference": "Services/DMSNetworkService.qml:538, Services/DMSNetworkService.qml:550", + "reference": "Services/DMSNetworkService.qml:570, Services/DMSNetworkService.qml:582", "comment": "" }, { "term": "WiFi is off", "context": "WiFi is off", - "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:166", + "reference": "Modules/ControlCenter/Details/NetworkDetail.qml:194", "comment": "" }, { "term": "Widget Background Color", "context": "Widget Background Color", - "reference": "Modules/Settings/ThemeColorsTab.qml:774", + "reference": "Modules/Settings/ThemeColorsTab.qml:778", "comment": "" }, { "term": "Widget Management", "context": "Widget Management", - "reference": "Modules/Settings/DankBarTab.qml:2648", + "reference": "Modules/Settings/DankBarTab.qml:3132", + "comment": "" + }, + { + "term": "Widget Outline", + "context": "Widget Outline", + "reference": "Modules/Settings/DankBarTab.qml:2610", "comment": "" }, { @@ -4592,19 +5078,19 @@ { "term": "Widget Transparency", "context": "Widget Transparency", - "reference": "Modules/Settings/DankBarTab.qml:2449, Modules/Settings/DankBarTab.qml:2463", + "reference": "Modules/Settings/DankBarTab.qml:2935, Modules/Settings/DankBarTab.qml:2949", "comment": "" }, { "term": "Widgets", "context": "Widgets", - "reference": "Modals/Settings/SettingsSidebar.qml:27", + "reference": "Modals/Settings/SettingsSidebar.qml:31", "comment": "" }, { "term": "Wind", "context": "Wind", - "reference": "Modules/DankDash/WeatherTab.qml:354, Modules/Settings/TimeWeatherTab.qml:1180", + "reference": "Modules/DankDash/WeatherTab.qml:354, Modules/Settings/TimeWeatherTab.qml:1176", "comment": "" }, { @@ -4616,25 +5102,31 @@ { "term": "Workspace Index Numbers", "context": "Workspace Index Numbers", - "reference": "Modules/Settings/WidgetTweaksTab.qml:59", + "reference": "Modules/Settings/WidgetTweaksTab.qml:58", "comment": "" }, { "term": "Workspace Padding", "context": "Workspace Padding", - "reference": "Modules/Settings/WidgetTweaksTab.qml:69", + "reference": "Modules/Settings/WidgetTweaksTab.qml:67", "comment": "" }, { "term": "Workspace Settings", "context": "Workspace Settings", - "reference": "Modules/Settings/WidgetTweaksTab.qml:49", + "reference": "Modules/Settings/WidgetTweaksTab.qml:48", "comment": "" }, { "term": "Workspace Switcher", "context": "Workspace Switcher", - "reference": "Modules/Settings/DankBarTab.qml:202", + "reference": "Modules/Settings/DankBarTab.qml:354", + "comment": "" + }, + { + "term": "Yes", + "context": "Yes", + "reference": "Widgets/VpnDetailContent.qml:419, Modules/Settings/NetworkTab.qml:1785", "comment": "" }, { @@ -4670,103 +5162,103 @@ { "term": "loginctl not available - lock integration requires DMS socket connection", "context": "loginctl not available - lock integration requires DMS socket connection", - "reference": "Modals/Settings/PowerSettings.qml:64", + "reference": "Modals/Settings/PowerSettings.qml:65", "comment": "" }, { "term": "matugen not detected - dynamic theming unavailable", "context": "matugen not detected - dynamic theming unavailable", - "reference": "Modules/Settings/PersonalizationTab.qml:1890", + "reference": "Modules/Settings/PersonalizationTab.qml:1885", "comment": "" }, { "term": "official", "context": "official", - "reference": "Modules/Settings/PluginBrowser.qml:408", + "reference": "Modules/Settings/PluginBrowser.qml:380", "comment": "" }, { "term": "update dms for NM integration.", "context": "update dms for NM integration.", - "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:205", + "reference": "Modules/ControlCenter/Components/DragDropGrid.qml:207", "comment": "" }, { "term": "• Install only from trusted sources", "context": "• Install only from trusted sources", - "reference": "Modules/Settings/PluginBrowser.qml:634", + "reference": "Modules/Settings/PluginBrowser.qml:618", "comment": "" }, { "term": "• M - Month (1-12)", "context": "• M - Month (1-12)", - "reference": "Modules/Settings/TimeWeatherTab.qml:392", + "reference": "Modules/Settings/TimeWeatherTab.qml:398", "comment": "" }, { "term": "• MM - Month (01-12)", "context": "• MM - Month (01-12)", - "reference": "Modules/Settings/TimeWeatherTab.qml:403", + "reference": "Modules/Settings/TimeWeatherTab.qml:409", "comment": "" }, { "term": "• MMM - Month (Jan)", "context": "• MMM - Month (Jan)", - "reference": "Modules/Settings/TimeWeatherTab.qml:409", + "reference": "Modules/Settings/TimeWeatherTab.qml:415", "comment": "" }, { "term": "• MMMM - Month (January)", "context": "• MMMM - Month (January)", - "reference": "Modules/Settings/TimeWeatherTab.qml:415", + "reference": "Modules/Settings/TimeWeatherTab.qml:421", "comment": "" }, { "term": "• Plugins may contain bugs or security issues", "context": "• Plugins may contain bugs or security issues", - "reference": "Modules/Settings/PluginBrowser.qml:622", + "reference": "Modules/Settings/PluginBrowser.qml:606", "comment": "" }, { "term": "• Review code before installation when possible", "context": "• Review code before installation when possible", - "reference": "Modules/Settings/PluginBrowser.qml:628", + "reference": "Modules/Settings/PluginBrowser.qml:612", "comment": "" }, { "term": "• d - Day (1-31)", "context": "• d - Day (1-31)", - "reference": "Modules/Settings/TimeWeatherTab.qml:368", + "reference": "Modules/Settings/TimeWeatherTab.qml:374", "comment": "" }, { "term": "• dd - Day (01-31)", "context": "• dd - Day (01-31)", - "reference": "Modules/Settings/TimeWeatherTab.qml:374", + "reference": "Modules/Settings/TimeWeatherTab.qml:380", "comment": "" }, { "term": "• ddd - Day name (Mon)", "context": "• ddd - Day name (Mon)", - "reference": "Modules/Settings/TimeWeatherTab.qml:380", + "reference": "Modules/Settings/TimeWeatherTab.qml:386", "comment": "" }, { "term": "• dddd - Day name (Monday)", "context": "• dddd - Day name (Monday)", - "reference": "Modules/Settings/TimeWeatherTab.qml:386", + "reference": "Modules/Settings/TimeWeatherTab.qml:392", "comment": "" }, { "term": "• yy - Year (24)", "context": "• yy - Year (24)", - "reference": "Modules/Settings/TimeWeatherTab.qml:421", + "reference": "Modules/Settings/TimeWeatherTab.qml:427", "comment": "" }, { "term": "• yyyy - Year (2024)", "context": "• yyyy - Year (2024)", - "reference": "Modules/Settings/TimeWeatherTab.qml:427", + "reference": "Modules/Settings/TimeWeatherTab.qml:433", "comment": "" } ] \ No newline at end of file diff --git a/quickshell/translations/poexports/it.json b/quickshell/translations/poexports/it.json index 93aab139..eabcce51 100644 --- a/quickshell/translations/poexports/it.json +++ b/quickshell/translations/poexports/it.json @@ -1,12 +1,18 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1 caratteri" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { - "%1 display(s)": "" + "%1 display(s)": "%1 display(s)" }, "%1 widgets": { - "%1 widgets": "" + "%1 widgets": "%1 widgets" }, "(Unnamed)": { "(Unnamed)": "(Senza nome)" @@ -50,11 +56,26 @@ "Actions": { "Actions": "Azioni" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "Aggiungi" }, "Add Bar": { - "Add Bar": "" + "Add Bar": "Aggiungi Barra" }, "Add Widget": { "Add Widget": "Aggiungi Widget" @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "Aggiungi Widget" }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "Aggiungi una VPN in NetworkManager" }, @@ -84,7 +108,7 @@ "Always Show OSD Percentage": "Visualizza sempre percentuale OSD" }, "Always on icons": { - "Always on icons": "" + "Always on icons": "Icone sempre attive" }, "Always show a minimum of 3 workspaces, even if fewer are available": { "Always show a minimum of 3 workspaces, even if fewer are available": "Visualizza sempre un minimo di 3 workspaces, anche se ne sono visibili meno" @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "Velocità Animazione" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "Identità anonima (facoltativa)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "Sei sicuro di voler sospendere il sistema?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "Codec Audio" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "Dispositivi Uscita Audio (" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "Autenticare" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "Autenticazione Richiesta" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "Autorizza servizio per " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "Posizione Automatica" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "Salvataggio automatico..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "Connessione automatica disabilitata" }, @@ -224,23 +269,32 @@ "Available Layouts": { "Available Layouts": "Layouts Disponibili" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "Plugins Disponibili" }, "Available Screens (": { "Available Screens (": "Schermi Disponibili (" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "Indietro" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "Tavolozza bilanciata con accenti focalizzati (default)." }, "Bar Configurations": { - "Bar Configurations": "" + "Bar Configurations": "Configurazioni Barra" }, "Bar Transparency": { - "Bar Transparency": "" + "Bar Transparency": "Trasparenza Barra" }, "Battery": { "Battery": "Batteria" @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Collega il blocca schermo ai segnali dbus da loginctl.\nDisabilità se stai usando un blocca schermo esterno" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "Icona Bluetooth" }, @@ -341,17 +398,23 @@ "Center Tiling": { "Center Tiling": "Tiling Centrale" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { - "Change bar appearance": "" + "Change bar appearance": "Cambia aspetto barra" }, "Changes:": { "Changes:": "Modifiche:" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "Controlla aggiornamenti di sistema" }, "Choose Color": { - "Choose Color": "" + "Choose Color": "Scegli colore" }, "Choose Launcher Logo Color": { "Choose Launcher Logo Color": "Scegli Colore Logo Launcher" @@ -360,7 +423,7 @@ "Choose icon": "Scegli icona" }, "Choose the background color for widgets": { - "Choose the background color for widgets": "" + "Choose the background color for widgets": "Scegli il colore di sfondo per i widgets" }, "Choose the border accent color": { "Choose the border accent color": "Scegli il colore di accento dei bordi" @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "Scegli il logo visualizzato sul bottone lanciatore nella DankBar" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "Scegli dove i popup delle notifiche appaiono sullo schermo" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "Scegli dove i messaggi appaiono sullo schermo" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "Pulisci" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "Pulire tutta la cronologia?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "Cronologia Clipboard" }, @@ -399,7 +471,7 @@ "Close": "Chiudi" }, "Close Overview on Launch": { - "Close Overview on Launch": "" + "Close Overview on Launch": "Chiudi Overview all'Avvio" }, "Color Override": { "Color Override": "Sostituzione Colore" @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "Connetti a Wi-Fi" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "Display Connessi" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Elimina • Shift+Del: Elimina Tutto • 1-9: Azioni • F10: Help • Esc: Chiude" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "Deriva colori che si avvicinano all'immagine sottostante" }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "Disconnetti" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "Disconnesso dal Wi-Fi" }, @@ -654,10 +738,10 @@ "Dismiss": "Dismetti" }, "Display Assignment": { - "Display Assignment": "" + "Display Assignment": "Assegnazione di visualizzazione" }, "Display Name Format": { - "Display Name Format": "" + "Display Name Format": "Formato del nome visualizzato" }, "Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": { "Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "Visualizza una dock con applicazioni pinnate ed in esecuzione che possono essere posizionate nell'angolo superiore, inferiore, sinistro o destro dello schermo" @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "Mostra il titolo delle applicazioni attualmente in focus" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "Visualizza le azioni di alimentazioni in griglia invece di una lista" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Trascina i widget per riordinarli nelle sezioni. Usa l'icona occhio per nascondere/mostrare i widget (mantenendo la spaziatura), o X per rimuoverli completamente." }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "Duplica Sfondo con Sfocatura" }, @@ -738,7 +828,7 @@ "Enable Autoconnect": "Abilita connessione automatica" }, "Enable Bar": { - "Enable Bar": "" + "Enable Bar": "Abilita Barra" }, "Enable GPU Temperature": { "Enable GPU Temperature": "Abilita Temperatura GPU" @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "Inserisci questa passkey su " }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "Errore" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "Offset Zona Esclusa" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: Cambia • F10: Help" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "Impossibile attivare configurazione" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "Impossibile connettersi a " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "Impossibile disconnettersi dalla VPN" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "Impossibile abilitare WiFi" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "Impossibile mettere in pausa la stampante" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "Impossibile avviare connessione a " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "Impossibile aggiornare connessione automatica" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "Forza applicazioni da terminale ad usare schemi di colori scuri" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "Dimentica Dispositivo" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "Legenda Formato" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "Svago" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "Angoli Gotici" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "Grafica" }, @@ -975,7 +1098,7 @@ "Hibernate": "Iberna" }, "Hide Delay (ms)": { - "Hide Delay (ms)": "" + "Hide Delay (ms)": "Ritardo Scomparsa (ms)" }, "Hide the dock when not in use and reveal it when hovering near the dock area": { "Hide the dock when not in use and reveal it when hovering near the dock area": "Nascondi la dock quando " @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "Tavolozza alta-fedeltà per preservare la tonalità della sorgente" }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "Ore" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "Ho capito" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "Dimensione Icona" }, @@ -1011,7 +1152,7 @@ "Idle Inhibitor": "Inibitore Riposo" }, "Idle Inhibitor OSD": { - "Idle Inhibitor OSD": "" + "Idle Inhibitor OSD": "OSD Inibitore inattività" }, "Idle Settings": { "Idle Settings": "Impostazioni Riposo" @@ -1022,6 +1163,12 @@ "Image": { "Image": "Immagine" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "Includi Transizioni" }, @@ -1035,7 +1182,7 @@ "Individual Batteries": "Batterie Individuali" }, "Individual bar configuration": { - "Individual bar configuration": "" + "Individual bar configuration": "Configurazione barra individuale" }, "Inhibit idle timeout when audio or video is playing": { "Inhibit idle timeout when audio or video is playing": "Impedisci tempo inattività quando audio o video sono in riproduzione" @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "Installa plugins dal registro dei plugin DMS" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "Interblocco Aperto" }, @@ -1065,13 +1215,13 @@ "Jobs: ": "Lavori:" }, "Keep Awake": { - "Keep Awake": "" + "Keep Awake": "Mantieni Attivo" }, "Keep Changes": { "Keep Changes": "Conserva Modifiche" }, "Keeping Awake": { - "Keeping Awake": "" + "Keeping Awake": "Mantieni Attivo" }, "Keyboard Layout Name": { "Keyboard Layout Name": "Nome Layout Tastiera" @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "Caricamento plugins..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "Ricerca Posizione" }, @@ -1160,11 +1313,17 @@ "Low Priority": { "Low Priority": "Bassa Priorità" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "Gestione e configurazione plugins per estendere le funzionalità di DMS" }, "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "" + "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Gestisci fino a 4 configurazioni di barre indipendenti. Ogni barra ha la propria posizione, widget, stile e assegnazione di visualizzazione. " }, "Manual Coordinates": { "Manual Coordinates": "Coordinate Manuali" @@ -1230,7 +1389,7 @@ "Media Players (": "Media Players (" }, "Media Volume OSD": { - "Media Volume OSD": "" + "Media Volume OSD": "OSD Volume Media" }, "Memory": { "Memory": "Memoria" @@ -1245,10 +1404,10 @@ "Microphone": "Microfono" }, "Microphone Mute OSD": { - "Microphone Mute OSD": "" + "Microphone Mute OSD": "OSD Microfono Muto" }, "Middle Section": { - "Middle Section": "" + "Middle Section": "Sezione Centrale" }, "Minimal palette built around a single hue.": { "Minimal palette built around a single hue.": "Tavolozza minima costruita attorno a una singola tonalità." @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "Minuti" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "Modalità:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "Monitor Velocità Rete" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "Mostra velocità di download e upload della rete" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "Temperatura Notte" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "Nessun Riproduttore Attivo" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "Nessun Media" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "Nessun profilo VPN trovato" }, "No Weather Data Available": { "No Weather Data Available": "Nessun Dato Meteo Disponibile" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "Nessun appunto trovato" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "Priorità Normale" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "Notepad" }, @@ -1431,7 +1608,7 @@ "On-Screen Displays": "Visualizzazione A Schermo" }, "On-screen Displays": { - "On-screen Displays": "" + "On-screen Displays": "Visualizzazione a Schermo" }, "Only adjust gamma based on time or location rules.": { "Only adjust gamma based on time or location rules.": "Regolare gamma solo in base alle regole di tempo o di posizione." @@ -1454,6 +1631,15 @@ "Other": { "Other": "Altro" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "Area Uscita Quasi Piena" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "Panoramica" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "Sovrascrivi" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "Padding" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "Riproduci suono per eventi di sistema" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "Connesso" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "OSD Profilo Alimentazione" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "Pressione" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "Server di Stampa non disponibile" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "Stampanti" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "Indicatore Privacy" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "Processo" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "Immagine profilo troppo grande. Per favore usa un'immagine più piccola" }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "Accesso veloce al launcher applicazioni" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "Possibili Piogge" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "Motivo" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "Richiedi conferma alle azioni di spegnimento, riavvio, sospensione, hibernazione e logout" }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "Richiede compositor DWL" }, @@ -1722,11 +1935,14 @@ "Save Notepad File": "Salva File Notepad" }, "Save password": { - "Save password": "" + "Save password": "Salva password" }, "Saved": { "Saved": "Salvato" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "Scala indipendentemente le dimensioni dei font della DankBar" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "Scansiona" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "Scienza" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "Cerca plugins..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "Cerca..." }, "Searching...": { "Searching...": "Cercando..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "Seleziona Logo Launcher" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "Seleziona un widget da aggiungere a " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "Seleziona un'immagine" }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "Separatore" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "Imposta sfondi differenti per ogni monitor connesso" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "Mostra Log Out" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "Mostra Azioni Alimentazione" }, @@ -1881,10 +2118,10 @@ "Show on-screen display when caps lock state changes": "Visualizza un messaggio a schermo quando lo stato del maiuscolo cambia" }, "Show on-screen display when idle inhibitor state changes": { - "Show on-screen display when idle inhibitor state changes": "" + "Show on-screen display when idle inhibitor state changes": "Mostra visualizzazione a schermo quando cambia lo stato dell'inibitore di inattività" }, "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "" + "Show on-screen display when media player volume changes": "Mostra visualizzazione a schermo quando cambia il volume del lettore multimediale" }, "Show on-screen display when microphone is muted/unmuted": { "Show on-screen display when microphone is muted/unmuted": "Visualizza un messaggio a schermo quando il microfono è mutato/aperto" @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "Spegni" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "Dimensione" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "Spaziatura" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "Area Spool Piena" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "Inizia a scrivere i tuoi appunti qui..." }, + "State": { + "State": "" + }, "Status": { "Status": "Stato" }, @@ -2109,7 +2358,10 @@ "Toggle top bar visibility manually (can be controlled via IPC)": "Cambia manualmente visibiltà barra superiore (può essere controllata via IPC)" }, "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "" + "Toggle visibility of this bar configuration": "Attiva/disattiva la visibilità di questa configurazione della barra" + }, + "Toggling...": { + "Toggling...": "" }, "Tomorrow": { "Tomorrow": "Domani" @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "Spegni monitors dopo" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "Disinstalla Plugin" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "Sblocca da Dock" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "Connessioni VPN" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "Stato VPN e connessione veloce" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "Volume, luminosità, e altri OSD di sistema" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "Sfondo" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Quando abilitato, le applicazioni sono ordinate alfabeticamente. Quando disabilitato, le applicazioni sono ordinate per frequenza d'uso" }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "WiFi disabilitato" }, @@ -2301,19 +2583,22 @@ "WiFi is off": "WiFi spento" }, "Widget Background Color": { - "Widget Background Color": "" + "Widget Background Color": "Colore Sfondo Widget" }, "Widget Management": { "Widget Management": "Gestione Widget" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { - "Widget Style": "" + "Widget Style": "Stile Widget" }, "Widget Styling": { "Widget Styling": "Widget Styling" }, "Widget Transparency": { - "Widget Transparency": "" + "Widget Transparency": "Trasparenza Widget" }, "Widgets": { "Widgets": "Widgets" @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "Switcher Workspace" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "Ci sono modifiche non salvate. Salvare prima di chiudere questa tab?" }, @@ -2349,10 +2637,10 @@ "You have unsaved changes. Save before opening a file?": "Ci sono modifiche non salvate. Salvare prima di aprire un file?" }, "custom theme file browser title": { - "Select Custom Theme": "" + "Select Custom Theme": "Seleziona Tema Personalizzato" }, "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title": { - "Select Wallpaper": "" + "Select Wallpaper": "Seleziona Sfondo" }, "events": { "events": "eventi" @@ -2367,19 +2655,19 @@ "official": "ufficiale" }, "profile image file browser title": { - "Select Profile Image": "" + "Select Profile Image": "Seleziona Immagine Profilo" }, "settings window title": { - "Settings": "" + "Settings": "Impostazioni" }, "sysmon window title": { - "System Monitor": "" + "System Monitor": "Monitor Sistema" }, "update dms for NM integration.": { "update dms for NM integration.": "aggiorna dms per integrazione NM" }, "wallpaper directory file browser title": { - "Select Wallpaper Directory": "" + "Select Wallpaper Directory": "Seleziona Cartella Sfondo" }, "• Install only from trusted sources": { "• Install only from trusted sources": "• Installa solo da sorgenti fidate" diff --git a/quickshell/translations/poexports/ja.json b/quickshell/translations/poexports/ja.json index 3f58ab6e..9d401061 100644 --- a/quickshell/translations/poexports/ja.json +++ b/quickshell/translations/poexports/ja.json @@ -1,12 +1,18 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1 文字" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { - "%1 display(s)": "" + "%1 display(s)": "%1 表示" }, "%1 widgets": { - "%1 widgets": "" + "%1 widgets": "%1 ウィジェット" }, "(Unnamed)": { "(Unnamed)": "(名前なし)" @@ -50,11 +56,26 @@ "Actions": { "Actions": "アクション" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "追加" }, "Add Bar": { - "Add Bar": "" + "Add Bar": "バーを作る" }, "Add Widget": { "Add Widget": "ウィジェットを追加" @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "ウィジェットを追加 " }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "NetworkManagerでVPNを追加" }, @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "アニメーション速度" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "匿名 ID (オプション)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "システムを一時停止してもよろしいですか?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "オーディオコーデック" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "オーディオ出力デバイス(" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "認証" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "認証が必要です" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "サービスを許可 " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "自動位置検出" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "自動保存中..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "自動接続が無効" }, @@ -224,23 +269,32 @@ "Available Layouts": { "Available Layouts": "利用可能なレイアウト" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "利用可能なプラグイン" }, "Available Screens (": { "Available Screens (": "利用可能なスクリーン(" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "戻る" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "アクセントに焦点を絞ったバランスの取れたパレット(デフォルト)。" }, "Bar Configurations": { - "Bar Configurations": "" + "Bar Configurations": "バーの設定" }, "Bar Transparency": { - "Bar Transparency": "" + "Bar Transparency": "バーの透明度" }, "Battery": { "Battery": "バッテリー" @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "ロック画面をloginctlからのdbus信号にバインド。外部ロック画面を使用している場合は無効に" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "Bluetoothアイコン" }, @@ -341,17 +398,23 @@ "Center Tiling": { "Center Tiling": "中央タイルリング" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { - "Change bar appearance": "" + "Change bar appearance": "バーの見た目を変更" }, "Changes:": { "Changes:": "変更:" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "システムアップデートを検査" }, "Choose Color": { - "Choose Color": "" + "Choose Color": "色を選んでください" }, "Choose Launcher Logo Color": { "Choose Launcher Logo Color": "ランチャーロゴの色を選ぶ" @@ -360,7 +423,7 @@ "Choose icon": "アイコンを選ぶ" }, "Choose the background color for widgets": { - "Choose the background color for widgets": "" + "Choose the background color for widgets": "ウィジェットの背景色を選んでください" }, "Choose the border accent color": { "Choose the border accent color": "ボーダーの強調色を選ぶ" @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "Dank Barのランチャーボタンに表示されるロゴを選ぶ" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "通知ポップアップが画面に表示される場所を選ぶ" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "OSDの表示する場所を選んでください" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "クリア" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "すべての履歴をクリアしますか?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "クリップボード履歴" }, @@ -399,7 +471,7 @@ "Close": "閉じる" }, "Close Overview on Launch": { - "Close Overview on Launch": "" + "Close Overview on Launch": "起動中のときに概要を閉じる" }, "Color Override": { "Color Override": "色のオーバーライド" @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "Wi-Fiに接続" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "接続されたディスプレイ" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: クリア • Shift+Del: すべてクリア • 1-9: アクション • F10: ヘルプ • Esc: 閉じる" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "下にある画像に密接に一致する色を導き出します。" }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "切断" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "WiFiから切断されました" }, @@ -654,7 +738,7 @@ "Dismiss": "解除" }, "Display Assignment": { - "Display Assignment": "" + "Display Assignment": "表示割り当て" }, "Display Name Format": { "Display Name Format": "名称形式を表示" @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "現在フォーカスされているアプリケーションのタイトルを表示" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "電源メニューのアクションをリストではなくグリッドに表示" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "ウィジェットをドラッグしてセクション内で順序を変更できます。目のアイコンでウィジェットを表示/非表示に(スペースは維持)、Xで完全に削除できます。" }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "ぼかしで壁紙を複製" }, @@ -738,7 +828,7 @@ "Enable Autoconnect": "自動接続を有効" }, "Enable Bar": { - "Enable Bar": "" + "Enable Bar": "バーを起用" }, "Enable GPU Temperature": { "Enable GPU Temperature": "GPU温度を有効にする" @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "ここでパスキーを入力してください " }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "エラー" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "排他ゾーンオフセット" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: 切り替え • F10: ヘルプ" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "設定が適用できませんでした" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "接続ができませんでした " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "VPNへの切断が失敗しました" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "WiFiを有効化にできませんでした" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "プリンターの一時中断に失敗しました" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "接続ができませんでした " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "自動接続の更新が失敗しました" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "端末アプリで常に暗い配色を強制使用" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "デバイスを忘れる" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "フォーマット凡例" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "娯楽" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "ゴスコーナーズ" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "グラフィック" }, @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "ソースの色相を保持する忠実度の高いパレット。" }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "時間" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "わかりました" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "アイコンサイズ" }, @@ -1022,6 +1163,12 @@ "Image": { "Image": "画像" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "トランジションを含める" }, @@ -1035,7 +1182,7 @@ "Individual Batteries": "バッテリーごと" }, "Individual bar configuration": { - "Individual bar configuration": "" + "Individual bar configuration": "バーの個別設定" }, "Inhibit idle timeout when audio or video is playing": { "Inhibit idle timeout when audio or video is playing": "オーディオまたはビデオの再生中のアイドルタイムアウトを禁止" @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "DMSプラグインレジストリからプラグインをインストールする" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "インターロックオープン" }, @@ -1065,13 +1215,13 @@ "Jobs: ": "ジョブ: " }, "Keep Awake": { - "Keep Awake": "" + "Keep Awake": "活動状態を維持" }, "Keep Changes": { "Keep Changes": "変更を保持" }, "Keeping Awake": { - "Keeping Awake": "" + "Keeping Awake": "活動状態を維持" }, "Keyboard Layout Name": { "Keyboard Layout Name": "キーボードレイアウト名" @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "プラグインを読み込んでいます..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "ロケーション検索" }, @@ -1160,11 +1313,17 @@ "Low Priority": { "Low Priority": "低優先度" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "DMS 機能を拡張するためのプラグインを管理および構成" }, "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "" + "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "最大4つの独立したバー構成を管理できます。各バーには独自の位置、ウィジェット、スタイリング、表示割り当てがあります。" }, "Manual Coordinates": { "Manual Coordinates": "手動座標" @@ -1230,7 +1389,7 @@ "Media Players (": "メディアプレーヤー(" }, "Media Volume OSD": { - "Media Volume OSD": "" + "Media Volume OSD": "メディア音量OSD" }, "Memory": { "Memory": "メモリ" @@ -1248,7 +1407,7 @@ "Microphone Mute OSD": "マイクミュートOSD" }, "Middle Section": { - "Middle Section": "" + "Middle Section": "中間区間" }, "Minimal palette built around a single hue.": { "Minimal palette built around a single hue.": "単一の色相を中心に構築された最小限のパレット。" @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "分" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "モード:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "ネットワーク速度モニター" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "ネットワークのダウンロードおよびアップロード速度を表示" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "夜間の温度" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "アクティブプレイヤーなし" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "メディアなし" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "VPNプロファイルが見つかりませんでした" }, "No Weather Data Available": { "No Weather Data Available": "気象データはありません" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "クリップボードのエントリが見つかりませんでした" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "通常の優先度" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "メモ帳" }, @@ -1454,6 +1631,15 @@ "Other": { "Other": "他" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "アウトプットエリアがほぼ満杯" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "概要" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "上書き" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "パディング" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "システムイベントが発生したときにサウンドを再生" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "接続" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "電源プロファイルOSD" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "プレッシャー" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "プリントサーバーが利用できません" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "プリンター" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "プライバシーインジケーター" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "プロセス" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "プロフィール画像が大きすぎます。より小さい画像を使用してください。" }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "アプリケーションランチャーへのクイックアクセス" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "降水確率" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "原因" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "電源オフ、再起動、一時停止、休止状態、ログアウトアクションの確認を要求" }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "DWLコンポジターが必要" }, @@ -1722,11 +1935,14 @@ "Save Notepad File": "メモ帳ファイルを保存" }, "Save password": { - "Save password": "" + "Save password": "パスワードを保存" }, "Saved": { "Saved": "保存されました" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "Dank Barのフォントサイズを個別に調整" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "スキャン" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "科学" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "プラグインを検索..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "検索..." }, "Searching...": { "Searching...": "検索中..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "ランチャーロゴを選ぶ" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "追加するウィジェットを選ぶ " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "画像ファイルを選ぶ..." }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "区切り" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "接続されているモニターごとに異なる壁紙を設定する" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "ログアウトを表示" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "電源アクションを表示" }, @@ -1884,7 +2121,7 @@ "Show on-screen display when idle inhibitor state changes": "アイドルインヒビターの状態が変化した時にOSDを表示" }, "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "" + "Show on-screen display when media player volume changes": "メディアプレーヤーの音量が変化したときにOSDを表示" }, "Show on-screen display when microphone is muted/unmuted": { "Show on-screen display when microphone is muted/unmuted": "マイクがミュート/ミュート解除された時にOSDを表示" @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "シャットダウン" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "サイズ" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "間隔" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "スプールエリアがいっぱい" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "ここでメモを入力しましょう..." }, + "State": { + "State": "" + }, "Status": { "Status": "状態" }, @@ -2109,7 +2358,10 @@ "Toggle top bar visibility manually (can be controlled via IPC)": "トップバーの表示を手動で切り替える(IPC 経由で制御可能)" }, "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "" + "Toggle visibility of this bar configuration": "このバー構成の可視性を切り替える" + }, + "Toggling...": { + "Toggling...": "" }, "Tomorrow": { "Tomorrow": "明日" @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "後にモニターの電源を切る" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "プラグインをアンインストール" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "ドックから固定を解除" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "VPN接続" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "VPNステータスとクイック接続" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "音量、明るさ、その他のシステム OSD" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "壁紙" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "有効にすると、アプリはアルファベット順に並べ替えられます。無効にすると、アプリは使用頻度で並べ替えられます。" }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "WiFiを無効化にしました" }, @@ -2301,19 +2583,22 @@ "WiFi is off": "Wi-Fiはオフ中" }, "Widget Background Color": { - "Widget Background Color": "" + "Widget Background Color": "ウィジェットの背景色" }, "Widget Management": { "Widget Management": "ウィジェット管理" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { - "Widget Style": "" + "Widget Style": "ウィジェットのスタイル" }, "Widget Styling": { "Widget Styling": "ウィジェットのスタイル" }, "Widget Transparency": { - "Widget Transparency": "" + "Widget Transparency": "ウィジェットの透明度" }, "Widgets": { "Widgets": "ウィジェット" @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "ワークスペーススイッチャー" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "保存されていない変更があります。このタブを閉じる前に保存しますか?" }, @@ -2349,10 +2637,10 @@ "You have unsaved changes. Save before opening a file?": "保存されていない変更があります。ファイルを開く前に保存しますか?" }, "custom theme file browser title": { - "Select Custom Theme": "" + "Select Custom Theme": "カスタムテーマを選んでください" }, "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title": { - "Select Wallpaper": "" + "Select Wallpaper": "壁紙を選んでください" }, "events": { "events": "イベント" @@ -2367,19 +2655,19 @@ "official": "公式" }, "profile image file browser title": { - "Select Profile Image": "" + "Select Profile Image": "プロファイル画像を選んでください" }, "settings window title": { - "Settings": "" + "Settings": "設定" }, "sysmon window title": { - "System Monitor": "" + "System Monitor": "システムモニタ" }, "update dms for NM integration.": { "update dms for NM integration.": "NM統合のためにDMSを更新します。" }, "wallpaper directory file browser title": { - "Select Wallpaper Directory": "" + "Select Wallpaper Directory": "壁紙のディレクトリを選んでください" }, "• Install only from trusted sources": { "• Install only from trusted sources": "• 信頼できるソースからのみインストールする" diff --git a/quickshell/translations/poexports/pl.json b/quickshell/translations/poexports/pl.json index 92472e37..bffdfed4 100644 --- a/quickshell/translations/poexports/pl.json +++ b/quickshell/translations/poexports/pl.json @@ -1,12 +1,18 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1 znaków" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { - "%1 display(s)": "" + "%1 display(s)": "%1 wyświetlaczy" }, "%1 widgets": { - "%1 widgets": "" + "%1 widgets": "%1 widżetów" }, "(Unnamed)": { "(Unnamed)": "(Bez nazwy)" @@ -50,11 +56,26 @@ "Actions": { "Actions": "Akcje" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "Dodaj" }, "Add Bar": { - "Add Bar": "" + "Add Bar": "Dodaj pasek" }, "Add Widget": { "Add Widget": "Dodaj widżet" @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "Dodaj widżet do" }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "Dodaj sieć VPN w NetworkManager" }, @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "Szybkość animacji" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "Tożsamość anonimowa (opcjonalnie)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "Czy na pewno chcesz uśpić komputer?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "Kodek audio" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "Urządzenia wyjściowe audio (" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "Uwierzytelnij" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "Wymagane uwierzytelnienie" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "Autoryzuj usługę dla " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "Automatyczna lokalizacja" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "Automatyczny zapis..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "Automatyczne łączenie wyłączone" }, @@ -224,23 +269,32 @@ "Available Layouts": { "Available Layouts": "Dostępne układy" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "Dostępne wtyczki" }, "Available Screens (": { "Available Screens (": "Dostępne ekrany (" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "Wstecz" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "Zrównoważona paleta ze skupionymi akcentami (domyślnie)." }, "Bar Configurations": { - "Bar Configurations": "" + "Bar Configurations": "Konfiguracje pasków" }, "Bar Transparency": { - "Bar Transparency": "" + "Bar Transparency": "Przezroczystość paska" }, "Battery": { "Battery": "Bateria" @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Powiąż ekran blokady z sygnałami dbus z loginctl. Wyłącz, jeśli używasz zewnętrznego ekranu blokady" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "Ikona Bluetooth" }, @@ -341,17 +398,23 @@ "Center Tiling": { "Center Tiling": "Płytki środkowe" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { - "Change bar appearance": "" + "Change bar appearance": "Zmień wygląd paska" }, "Changes:": { "Changes:": "Zmiany:" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "Sprawdź aktualizacje systemu" }, "Choose Color": { - "Choose Color": "" + "Choose Color": "Wybierz kolor" }, "Choose Launcher Logo Color": { "Choose Launcher Logo Color": "Wybierz kolor logo launchera" @@ -360,7 +423,7 @@ "Choose icon": "Wybierz ikonę" }, "Choose the background color for widgets": { - "Choose the background color for widgets": "" + "Choose the background color for widgets": "Wybierz kolor tła dla widżetów" }, "Choose the border accent color": { "Choose the border accent color": "Wybierz kolor akcentu obramowania" @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "Wybierz logo wyświetlane na przycisku launchera w DankBar" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "Wybierz, gdzie na ekranie mają pojawiać się powiadomienia" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "Wybierz miejsce wyświetlania informacji na ekranie" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "Wyczyść" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "Usunąć całą historię?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "Historia schowka" }, @@ -399,7 +471,7 @@ "Close": "Zamknij" }, "Close Overview on Launch": { - "Close Overview on Launch": "" + "Close Overview on Launch": "Zamknij podgląd przy uruchomieniu" }, "Color Override": { "Color Override": "Nadpisanie koloru" @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "Połącz z siecią Wi-Fi" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "Podłączone ekrany" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Wyczyść • Shift+Del: Wyczyść wszystko • 1-9: Akcje • F10: Pomoc • Esc: Zamknij" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "Uzyskuje kolory, które ściśle pasują do obrazu bazowego." }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "Rozłącz" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "Rozłączono z Wi-Fi" }, @@ -654,7 +738,7 @@ "Dismiss": "Odrzuć" }, "Display Assignment": { - "Display Assignment": "" + "Display Assignment": "Przypisanie wyświetlacza" }, "Display Name Format": { "Display Name Format": "Format nazwy wyświetlanej" @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "Wyświetlaj tytuł aktywnej aplikacji" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "Wyświetl elementy menu zasilania w siatce zamiast listy" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Przeciągnij widżety, aby zmienić kolejność w sekcjach. Użyj ikony oka, aby ukryć/pokazać widżety (zachowując odstępy), lub X, aby je całkowicie usunąć." }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "Powiel tapetę z rozmyciem" }, @@ -738,7 +828,7 @@ "Enable Autoconnect": "Włącz automatyczne łączenie" }, "Enable Bar": { - "Enable Bar": "" + "Enable Bar": "Włącz pasek" }, "Enable GPU Temperature": { "Enable GPU Temperature": "Pokaż temperaturę GPU" @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "Wprowadź ten klucz dostępu " }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "Błąd" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "Przesunięcie strefy wyłączności" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: Przełącz • F10: Pomoc" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "Nie udało się aktywować konfiguracji" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "Nie udało się połączyć z " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "Nie udało się rozłączyć z VPN" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "Nie udało się włączyć Wi-Fi" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "Wstrzymanie drukarki nie powiodło się" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "Nie udało się rozpocząć połączenia z " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "Nie udało się zaktualizować automatycznego łączenia" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "Wymuś ciemny motyw na aplikacjach terminala" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "Zapomnij urządzenie" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "Legenda formatowania" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "Zabawa" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "Gotyckie narożniki" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "Grafika" }, @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "Wysokiej jakości paleta, która zachowuje źródłowe odcienie." }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "Godzina" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "Rozumiem" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "Rozmiar ikony" }, @@ -1022,6 +1163,12 @@ "Image": { "Image": "Zdjęcie" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "Uwzględnij przejścia" }, @@ -1035,7 +1182,7 @@ "Individual Batteries": "Pojedyncze akumulatory" }, "Individual bar configuration": { - "Individual bar configuration": "" + "Individual bar configuration": "Indywidualna konfiguracja paska" }, "Inhibit idle timeout when audio or video is playing": { "Inhibit idle timeout when audio or video is playing": "Blokuj limit czasu bezczynności podczas odtwarzania dźwięku lub obrazu" @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "Instaluj wtyczki z rejestru wtyczek DMS" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "Blokada otwarta" }, @@ -1065,13 +1215,13 @@ "Jobs: ": "Zadania: " }, "Keep Awake": { - "Keep Awake": "" + "Keep Awake": "Utrzymuj aktywność" }, "Keep Changes": { "Keep Changes": "Zachowaj zmiany" }, "Keeping Awake": { - "Keeping Awake": "" + "Keeping Awake": "Utrzymywanie aktywności" }, "Keyboard Layout Name": { "Keyboard Layout Name": "Nazwa układu klawiatury" @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "Ładowanie wtyczek..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "Wyszukiwanie lokalizacji" }, @@ -1160,11 +1313,17 @@ "Low Priority": { "Low Priority": "Niski priorytet" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "Zarządzaj i konfiguruj wtyczki rozszerzające funkcjonalność DMS" }, "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "" + "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "Zarządzaj maksymalnie 4 niezależnymi konfiguracjami pasków. Każdy pasek ma własną pozycję, widżety, styl i przypisanie do wyświetlacza." }, "Manual Coordinates": { "Manual Coordinates": "Ręczne współrzędne" @@ -1230,7 +1389,7 @@ "Media Players (": "Odtwarzacze multimediów (" }, "Media Volume OSD": { - "Media Volume OSD": "" + "Media Volume OSD": "OSD głośności multimediów" }, "Memory": { "Memory": "Pamięć" @@ -1248,7 +1407,7 @@ "Microphone Mute OSD": "OSD Wyciszenia Mikrofonu" }, "Middle Section": { - "Middle Section": "" + "Middle Section": "Sekcja środkowa" }, "Minimal palette built around a single hue.": { "Minimal palette built around a single hue.": "Minimalna paleta zbudowana wokół jednego odcienia." @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "Minuta" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "Tryb:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "Monitor prędkości sieci" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "Wyświetlanie prędkości pobierania i wysyłania sieci" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "Temperatura w nocy" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "Brak aktywnych odtwarzaczy" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "Brak mediów" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "Nie znaleziono profili VPN" }, "No Weather Data Available": { "No Weather Data Available": "Brak danych pogodowych" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "Nie znaleziono wpisów w schowku" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "Normalny priorytet" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "Notatnik" }, @@ -1454,6 +1631,15 @@ "Other": { "Other": "Inne" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "Obszar wyjściowy prawie pełny" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "Podgląd" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "Nadpisz" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "Dopełnienie" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "Odtwarzaj dźwięki zdarzeń systemowych" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "Podłączony" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "OSD Profilu Zasilania" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "Ciśnienie" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "Serwer wydruku niedostępny" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "Drukarki" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "Wskaźnik prywatności" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "Proces" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "Zdjęcie profilowe jest za duże. Użyj mniejszego zdjęcia." }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "Szybki dostęp do uruchamiania aplikacji" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "Szansa na deszcz" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "Powód" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "Poproś o potwierdzenie czynności wyłączenia, ponownego uruchomienia, zawieszenia, hibernacji i wylogowania." }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "Wymaga kompozytora DWL" }, @@ -1722,11 +1935,14 @@ "Save Notepad File": "Zapisz plik notatnika" }, "Save password": { - "Save password": "" + "Save password": "Zapisz hasło" }, "Saved": { "Saved": "Zapisano" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "Skaluj rozmiary czcionek DankBar niezależnie" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "Skanuj" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "Nauka" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "Szukaj wtyczek..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "Szukaj..." }, "Searching...": { "Searching...": "Wyszukiwanie..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "Wybierz logo launchera" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "Wybierz widżet do dodania do " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "Wybierz plik obrazu..." }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "Separator" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "Ustaw różne tapety dla każdego podłączonego monitora" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "Pokaż wylogowanie" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "Pokaż akcje zasilania" }, @@ -1884,7 +2121,7 @@ "Show on-screen display when idle inhibitor state changes": "Wyświetlaj powiadomienie ekranowe przy zmianie stanu inhibitora bezczynności" }, "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "" + "Show on-screen display when media player volume changes": "Pokaż OSD przy zmianie głośności multimediów" }, "Show on-screen display when microphone is muted/unmuted": { "Show on-screen display when microphone is muted/unmuted": "Wyświetlaj powiadomienie ekranowe przy wyciszaniu/włączaniu mikrofonu" @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "Wyłączenie" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "Rozmiar" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "Odstępy" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "Obszar buforowania pełny" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "Zacznij pisać swoje notatki tutaj..." }, + "State": { + "State": "" + }, "Status": { "Status": "Status" }, @@ -2109,7 +2358,10 @@ "Toggle top bar visibility manually (can be controlled via IPC)": "Ręczne przełączanie widoczności górnego paska (można kontrolować przez IPC)" }, "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "" + "Toggle visibility of this bar configuration": "Przełącz widoczność tej konfiguracji paska" + }, + "Toggling...": { + "Toggling...": "" }, "Tomorrow": { "Tomorrow": "Jutro" @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "Wyłącz monitory po" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "Odinstaluj wtyczkę" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "Odepnij z doku" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "Połączenia VPN" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "Status VPN i szybkie połączenie" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "Głośność, jasność i inne systemowe menu ekranowe" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "Tapeta" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Po włączeniu aplikacje są sortowane alfabetycznie. Po wyłączeniu aplikacje są sortowane według częstotliwości użytkowania." }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "WiFi wyłączone" }, @@ -2301,19 +2583,22 @@ "WiFi is off": "WiFi jest wyłączone" }, "Widget Background Color": { - "Widget Background Color": "" + "Widget Background Color": "Kolor tła widżetu" }, "Widget Management": { "Widget Management": "Zarządzanie widżetami" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { - "Widget Style": "" + "Widget Style": "Styl widżetu" }, "Widget Styling": { "Widget Styling": "Stylizacja widżetów" }, "Widget Transparency": { - "Widget Transparency": "" + "Widget Transparency": "Przezroczystość widżetu" }, "Widgets": { "Widgets": "Widżety" @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "Przełącznik obszarów roboczych" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "Masz niezapisane zmiany. Zapisać przed zamknięciem tej karty?" }, @@ -2349,10 +2637,10 @@ "You have unsaved changes. Save before opening a file?": "Masz niezapisane zmiany. Zapisać przed otwarciem pliku?" }, "custom theme file browser title": { - "Select Custom Theme": "" + "Select Custom Theme": "Wybierz niestandardowy motyw" }, "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title": { - "Select Wallpaper": "" + "Select Wallpaper": "Wybierz tapetę" }, "events": { "events": "wydarzenia" @@ -2367,19 +2655,19 @@ "official": "oficjalny" }, "profile image file browser title": { - "Select Profile Image": "" + "Select Profile Image": "Wybierz obraz profilowy" }, "settings window title": { - "Settings": "" + "Settings": "Ustawienia" }, "sysmon window title": { - "System Monitor": "" + "System Monitor": "Monitor systemu" }, "update dms for NM integration.": { "update dms for NM integration.": "zaktualizuj dms dla integracji z NM." }, "wallpaper directory file browser title": { - "Select Wallpaper Directory": "" + "Select Wallpaper Directory": "Wybierz katalog z tapetami" }, "• Install only from trusted sources": { "• Install only from trusted sources": "• Instaluj tylko z zaufanych źródeł" diff --git a/quickshell/translations/poexports/pt.json b/quickshell/translations/poexports/pt.json index 05821f4e..d68497ae 100644 --- a/quickshell/translations/poexports/pt.json +++ b/quickshell/translations/poexports/pt.json @@ -1,7 +1,13 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1 caracteres" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { "%1 display(s)": "" }, @@ -50,6 +56,21 @@ "Actions": { "Actions": "Ações" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "Adicionar" }, @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "Adicionar Widget para " }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "Adicionar um VPN ao NetworkManager" }, @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "Velocidade de Animação" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "Identidade Anônima (opcional)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "Você tem certeza que deseja suspender o sistema?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "Codec de Áudio" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "Dispositivos de Saída de Áudio (" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "Autenticar" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "Autenticação Necessária" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "Autorizar serviço para " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "Localização Automática" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "Salvando automáticamente..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "" }, @@ -224,15 +269,24 @@ "Available Layouts": { "Available Layouts": "" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "Plugins disponíveis" }, "Available Screens (": { "Available Screens (": "Telas disponíveis(" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "Voltar" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "Paleta equilibrada com destaques de cor focados (padrão)." }, @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Vincular o bloqueio de tela aos sinais do DBus do loginctl. Desative se estiver usando um bloqueio de tela externo" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "ícone do Bluetooth" }, @@ -341,12 +398,18 @@ "Center Tiling": { "Center Tiling": "" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { "Change bar appearance": "" }, "Changes:": { "Changes:": "" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "Verificar por atualizações de sistema" }, @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "Escolher a logo que será exibida no botão do Lançador no DankBar" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "Escolher onde as notificações irão aparecer na tela" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "Limpar" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "Apagar Todo o Histórico?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "Histórico da Área de Transferência" }, @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "Conectar ao Wi-Fi" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "Telas Conectadas" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Limpar • Shift+Del: Limpar Tudo • 1-9: Ações • F10: Ajuda • Esc: Fechar" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "Deriva cores que combinam de perto com a imagem de fundo." }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "Desconectar" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "Disconectado do WiFi" }, @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "Mostrar título do app em foco" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Arraste Widgets para reordená-los nas seções. Use o ícone de olho para esconder ou mostrá-los (manter o espaçamento), ou clique no X para removê-los por completo." }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "" }, @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "" }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "Ajuste da Zona Exclusiva" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: Ativar • F10: Ajuda" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "Erro ao ativar configuração" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "Erro ao conectar a " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "Erro ao desconectar VPN" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "Erro ao habilitar WiFi" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "Erro ao iniciar conexão a " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "Esquecer Dispositivo" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "Formatar Legenda" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "Diversão" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "Cantos Gotícos" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "Gráficos" }, @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "Paleta de alta fidelidade que preserva tons da fonte." }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "Hora" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "Entendi" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "Tamanho do Ícone" }, @@ -1022,6 +1163,12 @@ "Image": { "Image": "Imagem" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "Incluir Transições" }, @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "Instale plugins a partir do registro de plugins do DMS" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "" }, @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "Carregando plugins..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "Procurar Localização" }, @@ -1160,6 +1313,12 @@ "Low Priority": { "Low Priority": "Baixa Prioridade" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "Gerencia e configure plugins para extender funcionalidades do DMS" }, @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "Minuto" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "Modo:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "Monitor de Velocidade da Rede" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "Monitor de velocidades de download e upload da rede" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "Temperatura Noturna" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "Sem Tocadores Ativos" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "Sem Mídia" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "Nenhum perfil de VPN encontrado" }, "No Weather Data Available": { "No Weather Data Available": "Informações de Clima não dispóniveis" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "Área de transferência vazia" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "Prioridade Normal" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "Bloco de Nota" }, @@ -1454,6 +1631,15 @@ "Other": { "Other": "" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "Visão Geral" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "Sobrescrever" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "Preenchimento" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "Reproduzir sons para eventos do sistema" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "Conectado" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "Pressão" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "Indicador de Privacidade" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "Processo" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "A imagem de perfil é muito grande. Por favor use uma imagem menor." }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "Acesso rápido ao lançador de aplicativos" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "Chance de Chuva" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "Pedir confirmação ao desligar, reiniciar, suspender, hibernar e encerrar sessão" }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "" }, @@ -1727,6 +1940,9 @@ "Saved": { "Saved": "Salvo" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "Ajustar tamanho da fonte da DankBar de forma independente" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "Escanear" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "Ciência" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "Buscar plugins..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "Buscar..." }, "Searching...": { "Searching...": "Pesquisando..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "Selecionar Logo do Lançador" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "Selecione um widget para adicionar a " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "Selecione um arquivo de imagem..." }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "Separador" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "Use papéis de paredes diferentes para cada monitor conectado" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "Mostrar Ações de Energia" }, @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "Tamanho" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "Espaçamento" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "Comece a digitar suas anotações aqui..." }, + "State": { + "State": "" + }, "Status": { "Status": "Status" }, @@ -2111,6 +2360,9 @@ "Toggle visibility of this bar configuration": { "Toggle visibility of this bar configuration": "" }, + "Toggling...": { + "Toggling...": "" + }, "Tomorrow": { "Tomorrow": "Amanhã" }, @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "Desligar monitores depois de" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "Desinstalar Plugin" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "Desafixar do Dock" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "Conexões de VPN" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "Status de VPN e conexão rápida" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "Volume, brilho, e outros OSDs do sistema" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "Papel de parede" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Quando ativado, apps são ordenados alfabeticamente. Quando desativado, apps são ordenados por frequência de uso." }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "WiFi desativado" }, @@ -2306,6 +2588,9 @@ "Widget Management": { "Widget Management": "Gerenciamento de Widgets" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { "Widget Style": "" }, @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "Seletor de Áreas de Trabalho" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "Você tem mudanças não salvas. Salvar antes de fechar esta guia?" }, diff --git a/quickshell/translations/poexports/tr.json b/quickshell/translations/poexports/tr.json index d12ef859..a3c37d5d 100644 --- a/quickshell/translations/poexports/tr.json +++ b/quickshell/translations/poexports/tr.json @@ -1,12 +1,18 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1 karakter" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { - "%1 display(s)": "" + "%1 display(s)": "%1 ekran" }, "%1 widgets": { - "%1 widgets": "" + "%1 widgets": "%1 widget" }, "(Unnamed)": { "(Unnamed)": "(İsimsiz)" @@ -50,11 +56,26 @@ "Actions": { "Actions": "Eylemler" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "Ekle" }, "Add Bar": { - "Add Bar": "" + "Add Bar": "Bar Ekle" }, "Add Widget": { "Add Widget": "Widget Ekle" @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "Şuraya Widget ekle:" }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "NetworkManager'da VPN ekle" }, @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "Animasyon Hızı" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "Anonim Kimlik (isteğe bağlı)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "Sistemi askıya almak istediğinizden emin misiniz?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "Ses Codec'i" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "Ses Çıkış Aygıtları (" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "Kimlik Doğrula" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "Kimlik Doğrulama Gerekli" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "Şunun için servisi yetkilendir: " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "Otomatik Konum" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "Otomatik kaydetme..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "Otomatik bağlanma devre dışı" }, @@ -224,23 +269,32 @@ "Available Layouts": { "Available Layouts": "Mevcut Düzenler" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "Kullanılabilir Eklentiler" }, "Available Screens (": { "Available Screens (": "Kullanılabilir Ekranlar (" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "Geri" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "Odaklanmış vurgularla dengeli palet (varsayılan)." }, "Bar Configurations": { - "Bar Configurations": "" + "Bar Configurations": "Bar Ayarları" }, "Bar Transparency": { - "Bar Transparency": "" + "Bar Transparency": "Bar Opaklığı" }, "Battery": { "Battery": "Batarya" @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Kilit ekranını loginctl'den gelen dbus sinyallerine bağlayın. Harici bir kilit ekranı kullanıyorsanız devre dışı bırakın" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "Bluetooth Simgesi" }, @@ -341,17 +398,23 @@ "Center Tiling": { "Center Tiling": "Merkez Döşeme" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { - "Change bar appearance": "" + "Change bar appearance": "Bar görünümünü değiştir" }, "Changes:": { "Changes:": "Değişiklikler:" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "Sistem güncellemelerini kontrol et" }, "Choose Color": { - "Choose Color": "" + "Choose Color": "Renk Seç" }, "Choose Launcher Logo Color": { "Choose Launcher Logo Color": "Başlatıcı Logo Rengini Seçin" @@ -360,7 +423,7 @@ "Choose icon": "Simge seçin" }, "Choose the background color for widgets": { - "Choose the background color for widgets": "" + "Choose the background color for widgets": "Widgetlar için arkaplan rengini seç" }, "Choose the border accent color": { "Choose the border accent color": "Kenarlık vurgu rengini seç" @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "DankBar'daki başlatıcı düğmesinde görüntülenen logoyu seçin" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "Bildirim açılır pencerelerinin ekranda nerede görüneceğini seçin" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "Ekran gösterimlerinin ekranda nerede gösterileceğini seç" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "Temizle" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "Tüm Geçmişi Temizle?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "Pano Geçmişi" }, @@ -399,7 +471,7 @@ "Close": "Kapat" }, "Close Overview on Launch": { - "Close Overview on Launch": "" + "Close Overview on Launch": "Başlatmada Genel Görünümü Kapat" }, "Color Override": { "Color Override": "Renk Değiştirme" @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "Wi-Fi'ye Bağlan" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "Bağlı Ekranlar" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: Temizle • Shift+Del: Tümünü Temizle • 1-9: Eylemler • F10: Yardım • Esc: Kapat" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "Altta yatan görüntüye çok yakın renkler türetir" }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "Bağlantıyı Kes" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "WiFi bağlantısı kesildi" }, @@ -654,7 +738,7 @@ "Dismiss": "Reddet" }, "Display Assignment": { - "Display Assignment": "" + "Display Assignment": "Ekran Ataması" }, "Display Name Format": { "Display Name Format": "Ekran İsim Formatı" @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "Şu anda odaklanmış uygulamanın başlığını göster" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "Güç menüsü eylemlerini liste yerine ızgara şeklinde göster" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Widget'ları sürükleyerek bölümler içinde yeniden sıralayın. Göz simgesini kullanarak widget'ları gizleyin/gösterin (aralıkları korur) veya X simgesini kullanarak tamamen kaldırın." }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "Duvar kağıdını bulanıklık ile çoğalt" }, @@ -738,7 +828,7 @@ "Enable Autoconnect": "Otomatik Bağlanmayı Etkinleştir" }, "Enable Bar": { - "Enable Bar": "" + "Enable Bar": "Barı Etkinleştir" }, "Enable GPU Temperature": { "Enable GPU Temperature": "GPU Sıcaklığını Etkinleştir" @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "Bu şifreyi şuraya gir: " }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "Hata" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "Özel Bölge Ofseti" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: Değiştir • F10: Yardım" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "Yapılandırma etkinleştirilemedi" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "Bağlanılamadı " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "VPN bağlantısı kesilemedi" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "WiFi etkinleştirilemedi" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "Yazıcıyı duraklatma başarısız" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "Bağlantı başlatılamadı " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "Otomatik bağlanma güncellenemedi" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "Terminal uygulamalarının her zaman koyu renk şemalarını kullanmasını zorla" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "Aygıtı Unut" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "Biçim Açıklaması" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "Eğlence" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "Gotik Köşeler" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "Grafik" }, @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "Kaynak tonları koruyan yüksek sadakatli palet" }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "Saat" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "Anladım" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "Simge Boyutu" }, @@ -1022,6 +1163,12 @@ "Image": { "Image": "Resim" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "Geçişleri Dahil Et" }, @@ -1035,7 +1182,7 @@ "Individual Batteries": "Tekil Piller" }, "Individual bar configuration": { - "Individual bar configuration": "" + "Individual bar configuration": "Bireysel bar yapılandırması" }, "Inhibit idle timeout when audio or video is playing": { "Inhibit idle timeout when audio or video is playing": "Ses veya video oynatılırken boşta kalma süresini engelle" @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "DMS eklenti deposundan eklentiler yükle" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "Kilit Açık" }, @@ -1065,13 +1215,13 @@ "Jobs: ": "İşler:" }, "Keep Awake": { - "Keep Awake": "" + "Keep Awake": "Uyanık Tut" }, "Keep Changes": { "Keep Changes": "Değişiklikleri Tut" }, "Keeping Awake": { - "Keeping Awake": "" + "Keeping Awake": "Uyanık Tutuluyor" }, "Keyboard Layout Name": { "Keyboard Layout Name": "Klavye Düzeni Adı" @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "Eklentiler yükleniyor..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "Konum Arama" }, @@ -1160,11 +1313,17 @@ "Low Priority": { "Low Priority": "Düşük Öncelik" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "DMS işlevselliğini genişletmek için eklentileri yönetin ve yapılandırın" }, "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "" + "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "4 adede kadar bağımsız bar yapılandırmasını yönetin. Her barın kendi konumu, widget'ları, stili ve ekran ataması vardır." }, "Manual Coordinates": { "Manual Coordinates": "Manuel Koordinatlar" @@ -1230,7 +1389,7 @@ "Media Players (": "Medya Oynatıcıları (" }, "Media Volume OSD": { - "Media Volume OSD": "" + "Media Volume OSD": "Medya Ses OSD" }, "Memory": { "Memory": "Bellek" @@ -1248,7 +1407,7 @@ "Microphone Mute OSD": "Mikrofon Sessiz OSD" }, "Middle Section": { - "Middle Section": "" + "Middle Section": "Orta Bölüm" }, "Minimal palette built around a single hue.": { "Minimal palette built around a single hue.": "Tek bir renk tonu etrafında oluşturulmuş minimal palet." @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "Dakika" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "Mod:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "Ağ Hız Monitörü" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "Ağ indirme ve yükleme hız gösterimi" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "Gece Sıcaklığı" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "Aktif Oynatıcı Yok" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "Medya Yok" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "VPN profilleri bulunamadı" }, "No Weather Data Available": { "No Weather Data Available": "Hava Durumu Verileri Mevcut Değil" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "Pano girişleri bulunamadı" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "Normal Öncelik" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "Not Defteri" }, @@ -1454,6 +1631,15 @@ "Other": { "Other": "Diğer" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "Çıkış Alanı Neredeyse Dolu" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "Genel Görünüm" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "Üstüne Yaz" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "Dolgu" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "Sistem etkinlikleri için ses çal" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "Bağlandı" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "Güç Profili OSD" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "Basınç" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "Yazıcı Sunucusu Kullanılamıyor" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "Yazıcılar" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "Gizlilik Göstergesi" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "Süreç" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "Profil resmi çok büyük. Lütfen daha küçük bir resim kullanın." }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "Uygulama başlatıcısına hızlı erişim" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "Yağış İhtimali" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "Sebep" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "Kapatma, yeniden başlatma, askıya alma, hazırda bekletme ve oturumu kapatma işlemlerinde onay iste" }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "DWL kompozitör gerektirir" }, @@ -1722,11 +1935,14 @@ "Save Notepad File": "Not Defteri Dosyasını Kaydet" }, "Save password": { - "Save password": "" + "Save password": "Parolayı kaydet" }, "Saved": { "Saved": "Kaydedildi" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "DankBar yazı tipi boyutlarını bağımsız olarak ölçeklendir" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "Tara" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "Bilim" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "Eklentileri ara..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "Ara..." }, "Searching...": { "Searching...": "Arıyor..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "Başlatıcı Logosu Seç" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "Eklemek için widget seçin: " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "Bir resim dosyası seçin..." }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "Ayraç" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "Bağlı her monitör için farklı duvar kağıtları ayarlayın" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "Çıkışı Göster" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "Güç Eylemlerini Göster" }, @@ -1884,7 +2121,7 @@ "Show on-screen display when idle inhibitor state changes": "Boşta kalma engelleyici durumu değiştiğinde ekran gösterimi göster" }, "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "" + "Show on-screen display when media player volume changes": "Medya oynatıcının ses seviyesi değiştiğinde ekran üstü görüntü göster" }, "Show on-screen display when microphone is muted/unmuted": { "Show on-screen display when microphone is muted/unmuted": "Mikrofon sessize alındığında/sessizden çıkarıldığında ekran gösterimi göster" @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "Kapat" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "Boyut" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "Boşluk" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "Aktarım Alanı Dolu" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "Notunuzu buraya yazmaya başlayın..." }, + "State": { + "State": "" + }, "Status": { "Status": "Durum" }, @@ -2109,7 +2358,10 @@ "Toggle top bar visibility manually (can be controlled via IPC)": "Üst çubuğun görünürlüğünü manuel olarak değiştirin (IPC ile kontrol edilebilir)" }, "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "" + "Toggle visibility of this bar configuration": "Bu bar yapılandırmasının görünürlüğünü değiştir" + }, + "Toggling...": { + "Toggling...": "" }, "Tomorrow": { "Tomorrow": "Yarın" @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "Şu zaman sonra monitörleri kapat" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "Eklentiyi Kaldır" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "Dock'tan Sabitlemeyi Kaldır" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "VPN Bağlantıları" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "VPN durumu ve hızlı bağlanma" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "Ses, parlaklık ve diğer sistem ekran üstü gösterimleri" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "Duvar Kağıdı" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "Etkinleştirildiğinde, uygulamalar alfabetik olarak sıralanır. Devre dışı bırakıldığında, uygulamalar kullanım sıklığına göre sıralanır." }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "WiFi devre dışı" }, @@ -2301,19 +2583,22 @@ "WiFi is off": "WiFi kapalı" }, "Widget Background Color": { - "Widget Background Color": "" + "Widget Background Color": "Widget Arkaplan Rengi" }, "Widget Management": { "Widget Management": "Widget Yönetimi" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { - "Widget Style": "" + "Widget Style": "Widget Stili" }, "Widget Styling": { "Widget Styling": "Widget Stili" }, "Widget Transparency": { - "Widget Transparency": "" + "Widget Transparency": "Widget Opaklığı" }, "Widgets": { "Widgets": "Widgetlar" @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "Çalışma Alanı Değiştirici" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "Kaydedilmemiş değişiklikleriniz var. Sekmeyi kapatmadan önce kaydedelim mi?" }, @@ -2349,10 +2637,10 @@ "You have unsaved changes. Save before opening a file?": "Kaydedilmemiş değişiklikleriniz var. Yeni dosya açmadan önce kaydedelim mi?" }, "custom theme file browser title": { - "Select Custom Theme": "" + "Select Custom Theme": "Özel Tema Seç" }, "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title": { - "Select Wallpaper": "" + "Select Wallpaper": "Duvar Kağıdı Seç" }, "events": { "events": "etkinlikler" @@ -2367,19 +2655,19 @@ "official": "resmi" }, "profile image file browser title": { - "Select Profile Image": "" + "Select Profile Image": "Profil Resmi Seç" }, "settings window title": { - "Settings": "" + "Settings": "Ayarlar" }, "sysmon window title": { - "System Monitor": "" + "System Monitor": "Sistem Monitörü" }, "update dms for NM integration.": { "update dms for NM integration.": "NM entegrasyonu için dms'yi güncelle" }, "wallpaper directory file browser title": { - "Select Wallpaper Directory": "" + "Select Wallpaper Directory": "Duvar Kağıdı Dizinini Seç" }, "• Install only from trusted sources": { "• Install only from trusted sources": "• Yalnızca güvenilir kaynaklardan yükle" diff --git a/quickshell/translations/poexports/zh_CN.json b/quickshell/translations/poexports/zh_CN.json index 7494bb28..5d3aacd0 100644 --- a/quickshell/translations/poexports/zh_CN.json +++ b/quickshell/translations/poexports/zh_CN.json @@ -1,12 +1,18 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1个字符" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { - "%1 display(s)": "" + "%1 display(s)": "%1 显示" }, "%1 widgets": { - "%1 widgets": "" + "%1 widgets": "%1 小挂件" }, "(Unnamed)": { "(Unnamed)": "(未命名)" @@ -50,11 +56,26 @@ "Actions": { "Actions": "操作" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "添加" }, "Add Bar": { - "Add Bar": "" + "Add Bar": "添加状态栏" }, "Add Widget": { "Add Widget": "添加小组件" @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "添加小组件到" }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "在 NetworkManager 中添加 VPN" }, @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "动画速度" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "匿名身份(可选)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "你确定要挂起系统吗?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "音频编解码器" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "音频输出设备 (" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "认证" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "需要认证" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "授权服务 " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "自动定位" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "自动保存中..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "已禁用自动连接" }, @@ -224,23 +269,32 @@ "Available Layouts": { "Available Layouts": "可用布局" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "可用插件" }, "Available Screens (": { "Available Screens (": "可用显示器 (" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "返回" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "均衡配色,强调重点(默认)" }, "Bar Configurations": { - "Bar Configurations": "" + "Bar Configurations": "Bar状态栏" }, "Bar Transparency": { - "Bar Transparency": "" + "Bar Transparency": "状态栏透明度" }, "Battery": { "Battery": "电池" @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "将锁屏绑定到来自 loginctl 的 dbus 信号。如使用外部锁屏程序,请禁用此项" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "蓝牙图标" }, @@ -341,17 +398,23 @@ "Center Tiling": { "Center Tiling": "中心平铺" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { - "Change bar appearance": "" + "Change bar appearance": "更改状态栏外观" }, "Changes:": { "Changes:": "更改:" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "检查系统更新" }, "Choose Color": { - "Choose Color": "" + "Choose Color": "选择颜色" }, "Choose Launcher Logo Color": { "Choose Launcher Logo Color": "设置启动器 Logo 颜色" @@ -360,7 +423,7 @@ "Choose icon": "选择图标" }, "Choose the background color for widgets": { - "Choose the background color for widgets": "" + "Choose the background color for widgets": "选择小组件背景色" }, "Choose the border accent color": { "Choose the border accent color": "选择边框强调色" @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "选择在 Dank Bar 启动器按钮上显示的 Logo" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "设置通知弹窗的出现位置" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "选择OSD在屏幕上出现的位置" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "清除" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "清空历史记录?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "剪切板历史记录" }, @@ -399,7 +471,7 @@ "Close": "关闭" }, "Close Overview on Launch": { - "Close Overview on Launch": "" + "Close Overview on Launch": "在启动时关闭概览" }, "Color Override": { "Color Override": "覆盖颜色" @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "连接到Wi-Fi" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "已连接显示器" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: 清除 • Shift+Del: 清空 • 1-9: 操作 • F10: 帮助 • Esc: 关闭" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "提取与壁纸高度匹配的颜色。" }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "断开连接" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "Wi-Fi 已断开" }, @@ -654,7 +738,7 @@ "Dismiss": "忽略" }, "Display Assignment": { - "Display Assignment": "" + "Display Assignment": "显示布局" }, "Display Name Format": { "Display Name Format": "显示名称格式" @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "显示当前聚焦应用的标题" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "通过网格而非列表显示电源菜单" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖动组件以在各区块内重新排序。点击眼睛图标可隐藏/显示组件(保留间距),点击 X 可彻底移除。" }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "带模糊效果的壁纸复本" }, @@ -738,7 +828,7 @@ "Enable Autoconnect": "启用自动连接" }, "Enable Bar": { - "Enable Bar": "" + "Enable Bar": "启用状态栏" }, "Enable GPU Temperature": { "Enable GPU Temperature": "显示 GPU 温度" @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "在该处输入此通行密钥 " }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "错误" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "独占区域偏移量" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: 切换 • F10: 帮助" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "无法应用配置" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "无法连接至 " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "断开 VPN 失败" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "无法启用 Wi-Fi" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "无法暂停打印机" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "无法启动连接至 " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "无法更新自动连接" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "强制终端应用使用暗色" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "取消配对" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "参考格式" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "娱乐" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "哥特风格圆角" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "图形" }, @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "高保真配色,保留原始色调。" }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "小时" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "我明白以上内容" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "图标大小" }, @@ -1022,6 +1163,12 @@ "Image": { "Image": "图像" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "包含过渡效果" }, @@ -1035,7 +1182,7 @@ "Individual Batteries": "分别显示电池" }, "Individual bar configuration": { - "Individual bar configuration": "" + "Individual bar configuration": "单栏配置" }, "Inhibit idle timeout when audio or video is playing": { "Inhibit idle timeout when audio or video is playing": "在播放音频或视频时,禁止待机超时" @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "从 DMS 插件库安装插件" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "安全联锁已打开" }, @@ -1065,13 +1215,13 @@ "Jobs: ": "任务: " }, "Keep Awake": { - "Keep Awake": "" + "Keep Awake": "保持活动" }, "Keep Changes": { "Keep Changes": "保持更改" }, "Keeping Awake": { - "Keeping Awake": "" + "Keeping Awake": "保持活动" }, "Keyboard Layout Name": { "Keyboard Layout Name": "键盘布局名称" @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "正在加载插件…..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "位置搜索" }, @@ -1160,11 +1313,17 @@ "Low Priority": { "Low Priority": "次要通知" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "管理和配置插件以扩展 DMS 功能" }, "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": { - "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "" + "Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.": "至多可管理4个独立的状态栏配置。每个状态栏都有自己的位置、控件、样式和显示布局。" }, "Manual Coordinates": { "Manual Coordinates": "手动设置坐标" @@ -1230,7 +1389,7 @@ "Media Players (": "媒体播放器 (" }, "Media Volume OSD": { - "Media Volume OSD": "" + "Media Volume OSD": "媒体音量OSD" }, "Memory": { "Memory": "内存" @@ -1248,7 +1407,7 @@ "Microphone Mute OSD": "OSD麦克风静音" }, "Middle Section": { - "Middle Section": "" + "Middle Section": "中间区域" }, "Minimal palette built around a single hue.": { "Minimal palette built around a single hue.": "围绕单一色调构建的简约配色。" @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "分钟" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "模式:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "实时网速显示" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "显示网络下载与上传速度" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "夜间色温" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "没有正在播放的音频" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "当前无播放内容" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "未找到 VPN 配置" }, "No Weather Data Available": { "No Weather Data Available": "暂无天气数据" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "无可用记录" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "标准通知" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "便签" }, @@ -1454,6 +1631,15 @@ "Other": { "Other": "其他" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "出纸盒即将饱和" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "概览" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "覆盖" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "内边距" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "为系统事件播放声音" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "连接电源" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "OSD电源配置" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "气压" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "打印服务不可用" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "打印机" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "隐私指示器" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "进程" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "个人资料图片过大,请选择更小的图片。" }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "快捷访问应用启动器" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "降雨概率" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "原因" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "关机、重启、挂起、休眠和注销前请求确认" }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "需要 DWL 合成器" }, @@ -1722,11 +1935,14 @@ "Save Notepad File": "保存便签" }, "Save password": { - "Save password": "" + "Save password": "保存密码" }, "Saved": { "Saved": "已保存" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "独立调整 Dank Bar 字体缩放" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "扫描" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "科学" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "搜索插件中..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "搜索中..." }, "Searching...": { "Searching...": "检索中..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "选择启动器Logo" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "选择一个小组件添加到 " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "选择一张图片..." }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "分隔符" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "分别为各个显示器设置壁纸" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "显示注销" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "显示电源操作" }, @@ -1884,7 +2121,7 @@ "Show on-screen display when idle inhibitor state changes": "当空闲抑制状态改变时显示OSD" }, "Show on-screen display when media player volume changes": { - "Show on-screen display when media player volume changes": "" + "Show on-screen display when media player volume changes": "当媒体音量改变时显示OSD" }, "Show on-screen display when microphone is muted/unmuted": { "Show on-screen display when microphone is muted/unmuted": "当麦克风静音状态切换时显示OSD" @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "关机" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "尺寸" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "间距" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "打印缓冲区已满" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "请在这里记录你的笔记..." }, + "State": { + "State": "" + }, "Status": { "Status": "状态" }, @@ -2109,7 +2358,10 @@ "Toggle top bar visibility manually (can be controlled via IPC)": "手动切换顶栏可见性(可通过 IPC 控制)" }, "Toggle visibility of this bar configuration": { - "Toggle visibility of this bar configuration": "" + "Toggle visibility of this bar configuration": "显示/隐藏当前状态栏配置" + }, + "Toggling...": { + "Toggling...": "" }, "Tomorrow": { "Tomorrow": "明日" @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "在此时间后关闭显示器" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "卸载插件" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "从程序坞取消固定" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "VPN 连接" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "VPN 状态与快速连接" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "音量、亮度和其他系统屏幕显示" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "壁纸" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "启用后,应用按字母顺序排序;禁用则按使用频率排序" }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "Wi-Fi 已停用" }, @@ -2301,19 +2583,22 @@ "WiFi is off": "Wi-Fi 已关闭" }, "Widget Background Color": { - "Widget Background Color": "" + "Widget Background Color": "小挂件背景色" }, "Widget Management": { "Widget Management": "小组件管理" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { - "Widget Style": "" + "Widget Style": "小挂件风格" }, "Widget Styling": { "Widget Styling": "小组件样式" }, "Widget Transparency": { - "Widget Transparency": "" + "Widget Transparency": "小挂件透明度" }, "Widgets": { "Widgets": "小组件" @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "工作区切换器" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "检测到未保存的更改,是否在关闭此标签页前保存?" }, @@ -2349,10 +2637,10 @@ "You have unsaved changes. Save before opening a file?": "检测到未保存的更改,是否在打开文件前保存?" }, "custom theme file browser title": { - "Select Custom Theme": "" + "Select Custom Theme": "选择自定义主题" }, "dark mode wallpaper file browser title | light mode wallpaper file browser title | wallpaper file browser title": { - "Select Wallpaper": "" + "Select Wallpaper": "选择壁纸" }, "events": { "events": "事件" @@ -2367,19 +2655,19 @@ "official": "官方" }, "profile image file browser title": { - "Select Profile Image": "" + "Select Profile Image": "选择个人信息图像" }, "settings window title": { - "Settings": "" + "Settings": "设置" }, "sysmon window title": { - "System Monitor": "" + "System Monitor": "系统监视器" }, "update dms for NM integration.": { "update dms for NM integration.": "更新 DMS 以集成 NM" }, "wallpaper directory file browser title": { - "Select Wallpaper Directory": "" + "Select Wallpaper Directory": "选择壁纸位置" }, "• Install only from trusted sources": { "• Install only from trusted sources": "• 仅从可信来源安装" diff --git a/quickshell/translations/poexports/zh_TW.json b/quickshell/translations/poexports/zh_TW.json index c35ece61..07e693c7 100644 --- a/quickshell/translations/poexports/zh_TW.json +++ b/quickshell/translations/poexports/zh_TW.json @@ -1,7 +1,13 @@ { + "%1 adapter(s), none connected": { + "%1 adapter(s), none connected": "" + }, "%1 characters": { "%1 characters": "%1 個字元" }, + "%1 connected": { + "%1 connected": "" + }, "%1 display(s)": { "%1 display(s)": "" }, @@ -50,6 +56,21 @@ "Actions": { "Actions": "選項" }, + "Activate": { + "Activate": "" + }, + "Active": { + "Active": "" + }, + "Active: ": { + "Active: ": "" + }, + "Active: None": { + "Active: None": "" + }, + "Adapters": { + "Adapters": "" + }, "Add": { "Add": "新增" }, @@ -62,6 +83,9 @@ "Add Widget to ": { "Add Widget to ": "新增部件到 " }, + "Add Widget to %1 Section": { + "Add Widget to %1 Section": "" + }, "Add a VPN in NetworkManager": { "Add a VPN in NetworkManager": "新增VPN至網路管理器" }, @@ -92,6 +116,9 @@ "Animation Speed": { "Animation Speed": "動畫速度" }, + "Anonymous Identity": { + "Anonymous Identity": "" + }, "Anonymous Identity (optional)": { "Anonymous Identity (optional)": "匿名身分 (可選)" }, @@ -134,6 +161,9 @@ "Are you sure you want to suspend the system?": { "Are you sure you want to suspend the system?": "你確定要暫停系統嗎?" }, + "Audio": { + "Audio": "" + }, "Audio Codec": { "Audio Codec": "音訊編解碼器" }, @@ -149,9 +179,18 @@ "Audio Output Devices (": { "Audio Output Devices (": "音訊輸出設備 (" }, + "Auth": { + "Auth": "" + }, + "Auth Type": { + "Auth Type": "" + }, "Authenticate": { "Authenticate": "驗證" }, + "Authentication": { + "Authentication": "" + }, "Authentication Required": { "Authentication Required": "需要驗證" }, @@ -167,6 +206,9 @@ "Authorize service for ": { "Authorize service for ": "授權服務 " }, + "Auto": { + "Auto": "" + }, "Auto Location": { "Auto Location": "自動定位" }, @@ -182,6 +224,9 @@ "Auto-saving...": { "Auto-saving...": "自動保存..." }, + "Autoconnect": { + "Autoconnect": "" + }, "Autoconnect disabled": { "Autoconnect disabled": "自動連線關閉" }, @@ -224,15 +269,24 @@ "Available Layouts": { "Available Layouts": "可用佈局" }, + "Available Networks": { + "Available Networks": "" + }, "Available Plugins": { "Available Plugins": "可用的插件" }, "Available Screens (": { "Available Screens (": "可用的螢幕 (" }, + "BSSID": { + "BSSID": "" + }, "Back": { "Back": "返回" }, + "Backend": { + "Backend": "" + }, "Balanced palette with focused accents (default).": { "Balanced palette with focused accents (default).": "顏色平衡且帶有重點點綴的調色板 (預設)。" }, @@ -251,6 +305,9 @@ "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": { "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "將鎖定畫面綁定到 loginctl 的 dbus 訊號。如果使用外部鎖屏,請停用" }, + "Bluetooth": { + "Bluetooth": "" + }, "Bluetooth Icon": { "Bluetooth Icon": "藍芽圖示" }, @@ -341,12 +398,18 @@ "Center Tiling": { "Center Tiling": "居中平鋪" }, + "Certificate Password": { + "Certificate Password": "" + }, "Change bar appearance": { "Change bar appearance": "" }, "Changes:": { "Changes:": "變更:" }, + "Channel": { + "Channel": "" + }, "Check for system updates": { "Check for system updates": "檢查系統更新" }, @@ -368,12 +431,18 @@ "Choose the logo displayed on the launcher button in DankBar": { "Choose the logo displayed on the launcher button in DankBar": "選擇 DankBar 啟動器按鈕上顯示的 logo" }, + "Choose the widget outline accent color": { + "Choose the widget outline accent color": "" + }, "Choose where notification popups appear on screen": { "Choose where notification popups appear on screen": "選擇通知彈出視窗在螢幕上出現的位置" }, "Choose where on-screen displays appear on screen": { "Choose where on-screen displays appear on screen": "選擇螢幕顯示出現在螢幕上的位置" }, + "Cipher": { + "Cipher": "" + }, "Clear": { "Clear": "清除" }, @@ -383,6 +452,9 @@ "Clear All History?": { "Clear All History?": "清除所有紀錄?" }, + "Click Import to add a .ovpn or .conf": { + "Click Import to add a .ovpn or .conf": "" + }, "Clipboard History": { "Clipboard History": "剪貼簿歷史" }, @@ -470,6 +542,9 @@ "Connect to Wi-Fi": { "Connect to Wi-Fi": "連線到 Wi-Fi" }, + "Connected": { + "Connected": "" + }, "Connected Displays": { "Connected Displays": "已連接的螢幕" }, @@ -617,6 +692,12 @@ "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": { "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: 清除 • Shift+Del: 清除所有 • 1-9: 動作 • F10: 幫助 • Esc: 關閉" }, + "Delete": { + "Delete": "" + }, + "Delete VPN": { + "Delete VPN": "" + }, "Derives colors that closely match the underlying image.": { "Derives colors that closely match the underlying image.": "提取與底層圖像高度匹配的顏色。" }, @@ -641,6 +722,9 @@ "Disconnect": { "Disconnect": "斷開連線" }, + "Disconnected": { + "Disconnected": "" + }, "Disconnected from WiFi": { "Disconnected from WiFi": "已中斷 WiFi 連線" }, @@ -674,6 +758,9 @@ "Display currently focused application title": { "Display currently focused application title": "顯示目前焦點應用程式的標題" }, + "Display only workspaces that contain windows": { + "Display only workspaces that contain windows": "" + }, "Display power menu actions in a grid instead of a list": { "Display power menu actions in a grid instead of a list": "以網格而非列表顯示電源選單操作" }, @@ -716,6 +803,9 @@ "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": { "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖曳部件即可在版塊內重新排序。使用眼睛圖示隱藏/顯示部件 (會保持間距),或使用 X 將其完全移除。" }, + "Driver": { + "Driver": "" + }, "Duplicate Wallpaper with Blur": { "Duplicate Wallpaper with Blur": "模糊化重複桌布" }, @@ -800,9 +890,15 @@ "Enter this passkey on ": { "Enter this passkey on ": "" }, + "Enterprise": { + "Enterprise": "" + }, "Error": { "Error": "錯誤" }, + "Ethernet": { + "Ethernet": "" + }, "Exclusive Zone Offset": { "Exclusive Zone Offset": "獨佔區域偏移" }, @@ -812,6 +908,12 @@ "F1/I: Toggle • F10: Help": { "F1/I: Toggle • F10: Help": "F1/I: 切換 • F10: 幫助" }, + "Fade grace period": { + "Fade grace period": "" + }, + "Fade to lock screen": { + "Fade to lock screen": "" + }, "Failed to activate configuration": { "Failed to activate configuration": "無法啟動配置" }, @@ -827,6 +929,9 @@ "Failed to connect to ": { "Failed to connect to ": "無法連線到 " }, + "Failed to delete VPN": { + "Failed to delete VPN": "" + }, "Failed to disconnect VPN": { "Failed to disconnect VPN": "無法斷開 VPN" }, @@ -839,6 +944,12 @@ "Failed to enable WiFi": { "Failed to enable WiFi": "無法啟用 WiFi" }, + "Failed to import VPN": { + "Failed to import VPN": "" + }, + "Failed to load VPN config": { + "Failed to load VPN config": "" + }, "Failed to pause printer": { "Failed to pause printer": "無法暫停印表機" }, @@ -857,6 +968,9 @@ "Failed to start connection to ": { "Failed to start connection to ": "無法啟動連線到 " }, + "Failed to update VPN": { + "Failed to update VPN": "" + }, "Failed to update autoconnect": { "Failed to update autoconnect": "自動連線更新失敗" }, @@ -899,6 +1013,9 @@ "Force terminal applications to always use dark color schemes": { "Force terminal applications to always use dark color schemes": "強制終端應用程式始終使用深色配色方案" }, + "Forget": { + "Forget": "" + }, "Forget Device": { "Forget Device": "忘記設備" }, @@ -911,6 +1028,9 @@ "Format Legend": { "Format Legend": "格式說明" }, + "Frequency": { + "Frequency": "" + }, "Fun": { "Fun": "有趣的" }, @@ -944,6 +1064,9 @@ "Goth Corners": { "Goth Corners": "圓角介面融合" }, + "Gradually fade the screen before locking with a configurable grace period": { + "Gradually fade the screen before locking with a configurable grace period": "" + }, "Graphics": { "Graphics": "圖形" }, @@ -986,6 +1109,18 @@ "High-fidelity palette that preserves source hues.": { "High-fidelity palette that preserves source hues.": "保留來源色調的高保真調色板。" }, + "Hold Duration": { + "Hold Duration": "" + }, + "Hold longer to confirm": { + "Hold longer to confirm": "" + }, + "Hold to Confirm Power Actions": { + "Hold to Confirm Power Actions": "" + }, + "Hold to confirm (%1s)": { + "Hold to confirm (%1s)": "" + }, "Hour": { "Hour": "小時" }, @@ -998,6 +1133,12 @@ "I Understand": { "I Understand": "我了解" }, + "IP": { + "IP": "" + }, + "IP Address:": { + "IP Address:": "" + }, "Icon Size": { "Icon Size": "圖示大小" }, @@ -1022,6 +1163,12 @@ "Image": { "Image": "圖片" }, + "Import": { + "Import": "" + }, + "Import VPN": { + "Import VPN": "" + }, "Include Transitions": { "Include Transitions": "包括過渡" }, @@ -1046,6 +1193,9 @@ "Install plugins from the DMS plugin registry": { "Install plugins from the DMS plugin registry": "從 DMS 插件註冊表安裝插件" }, + "Interface:": { + "Interface:": "" + }, "Interlock Open": { "Interlock Open": "聯鎖開啟" }, @@ -1133,6 +1283,9 @@ "Loading plugins...": { "Loading plugins...": "讀取插件..." }, + "Loading...": { + "Loading...": "" + }, "Location Search": { "Location Search": "位置搜尋" }, @@ -1160,6 +1313,12 @@ "Low Priority": { "Low Priority": "低優先級" }, + "MAC": { + "MAC": "" + }, + "MTU": { + "MTU": "" + }, "Manage and configure plugins for extending DMS functionality": { "Manage and configure plugins for extending DMS functionality": "管理和配置用於擴展 DMS 功能的插件" }, @@ -1256,6 +1415,9 @@ "Minute": { "Minute": "分鐘" }, + "Mode": { + "Mode": "" + }, "Mode:": { "Mode:": "模式:" }, @@ -1316,6 +1478,9 @@ "Network Speed Monitor": { "Network Speed Monitor": "網速監視" }, + "Network Status": { + "Network Status": "" + }, "Network download and upload speed display": { "Network download and upload speed display": "顯示網路下載跟上傳速度" }, @@ -1334,6 +1499,9 @@ "Night Temperature": { "Night Temperature": "夜間色溫" }, + "No": { + "No": "" + }, "No Active Players": { "No Active Players": "無播放器" }, @@ -1346,12 +1514,18 @@ "No Media": { "No Media": "無媒體" }, + "No VPN profiles": { + "No VPN profiles": "" + }, "No VPN profiles found": { "No VPN profiles found": "未找到 VPN 設定檔" }, "No Weather Data Available": { "No Weather Data Available": "沒有氣象數據" }, + "No adapters": { + "No adapters": "" + }, "No clipboard entries found": { "No clipboard entries found": "剪貼簿無內容" }, @@ -1379,6 +1553,9 @@ "Normal Priority": { "Normal Priority": "普通優先級" }, + "Not connected": { + "Not connected": "" + }, "Notepad": { "Notepad": "筆記本" }, @@ -1454,6 +1631,15 @@ "Other": { "Other": "其他" }, + "Outline Color": { + "Outline Color": "" + }, + "Outline Opacity": { + "Outline Opacity": "" + }, + "Outline Thickness": { + "Outline Thickness": "" + }, "Output Area Almost Full": { "Output Area Almost Full": "輸出區域即將滿載" }, @@ -1466,9 +1652,15 @@ "Overview": { "Overview": "概覽" }, + "Overview of your network connections": { + "Overview of your network connections": "" + }, "Overwrite": { "Overwrite": "覆寫" }, + "PIN": { + "PIN": "" + }, "Padding": { "Padding": "內距" }, @@ -1532,6 +1724,9 @@ "Play sounds for system events": { "Play sounds for system events": "播放系統事件的音效" }, + "Playback": { + "Playback": "" + }, "Plugged In": { "Plugged In": "已插入" }, @@ -1583,6 +1778,9 @@ "Power Profile OSD": { "Power Profile OSD": "電源設定檔 OSD" }, + "Preference": { + "Preference": "" + }, "Pressure": { "Pressure": "氣壓" }, @@ -1598,6 +1796,9 @@ "Print Server not available": { "Print Server not available": "列印伺服器無法使用" }, + "Printer": { + "Printer": "" + }, "Printers": { "Printers": "印表機" }, @@ -1607,6 +1808,9 @@ "Privacy Indicator": { "Privacy Indicator": "隱私指示器" }, + "Private Key Password": { + "Private Key Password": "" + }, "Process": { "Process": "程序" }, @@ -1619,6 +1823,9 @@ "Profile image is too large. Please use a smaller image.": { "Profile image is too large. Please use a smaller image.": "個人資料圖片太大。請使用較小的圖片。" }, + "Protocol": { + "Protocol": "" + }, "Quick access to application launcher": { "Quick access to application launcher": "快速存取應用程式啟動器" }, @@ -1637,6 +1844,9 @@ "Rain Chance": { "Rain Chance": "降雨機率" }, + "Rate": { + "Rate": "" + }, "Reason": { "Reason": "原因" }, @@ -1664,6 +1874,9 @@ "Request confirmation on power off, restart, suspend, hibernate and logout actions": { "Request confirmation on power off, restart, suspend, hibernate and logout actions": "請求確認關機、重新啟動、暫停、休眠和登出操作" }, + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": { + "Require holding button/key to confirm power off, restart, suspend, hibernate and logout": "" + }, "Requires DWL compositor": { "Requires DWL compositor": "需要 DWL 混成器" }, @@ -1727,6 +1940,9 @@ "Saved": { "Saved": "已儲存" }, + "Saved Configurations": { + "Saved Configurations": "" + }, "Scale DankBar font sizes independently": { "Scale DankBar font sizes independently": "獨立縮放 DankBar 字體大小" }, @@ -1736,6 +1952,9 @@ "Scan": { "Scan": "掃描" }, + "Scanning...": { + "Scanning...": "" + }, "Science": { "Science": "科學" }, @@ -1757,12 +1976,21 @@ "Search plugins...": { "Search plugins...": "搜尋插件..." }, + "Search widgets...": { + "Search widgets...": "" + }, "Search...": { "Search...": "搜尋..." }, "Searching...": { "Searching...": "搜尋中..." }, + "Secured": { + "Secured": "" + }, + "Security": { + "Security": "" + }, "Select Launcher Logo": { "Select Launcher Logo": "選擇啟動器 Logo" }, @@ -1775,6 +2003,9 @@ "Select a widget to add to the ": { "Select a widget to add to the ": "選擇一個部件加到 " }, + "Select a widget to add. You can add multiple instances of the same widget if needed.": { + "Select a widget to add. You can add multiple instances of the same widget if needed.": "" + }, "Select an image file...": { "Select an image file...": "選擇一張圖片..." }, @@ -1805,6 +2036,9 @@ "Separator": { "Separator": "分隔符" }, + "Server": { + "Server": "" + }, "Set different wallpapers for each connected monitor": { "Set different wallpapers for each connected monitor": "為每個連接的螢幕設定不同的桌布" }, @@ -1838,6 +2072,9 @@ "Show Log Out": { "Show Log Out": "顯示登出" }, + "Show Occupied Workspaces Only": { + "Show Occupied Workspaces Only": "" + }, "Show Power Actions": { "Show Power Actions": "顯示電源選項" }, @@ -1931,6 +2168,12 @@ "Shutdown": { "Shutdown": "關機" }, + "Signal": { + "Signal": "" + }, + "Signal:": { + "Signal:": "" + }, "Size": { "Size": "大小" }, @@ -1949,6 +2192,9 @@ "Spacing": { "Spacing": "間距" }, + "Speed": { + "Speed": "" + }, "Spool Area Full": { "Spool Area Full": "緩衝區已滿" }, @@ -1961,6 +2207,9 @@ "Start typing your notes here...": { "Start typing your notes here...": "從這裡開始輸入您的筆記..." }, + "State": { + "State": "" + }, "Status": { "Status": "狀態" }, @@ -2111,6 +2360,9 @@ "Toggle visibility of this bar configuration": { "Toggle visibility of this bar configuration": "" }, + "Toggling...": { + "Toggling...": "" + }, "Tomorrow": { "Tomorrow": "明天" }, @@ -2135,9 +2387,15 @@ "Turn off monitors after": { "Turn off monitors after": "關閉螢幕之後" }, + "Unavailable": { + "Unavailable": "" + }, "Uninstall Plugin": { "Uninstall Plugin": "解除安裝插件" }, + "Unknown": { + "Unknown": "" + }, "Unpin from Dock": { "Unpin from Dock": "取消 Dock 釘選" }, @@ -2225,6 +2483,18 @@ "VPN Connections": { "VPN Connections": "VPN 連線" }, + "VPN Password": { + "VPN Password": "" + }, + "VPN configuration updated": { + "VPN configuration updated": "" + }, + "VPN deleted": { + "VPN deleted": "" + }, + "VPN imported: ": { + "VPN imported: ": "" + }, "VPN status and quick connect": { "VPN status and quick connect": "VPN 狀態和快速連線" }, @@ -2264,6 +2534,9 @@ "Volume, brightness, and other system OSDs": { "Volume, brightness, and other system OSDs": "音量、亮度及其他系統OSD" }, + "WPA/WPA2": { + "WPA/WPA2": "" + }, "Wallpaper": { "Wallpaper": "桌布" }, @@ -2291,6 +2564,15 @@ "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": { "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.": "啟用後,應用程式將按字母順序排序。禁用後,應用程式將按使用頻率排序。" }, + "Wi-Fi Password": { + "Wi-Fi Password": "" + }, + "WiFi": { + "WiFi": "" + }, + "WiFi Device": { + "WiFi Device": "" + }, "WiFi disabled": { "WiFi disabled": "關閉 WiFi" }, @@ -2306,6 +2588,9 @@ "Widget Management": { "Widget Management": "部件管理" }, + "Widget Outline": { + "Widget Outline": "" + }, "Widget Style": { "Widget Style": "" }, @@ -2336,6 +2621,9 @@ "Workspace Switcher": { "Workspace Switcher": "工作區切換器" }, + "Yes": { + "Yes": "" + }, "You have unsaved changes. Save before closing this tab?": { "You have unsaved changes. Save before closing this tab?": "您有未儲存的變更。是否要儲存?" }, diff --git a/quickshell/translations/template.json b/quickshell/translations/template.json index 73f406f2..35fb4926 100644 --- a/quickshell/translations/template.json +++ b/quickshell/translations/template.json @@ -1,4 +1,11 @@ [ + { + "term": "%1 adapter(s), none connected", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "%1 characters", "translation": "", @@ -6,6 +13,13 @@ "reference": "", "comment": "" }, + { + "term": "%1 connected", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "%1 display(s)", "translation": "", @@ -118,6 +132,41 @@ "reference": "", "comment": "" }, + { + "term": "Activate", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Active", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Active: ", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Active: None", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Adapters", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Add", "translation": "", @@ -140,14 +189,7 @@ "comment": "" }, { - "term": "Add Widget to ", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Add a VPN in NetworkManager", + "term": "Add Widget to %1 Section", "translation": "", "context": "", "reference": "", @@ -216,6 +258,13 @@ "reference": "", "comment": "" }, + { + "term": "Anonymous Identity", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Anonymous Identity (optional)", "translation": "", @@ -280,35 +329,7 @@ "comment": "" }, { - "term": "Are you sure you want to hibernate the system?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Are you sure you want to log out?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Are you sure you want to power off the system?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Are you sure you want to reboot the system?", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, - { - "term": "Are you sure you want to suspend the system?", + "term": "Audio", "translation": "", "context": "", "reference": "", @@ -335,13 +356,6 @@ "reference": "", "comment": "" }, - { - "term": "Audio Icon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, { "term": "Audio Output Devices (", "translation": "", @@ -349,6 +363,20 @@ "reference": "", "comment": "" }, + { + "term": "Auth", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Auth Type", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Authenticate", "translation": "", @@ -356,6 +384,13 @@ "reference": "", "comment": "" }, + { + "term": "Authentication", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Authentication Required", "translation": "", @@ -391,6 +426,13 @@ "reference": "", "comment": "" }, + { + "term": "Auto", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Auto Location", "translation": "", @@ -426,6 +468,13 @@ "reference": "", "comment": "" }, + { + "term": "Autoconnect", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Autoconnect disabled", "translation": "", @@ -524,6 +573,13 @@ "reference": "", "comment": "" }, + { + "term": "Available Networks", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Available Plugins", "translation": "", @@ -538,6 +594,13 @@ "reference": "", "comment": "" }, + { + "term": "BSSID", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Back", "translation": "", @@ -545,6 +608,13 @@ "reference": "", "comment": "" }, + { + "term": "Backend", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Balanced palette with focused accents (default).", "translation": "", @@ -588,7 +658,7 @@ "comment": "" }, { - "term": "Bluetooth Icon", + "term": "Bluetooth", "translation": "", "context": "", "reference": "", @@ -790,6 +860,13 @@ "reference": "", "comment": "" }, + { + "term": "Certificate Password", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Change bar appearance", "translation": "", @@ -804,6 +881,13 @@ "reference": "", "comment": "" }, + { + "term": "Channel", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Check for system updates", "translation": "", @@ -853,6 +937,13 @@ "reference": "", "comment": "" }, + { + "term": "Choose the widget outline accent color", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Choose where notification popups appear on screen", "translation": "", @@ -867,6 +958,13 @@ "reference": "", "comment": "" }, + { + "term": "Cipher", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Clear", "translation": "", @@ -888,6 +986,13 @@ "reference": "", "comment": "" }, + { + "term": "Click Import to add a .ovpn or .conf", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Clipboard History", "translation": "", @@ -1091,6 +1196,13 @@ "reference": "", "comment": "" }, + { + "term": "Connected", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Connected Displays", "translation": "", @@ -1406,6 +1518,20 @@ "reference": "", "comment": "" }, + { + "term": "Delete", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Delete VPN", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Derives colors that closely match the underlying image.", "translation": "", @@ -1462,6 +1588,13 @@ "reference": "", "comment": "" }, + { + "term": "Disconnected", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Disconnected from WiFi", "translation": "", @@ -1539,6 +1672,13 @@ "reference": "", "comment": "" }, + { + "term": "Display only workspaces that contain windows", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Display power menu actions in a grid instead of a list", "translation": "", @@ -1637,6 +1777,13 @@ "reference": "", "comment": "" }, + { + "term": "Driver", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Duplicate Wallpaper with Blur", "translation": "", @@ -1833,6 +1980,13 @@ "reference": "", "comment": "" }, + { + "term": "Enterprise", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Error", "translation": "", @@ -1840,6 +1994,13 @@ "reference": "", "comment": "" }, + { + "term": "Ethernet", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Exclusive Zone Offset", "translation": "", @@ -1861,6 +2022,20 @@ "reference": "", "comment": "" }, + { + "term": "Fade grace period", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Fade to lock screen", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Failed to activate configuration", "translation": "", @@ -1896,6 +2071,13 @@ "reference": "", "comment": "" }, + { + "term": "Failed to delete VPN", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Failed to disconnect VPN", "translation": "", @@ -1924,6 +2106,20 @@ "reference": "", "comment": "" }, + { + "term": "Failed to import VPN", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Failed to load VPN config", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Failed to pause printer", "translation": "", @@ -1966,6 +2162,13 @@ "reference": "", "comment": "" }, + { + "term": "Failed to update VPN", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Failed to update autoconnect", "translation": "", @@ -2064,6 +2267,13 @@ "reference": "", "comment": "" }, + { + "term": "Forget", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Forget Device", "translation": "", @@ -2092,6 +2302,13 @@ "reference": "", "comment": "" }, + { + "term": "Frequency", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Fun", "translation": "", @@ -2169,6 +2386,13 @@ "reference": "", "comment": "" }, + { + "term": "Gradually fade the screen before locking with a configurable grace period", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Graphics", "translation": "", @@ -2260,6 +2484,34 @@ "reference": "", "comment": "" }, + { + "term": "Hold Duration", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Hold longer to confirm", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Hold to Confirm Power Actions", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Hold to confirm (%1s)", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Hour", "translation": "", @@ -2288,6 +2540,20 @@ "reference": "", "comment": "" }, + { + "term": "IP", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "IP Address:", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Icon Size", "translation": "", @@ -2344,6 +2610,20 @@ "reference": "", "comment": "" }, + { + "term": "Import", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Import VPN", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Include Transitions", "translation": "", @@ -2400,6 +2680,13 @@ "reference": "", "comment": "" }, + { + "term": "Interface:", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Interlock Open", "translation": "", @@ -2603,6 +2890,13 @@ "reference": "", "comment": "" }, + { + "term": "Loading...", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Location Search", "translation": "", @@ -2666,6 +2960,20 @@ "reference": "", "comment": "" }, + { + "term": "MAC", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "MTU", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Manage and configure plugins for extending DMS functionality", "translation": "", @@ -2890,6 +3198,13 @@ "reference": "", "comment": "" }, + { + "term": "Mode", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Mode:", "translation": "", @@ -2995,13 +3310,6 @@ "reference": "", "comment": "" }, - { - "term": "Network Icon", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, { "term": "Network Info", "translation": "", @@ -3030,6 +3338,13 @@ "reference": "", "comment": "" }, + { + "term": "Network Status", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Network download and upload speed display", "translation": "", @@ -3072,6 +3387,13 @@ "reference": "", "comment": "" }, + { + "term": "No", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "No Active Players", "translation": "", @@ -3101,7 +3423,7 @@ "comment": "" }, { - "term": "No VPN profiles found", + "term": "No VPN profiles", "translation": "", "context": "", "reference": "", @@ -3114,6 +3436,13 @@ "reference": "", "comment": "" }, + { + "term": "No adapters", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "No clipboard entries found", "translation": "", @@ -3177,6 +3506,13 @@ "reference": "", "comment": "" }, + { + "term": "Not connected", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Notepad", "translation": "", @@ -3352,6 +3688,27 @@ "reference": "", "comment": "" }, + { + "term": "Outline Color", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Outline Opacity", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Outline Thickness", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Output Area Almost Full", "translation": "", @@ -3380,6 +3737,13 @@ "reference": "", "comment": "" }, + { + "term": "Overview of your network connections", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Overwrite", "translation": "", @@ -3387,6 +3751,13 @@ "reference": "", "comment": "" }, + { + "term": "PIN", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Padding", "translation": "", @@ -3534,6 +3905,13 @@ "reference": "", "comment": "" }, + { + "term": "Playback", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Plugged In", "translation": "", @@ -3653,6 +4031,13 @@ "reference": "", "comment": "" }, + { + "term": "Preference", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Pressure", "translation": "", @@ -3688,6 +4073,13 @@ "reference": "", "comment": "" }, + { + "term": "Printer", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Printers", "translation": "", @@ -3709,6 +4101,13 @@ "reference": "", "comment": "" }, + { + "term": "Private Key Password", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Process", "translation": "", @@ -3737,6 +4136,13 @@ "reference": "", "comment": "" }, + { + "term": "Protocol", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Quick access to application launcher", "translation": "", @@ -3779,6 +4185,13 @@ "reference": "", "comment": "" }, + { + "term": "Rate", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Reason", "translation": "", @@ -3836,7 +4249,7 @@ "comment": "" }, { - "term": "Request confirmation on power off, restart, suspend, hibernate and logout actions", + "term": "Require holding button/key to confirm power off, restart, suspend, hibernate and logout", "translation": "", "context": "", "reference": "", @@ -3982,6 +4395,13 @@ "reference": "", "comment": "" }, + { + "term": "Saved Configurations", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Scale DankBar font sizes independently", "translation": "", @@ -4003,6 +4423,13 @@ "reference": "", "comment": "" }, + { + "term": "Scanning...", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Science", "translation": "", @@ -4052,6 +4479,13 @@ "reference": "", "comment": "" }, + { + "term": "Search widgets...", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Search...", "translation": "", @@ -4066,6 +4500,20 @@ "reference": "", "comment": "" }, + { + "term": "Secured", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Security", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Select Custom Theme", "translation": "", @@ -4116,7 +4564,7 @@ "comment": "" }, { - "term": "Select a widget to add to the ", + "term": "Select a widget to add. You can add multiple instances of the same widget if needed.", "translation": "", "context": "", "reference": "", @@ -4192,6 +4640,13 @@ "reference": "", "comment": "" }, + { + "term": "Server", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Set different wallpapers for each connected monitor", "translation": "", @@ -4227,13 +4682,6 @@ "reference": "", "comment": "" }, - { - "term": "Show Confirmation on Power Actions", - "translation": "", - "context": "", - "reference": "", - "comment": "" - }, { "term": "Show Dock", "translation": "", @@ -4269,6 +4717,13 @@ "reference": "", "comment": "" }, + { + "term": "Show Occupied Workspaces Only", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Show Power Actions", "translation": "", @@ -4486,6 +4941,20 @@ "reference": "", "comment": "" }, + { + "term": "Signal", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "Signal:", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Size", "translation": "", @@ -4528,6 +4997,13 @@ "reference": "", "comment": "" }, + { + "term": "Speed", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Spool Area Full", "translation": "", @@ -4556,6 +5032,13 @@ "reference": "", "comment": "" }, + { + "term": "State", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Status", "translation": "", @@ -4899,6 +5382,13 @@ "reference": "", "comment": "" }, + { + "term": "Toggling...", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Tomorrow", "translation": "", @@ -4955,6 +5445,13 @@ "reference": "", "comment": "" }, + { + "term": "Unavailable", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Uninstall Plugin", "translation": "", @@ -4962,6 +5459,13 @@ "reference": "", "comment": "" }, + { + "term": "Unknown", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Unpin from Dock", "translation": "", @@ -5151,6 +5655,34 @@ "reference": "", "comment": "" }, + { + "term": "VPN Password", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "VPN configuration updated", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "VPN deleted", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "VPN imported: ", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "VPN status and quick connect", "translation": "", @@ -5242,6 +5774,13 @@ "reference": "", "comment": "" }, + { + "term": "WPA/WPA2", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Wallpaper", "translation": "", @@ -5305,6 +5844,27 @@ "reference": "", "comment": "" }, + { + "term": "Wi-Fi Password", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "WiFi", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, + { + "term": "WiFi Device", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "WiFi disabled", "translation": "", @@ -5340,6 +5900,13 @@ "reference": "", "comment": "" }, + { + "term": "Widget Outline", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "Widget Style", "translation": "", @@ -5410,6 +5977,13 @@ "reference": "", "comment": "" }, + { + "term": "Yes", + "translation": "", + "context": "", + "reference": "", + "comment": "" + }, { "term": "You have unsaved changes. Save before closing this tab?", "translation": "",