mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
network: big feature enrichment
- Dedicated view in settings - VPN profile management - Ethernet disconnection - Turn prompts into floating windows
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -18,24 +18,11 @@ 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,
|
||||
}
|
||||
|
||||
assert.Equal(t, "1", state.SessionID)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -37,9 +37,17 @@ 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{}
|
||||
ethernetDevices map[string]*ethernetDeviceInfo
|
||||
wifiDevice interface{}
|
||||
settings interface{}
|
||||
wifiDev interface{}
|
||||
@@ -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
|
||||
@@ -81,6 +107,7 @@ func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*Netwo
|
||||
backend := &NetworkManagerBackend{
|
||||
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
|
||||
}
|
||||
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...)
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
if !anyConnected && b.ethernetDevice != nil {
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -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,
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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{}{
|
||||
|
||||
@@ -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"})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -52,11 +52,25 @@ 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"`
|
||||
RemoteHost string `json:"remoteHost,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Autoconnect bool `json:"autoconnect"`
|
||||
Data map[string]string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type VPNActive struct {
|
||||
@@ -66,6 +80,12 @@ type VPNActive struct {
|
||||
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 {
|
||||
@@ -156,6 +183,7 @@ type PromptRequest struct {
|
||||
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"`
|
||||
@@ -169,6 +197,12 @@ 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"`
|
||||
@@ -177,6 +211,7 @@ type CredentialPrompt struct {
|
||||
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"`
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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?)")
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +1,60 @@
|
||||
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)
|
||||
|
||||
Connections {
|
||||
target: contentLoader.item
|
||||
function onImplicitHeightChanged() {
|
||||
if (shouldBeVisible && contentLoader.item) {
|
||||
const newHeight = contentLoader.item.implicitHeight + Theme.spacingM * 2;
|
||||
if (newHeight > minHeight) {
|
||||
minHeight = newHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
function hide() {
|
||||
visible = false;
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.passwordField) {
|
||||
contentLoader.item.passwordField.forceActiveFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onDialogClosed: {
|
||||
function submitAuth() {
|
||||
if (passwordInput.length === 0 || !currentFlow || isLoading)
|
||||
return;
|
||||
isLoading = true;
|
||||
currentFlow.submit(passwordInput);
|
||||
passwordInput = "";
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
onBackgroundClicked: () => {
|
||||
if (currentFlow && !isLoading) {
|
||||
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;
|
||||
}
|
||||
passwordInput = "";
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -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) {
|
||||
if (!currentFlow.isResponseRequired)
|
||||
return;
|
||||
isLoading = false;
|
||||
passwordInput = "";
|
||||
if (contentLoader.item && contentLoader.item.passwordField) {
|
||||
contentLoader.item.passwordField.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
passwordField.forceActiveFocus();
|
||||
}
|
||||
|
||||
function onAuthenticationSucceeded() {
|
||||
close();
|
||||
hide();
|
||||
}
|
||||
|
||||
function onAuthenticationFailed() {
|
||||
@@ -104,24 +92,18 @@ DankModal {
|
||||
}
|
||||
|
||||
function onAuthenticationRequestCancelled() {
|
||||
close();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
content: Component {
|
||||
FocusScope {
|
||||
id: authContent
|
||||
|
||||
property alias passwordField: passwordField
|
||||
id: contentFocusScope
|
||||
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
implicitHeight: headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM
|
||||
|
||||
Keys.onEscapePressed: event => {
|
||||
if (currentFlow && !isLoading) {
|
||||
currentFlow.cancelAuthenticationRequest();
|
||||
}
|
||||
cancelAuth();
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
@@ -175,11 +157,7 @@ DankModal {
|
||||
iconColor: Theme.surfaceText
|
||||
enabled: !isLoading
|
||||
opacity: enabled ? 1 : 0.5
|
||||
onClicked: () => {
|
||||
if (currentFlow) {
|
||||
currentFlow.cancelAuthenticationRequest();
|
||||
}
|
||||
}
|
||||
onClicked: cancelAuth()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,9 +191,7 @@ DankModal {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: !isLoading
|
||||
onClicked: () => {
|
||||
passwordField.forceActiveFocus();
|
||||
}
|
||||
onClicked: passwordField.forceActiveFocus()
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -229,16 +205,8 @@ DankModal {
|
||||
placeholderText: ""
|
||||
backgroundColor: "transparent"
|
||||
enabled: !isLoading
|
||||
onTextEdited: () => {
|
||||
passwordInput = text;
|
||||
}
|
||||
onAccepted: () => {
|
||||
if (passwordInput.length > 0 && currentFlow && !isLoading) {
|
||||
isLoading = true;
|
||||
currentFlow.submit(passwordInput);
|
||||
passwordInput = "";
|
||||
}
|
||||
}
|
||||
onTextEdited: passwordInput = text
|
||||
onAccepted: submitAuth()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +260,6 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
id: cancelText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: I18n.tr("Cancel")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -302,16 +269,11 @@ DankModal {
|
||||
|
||||
MouseArea {
|
||||
id: cancelArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: parent.enabled
|
||||
onClicked: () => {
|
||||
if (currentFlow) {
|
||||
currentFlow.cancelAuthenticationRequest();
|
||||
}
|
||||
}
|
||||
onClicked: cancelAuth()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +287,6 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
id: authText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: I18n.tr("Authenticate")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -335,18 +296,11 @@ DankModal {
|
||||
|
||||
MouseArea {
|
||||
id: authArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: parent.enabled
|
||||
onClicked: () => {
|
||||
if (currentFlow && !isLoading) {
|
||||
isLoading = true;
|
||||
currentFlow.submit(passwordInput);
|
||||
passwordInput = "";
|
||||
}
|
||||
}
|
||||
onClicked: submitAuth()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -361,4 +315,3 @@ DankModal {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,129 +88,172 @@ 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();
|
||||
visible = true;
|
||||
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();
|
||||
}
|
||||
if (reason === "wrong-password" && fieldsInfo.length === 0) {
|
||||
passwordInput.text = "";
|
||||
}
|
||||
focusFirstField();
|
||||
});
|
||||
}
|
||||
|
||||
shouldBeVisible: false
|
||||
modalWidth: 420
|
||||
modalHeight: {
|
||||
if (requiresEnterprise)
|
||||
return 430;
|
||||
if (isVpnPrompt)
|
||||
return 260;
|
||||
return 230;
|
||||
function hide() {
|
||||
visible = false;
|
||||
}
|
||||
onShouldBeVisibleChanged: () => {
|
||||
if (!shouldBeVisible) {
|
||||
wifiPasswordInput = "";
|
||||
wifiUsernameInput = "";
|
||||
wifiAnonymousIdentityInput = "";
|
||||
wifiDomainInput = "";
|
||||
|
||||
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, " ");
|
||||
}
|
||||
}
|
||||
onOpened: {
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item) {
|
||||
if (requiresEnterprise && contentLoader.item.usernameInput) {
|
||||
contentLoader.item.usernameInput.forceActiveFocus();
|
||||
} else if (contentLoader.item.passwordInput) {
|
||||
contentLoader.item.passwordInput.forceActiveFocus();
|
||||
|
||||
function submitCredentialsAndClose() {
|
||||
if (fieldsInfo.length > 0) {
|
||||
NetworkService.submitCredentials(promptToken, secretValues, savePasswordCheckbox.checked);
|
||||
hide();
|
||||
secretValues = {};
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
onBackgroundClicked: () => {
|
||||
|
||||
if (isPromptMode) {
|
||||
NetworkService.cancelCredentials(promptToken);
|
||||
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;
|
||||
}
|
||||
close();
|
||||
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 !== "") {
|
||||
if (!NetworkService.passwordDialogShouldReopen || NetworkService.connectingSSID === "")
|
||||
return;
|
||||
wifiPasswordSSID = NetworkService.connectingSSID;
|
||||
wifiPasswordInput = "";
|
||||
open();
|
||||
visible = true;
|
||||
NetworkService.passwordDialogShouldReopen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content: Component {
|
||||
FocusScope {
|
||||
id: wifiContent
|
||||
|
||||
property alias usernameInput: usernameInput
|
||||
property alias passwordInput: passwordInput
|
||||
id: contentFocusScope
|
||||
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
|
||||
Keys.onEscapePressed: event => {
|
||||
if (isPromptMode) {
|
||||
NetworkService.cancelCredentials(promptToken);
|
||||
}
|
||||
close();
|
||||
wifiPasswordInput = "";
|
||||
wifiUsernameInput = "";
|
||||
wifiAnonymousIdentityInput = "";
|
||||
wifiDomainInput = "";
|
||||
clearAndClose();
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentCol
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
width: contentCol.width
|
||||
|
||||
Column {
|
||||
width: parent.width - 40
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (isVpnPrompt) {
|
||||
return I18n.tr("Connect to VPN");
|
||||
}
|
||||
return I18n.tr("Connect to Wi-Fi");
|
||||
}
|
||||
text: isVpnPrompt ? I18n.tr("Connect to VPN") : I18n.tr("Connect to Wi-Fi")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -209,9 +265,10 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (isVpnPrompt) {
|
||||
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;
|
||||
}
|
||||
@@ -235,15 +292,76 @@ DankModal {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
onClicked: () => {
|
||||
if (isPromptMode) {
|
||||
NetworkService.cancelCredentials(promptToken);
|
||||
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();
|
||||
}
|
||||
close();
|
||||
wifiPasswordInput = "";
|
||||
wifiUsernameInput = "";
|
||||
wifiAnonymousIdentityInput = "";
|
||||
wifiDomainInput = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,13 +373,11 @@ DankModal {
|
||||
color: Theme.surfaceHover
|
||||
border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||
border.width: usernameInput.activeFocus ? 2 : 1
|
||||
visible: requiresEnterprise && !isVpnPrompt
|
||||
visible: requiresEnterprise && !isVpnPrompt && fieldsInfo.length === 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: () => {
|
||||
usernameInput.forceActiveFocus();
|
||||
}
|
||||
onClicked: usernameInput.forceActiveFocus()
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -273,15 +389,11 @@ DankModal {
|
||||
text: wifiUsernameInput
|
||||
placeholderText: I18n.tr("Username")
|
||||
backgroundColor: "transparent"
|
||||
enabled: root.shouldBeVisible
|
||||
onTextEdited: () => {
|
||||
wifiUsernameInput = text;
|
||||
}
|
||||
onAccepted: () => {
|
||||
if (passwordInput) {
|
||||
passwordInput.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
enabled: root.visible
|
||||
keyNavigationTab: passwordInput
|
||||
keyNavigationBacktab: domainMatchInput
|
||||
onTextEdited: wifiUsernameInput = text
|
||||
onAccepted: passwordInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,12 +404,11 @@ DankModal {
|
||||
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();
|
||||
}
|
||||
onClicked: passwordInput.forceActiveFocus()
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -310,69 +421,16 @@ DankModal {
|
||||
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();
|
||||
enabled: root.visible
|
||||
keyNavigationTab: (requiresEnterprise && !isVpnPrompt) ? anonInput : null
|
||||
keyNavigationBacktab: (requiresEnterprise && !isVpnPrompt) ? usernameInput : null
|
||||
onTextEdited: wifiPasswordInput = text
|
||||
onAccepted: {
|
||||
if (requiresEnterprise && !isVpnPrompt) {
|
||||
anonInput.forceActiveFocus();
|
||||
return;
|
||||
}
|
||||
submitCredentialsAndClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,9 +446,7 @@ DankModal {
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: () => {
|
||||
anonInput.forceActiveFocus();
|
||||
}
|
||||
onClicked: anonInput.forceActiveFocus()
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -402,10 +458,11 @@ DankModal {
|
||||
text: wifiAnonymousIdentityInput
|
||||
placeholderText: I18n.tr("Anonymous Identity (optional)")
|
||||
backgroundColor: "transparent"
|
||||
enabled: root.shouldBeVisible
|
||||
onTextEdited: () => {
|
||||
wifiAnonymousIdentityInput = text;
|
||||
}
|
||||
enabled: root.visible
|
||||
keyNavigationTab: domainMatchInput
|
||||
keyNavigationBacktab: passwordInput
|
||||
onTextEdited: wifiAnonymousIdentityInput = text
|
||||
onAccepted: domainMatchInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,9 +477,7 @@ DankModal {
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: () => {
|
||||
domainMatchInput.forceActiveFocus();
|
||||
}
|
||||
onClicked: domainMatchInput.forceActiveFocus()
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -434,10 +489,11 @@ DankModal {
|
||||
text: wifiDomainInput
|
||||
placeholderText: I18n.tr("Domain (optional)")
|
||||
backgroundColor: "transparent"
|
||||
enabled: root.shouldBeVisible
|
||||
onTextEdited: () => {
|
||||
wifiDomainInput = text;
|
||||
}
|
||||
enabled: root.visible
|
||||
keyNavigationTab: usernameInput
|
||||
keyNavigationBacktab: anonInput
|
||||
onTextEdited: wifiDomainInput = text
|
||||
onAccepted: submitCredentialsAndClose()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,6 +503,7 @@ DankModal {
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
visible: fieldsInfo.length === 0
|
||||
|
||||
Rectangle {
|
||||
id: showPasswordCheckbox
|
||||
@@ -472,9 +529,7 @@ DankModal {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: () => {
|
||||
showPasswordCheckbox.checked = !showPasswordCheckbox.checked;
|
||||
}
|
||||
onClicked: showPasswordCheckbox.checked = !showPasswordCheckbox.checked
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +543,7 @@ DankModal {
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
visible: isVpnPrompt
|
||||
visible: isVpnPrompt || fieldsInfo.length > 0
|
||||
|
||||
Rectangle {
|
||||
id: savePasswordCheckbox
|
||||
@@ -514,9 +569,7 @@ DankModal {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: () => {
|
||||
savePasswordCheckbox.checked = !savePasswordCheckbox.checked;
|
||||
}
|
||||
onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +601,6 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
id: cancelText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: I18n.tr("Cancel")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -558,20 +610,10 @@ DankModal {
|
||||
|
||||
MouseArea {
|
||||
id: cancelArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: () => {
|
||||
if (isPromptMode) {
|
||||
NetworkService.cancelCredentials(promptToken);
|
||||
}
|
||||
close();
|
||||
wifiPasswordInput = "";
|
||||
wifiUsernameInput = "";
|
||||
wifiAnonymousIdentityInput = "";
|
||||
wifiDomainInput = "";
|
||||
}
|
||||
onClicked: clearAndClose()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,16 +623,24 @@ DankModal {
|
||||
radius: Theme.cornerRadius
|
||||
color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||
enabled: {
|
||||
if (isVpnPrompt) {
|
||||
return passwordInput.text.length > 0;
|
||||
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 {
|
||||
id: connectText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: I18n.tr("Connect")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -600,41 +650,11 @@ DankModal {
|
||||
|
||||
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 = "";
|
||||
}
|
||||
onClicked: submitCredentialsAndClose()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -649,4 +669,3 @@ DankModal {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Inlined VPN details
|
||||
Rectangle {
|
||||
id: vpnDetail
|
||||
|
||||
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
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
VpnDetailContent {
|
||||
width: parent.width
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
listHeight: 200
|
||||
parentPopout: root
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1839
quickshell/Modules/Settings/NetworkTab.qml
Normal file
1839
quickshell/Modules/Settings/NetworkTab.qml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -176,15 +176,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
function onPrepareForSleep() {
|
||||
if (SettingsData.lockBeforeSuspend) {
|
||||
root.lockRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onPreventIdleForMediaChanged() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
220
quickshell/Services/VPNService.qml
Normal file
220
quickshell/Services/VPNService.qml
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ Item {
|
||||
property list<real> 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;
|
||||
|
||||
476
quickshell/Widgets/VpnDetailContent.qml
Normal file
476
quickshell/Widgets/VpnDetailContent.qml
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
@@ -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": "• 信頼できるソースからのみインストールする"
|
||||
|
||||
@@ -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ł"
|
||||
|
||||
@@ -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?"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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": "• 仅从可信来源安装"
|
||||
|
||||
@@ -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?": "您有未儲存的變更。是否要儲存?"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user